1 /* libsswf_blendmode.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2002-2008 */
2
3 /*
4
5 Copyright (c) 2002-2008 Made to Order Software Corp.
6
7 Permission is hereby granted, free of charge, to any
8 person obtaining a copy of this software and
9 associated documentation files (the "Software"), to
10 deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify,
12 merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom
14 the Software is furnished to do so, subject to the
15 following conditions:
16
17 The above copyright notice and this permission notice
18 shall be included in all copies or substantial
19 portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
22 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
23 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
25 EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
28 ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 SOFTWARE.
31
32 */
33
34 /** \file
35 *
36 * \brief The implementation of the sswf::BlendMode class
37 *
38 * This file declares the body of the functions which are not
39 * inline. It is part of the SSWF library.
40 */
41
42 #include "sswf/libsswf.h"
43
44 using namespace sswf;
45
46
47
48 /////////////////////////////////////////// State
49
50
51 /** \class sswf::BlendMode
52 *
53 * \brief The mode used to render the object on the screen
54 *
55 * This class was introduced in version 1.8.0.
56 *
57 * This class is used to declare a blending mode which can be
58 * shared by different classes.
59 *
60 * \sa sswf::State
61 * \sa sswf::TagPlace
62 * \sa <a href="../SWFalexref.html#tag_placeobject3">SWF Alexis' Reference—Place Object 3</a>
63 */
64
65
66 /** \enum sswf::BlendMode::blend_mode_t
67 *
68 * \brief List all the available blend modes
69 *
70 * The following lists the blend modes available when placing an object
71 * on your screen.
72 *
73 * In the following, I included formulas which use the following variables:
74 *
75 * \li R - the resulting color
76 * \li C - the source color (i.e. the object in the TagPlace or State)
77 * \li B - the background (i.e. what has been drawn before this object)
78 *
79 * In some cases, a specific component is affected. This is marked by
80 * a subscript with the component letter (one of RGBA as in: R<sub>a</sub>.)
81 */
82
83
84 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_UNDEFINED
85 *
86 * \brief According to Macromedia this is the same as sswf::BlendMode::BLEND_MODE_NORMAL
87 *
88 * This value should probably not be used, yet according to the
89 * Macromedia documentation, it is equivalent to sswf::BlendMode::BLEND_MODE_NORMAL
90 *
91 * This is a <i>do nothing</i> blending mode.
92 *
93 * \code
94 * R = C
95 * \endcode
96 */
97
98
99 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_NORMAL
100 *
101 * \brief A <i>do nothing</i> blending mode
102 *
103 * This blending mode has no effect on the object being placed.
104 *
105 * \note
106 * This may be a place holder in case you want to apply some blending mode
107 * with an ActionScript. Without it you may not be able to apply any blending
108 * mode from a script (TBD).
109 *
110 * \code
111 * R = C
112 * \endcode
113 */
114
115
116 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_LAYER
117 *
118 * \brief Use multiple objects
119 *
120 * This blending mode uses multiple objects to render the final output. At
121 * this time, it isn't clear to me what this does...
122 */
123
124
125 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_MULTIPLY
126 *
127 * \brief Multiply the background and the object colors (light effect)
128 *
129 * This blending mode can be used to multiply the background colors with
130 * the object being placed. When the object being placed is a grey scale,
131 * this is a way to apply brightness to the background. Thus you can
132 * generate the effect of a light (or a reflection of a light) on the
133 * screen.
134 *
135 \htmlonly
136 <div class="fragment"><pre class="fragment">
137 R = B × C / 255
138 </pre></div>
139 \endhtmlonly
140 */
141
142
143
144
145 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_SCREEN
146 *
147 * \brief Multiply the inverse of the background and the object colors
148 *
149 * There is probably no good reason to use the inverse color of the
150 * object since the object could be rendered properly in the first
151 * place (i.e. if you need 255, use white and if you need 0 use black).
152 * Yet, this filter multiplies the inverse of the background and the
153 * object colors together.
154 *
155 \htmlonly
156 <div class="fragment"><pre class="fragment">
157 R = (255 - B) × (255 - C) / 255
158 </pre></div>
159 \endhtmlonly
160 */
161
162
163
164 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_LIGHTEN
165 *
166 * \brief Use the largest of the two colors
167 *
168 * Select which of the background or the object being placed has the
169 * largest component.
170 *
171 * Use black in your object to not affect the screen.
172 *
173 * \code
174 * R = max(B, C)
175 * \endcode
176 */
177
178
179
180 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_DARKEN
181 *
182 * \brief Use the largest of the two colors
183 *
184 * Select which of the background or the object being placed has the
185 * smallest component.
186 *
187 * Use white in your object to not affect the screen.
188 *
189 * \code
190 * R = min(B, C)
191 * \endcode
192 */
193
194
195
196 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_ADD
197 *
198 * \brief Add the object components to the background
199 *
200 * This filter can be used for a strong brightness effect. Watchout, do not
201 * create too bright an object for this blend mode. It would otherwise make
202 * your screen look bad.
203 *
204 * \code
205 * R = max(B + C, 255)
206 * \endcode
207 */
208
209
210
211 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_SUBTRACT
212 *
213 * \brief Subject the object components from the background
214 *
215 * This filter can be used for a strong darkning effect. Watchout, do not
216 * create too bright an object for this blend mode. It would otherwise make
217 * your screen look bad.
218 *
219 * \code
220 * R = min(B - C, 0)
221 * \endcode
222 */
223
224
225
226 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_DIFFERENCE
227 *
228 * \brief Take the absolute value of the object color minus the background color
229 *
230 * At this time, I'm not too sure what this is for. The colors will loop around
231 * with this object and in general this make the image look <i>weird</i>. May
232 * be a good idea to create some sort of negative effect.
233 *
234 * \code
235 * R = | B - C |
236 * \endcode
237 */
238
239
240
241 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_INVERT
242 *
243 * \brief Inverse the background colors
244 *
245 * This filter does not use the source image for anything more than know where
246 * to apply the filter. Otherwise it inverts the color creating a negative
247 * (the same as when you take pictures with your camera, the resulting film
248 * is a negative -- the colors are invered.)
249 *
250 * \code
251 * R = 255 - B
252 * \endcode
253 */
254
255
256
257 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_ALPHA
258 *
259 * \brief Copy the object alpha in the background
260 *
261 * This filter copies the alpha channel as is from the object to the background.
262 * Used in a Sprite, I suppose this can be used to switch between different
263 * alpha channels for the same object.
264 *
265 \htmlonly
266 <div class="fragment"><pre class="fragment">
267 R<sub>a</sub> = C<sub>a</sub>
268 </pre></div>
269 \endhtmlonly
270 */
271
272
273
274 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_ERASE
275 *
276 * \brief Copy the inverse of the object alpha in the background
277 *
278 * This filter copies the inverts of the alpha channel from the object to
279 * the background. This as the effect of making the object itself
280 * disappear... and what's around appear, I would think.
281 *
282 \htmlonly
283 <div class="fragment"><pre class="fragment">
284 R<sub>a</sub> = 255 - C<sub>a</sub>
285 </pre></div>
286 \endhtmlonly
287 */
288
289
290
291 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_OVERLAY
292 *
293 * \brief Applies a MULTIPLY or SCREEN effect depending on the current background colors
294 *
295 * This filter copies the alpha channel as is from the object to the background.
296 *
297 \htmlonly
298 <div class="fragment"><pre class="fragment">
299 R = (B < 128 ? B × C : (255 - B) × (255 - C)) / 255
300 </pre></div>
301 \endhtmlonly
302 */
303
304
305
306 /** \var sswf::BlendMode::blend_mode_t sswf::BlendMode::BLEND_MODE_HARDLIGHT
307 *
308 * \brief Applies a MULTIPLY or SCREEN effect depending on the current background colors
309 *
310 * This filter copies the alpha channel as is from the object to the background.
311 *
312 \htmlonly
313 <div class="fragment"><pre class="fragment">
314 R = (C < 128 ? B × C : (255 - B) × (255 - C)) / 255
315 </pre></div>
316 \endhtmlonly
317 */
318
319
320
321 /** \brief Initialize the blend mode to \e undefined
322 *
323 * The constructor initializes the blend mode to the default of:
324 * BLEND_MODE_UNDEFINED.
325 *
326 * \sa sswf::BlendMode::HasBlendMode(void) const
327 */
BlendMode(void)328 BlendMode::BlendMode(void)
329 {
330 f_blend_mode = BLEND_MODE_UNDEFINED;
331 }
332
333
334 /** \brief Test whether a blending filter was defined
335 *
336 * This function determines whether a filter was defined in this BlendMode
337 * object.
338 *
339 * This is the same as testing wheter the BlendMode::HasBlendMode(void) const
340 * function returns BLEND_MODE_UNDEFINED.
341 *
342 * \return \e true when the blend mode is not BLEND_MODE_UNDEFINED; false otherwise
343 *
344 * \sa sswf::BlendMode::SetBlendMode(blend_mode_t blend_mode)
345 * \sa sswf::BlendMode::SetBlendModeByName(const char *blend_mode_name)
346 */
HasBlendMode(void) const347 bool BlendMode::HasBlendMode(void) const
348 {
349 return f_blend_mode != BLEND_MODE_UNDEFINED;
350 }
351
352
353 /** \brief Get the current blending mode
354 *
355 * This function returns the current blending mode as set by SetBlendMode()
356 * or SetBlendModeByName().
357 *
358 * \return The current blend mode
359 *
360 * \sa sswf::BlendMode::SetBlendMode(blend_mode_t blend_mode)
361 * \sa sswf::BlendMode::SetBlendModeByName(const char *blend_mode_name)
362 */
GetBlendMode(void) const363 BlendMode::blend_mode_t BlendMode::GetBlendMode(void) const
364 {
365 return f_blend_mode;
366 }
367
368
369 /** \brief Defines a filter by value
370 *
371 * This function defines the filter to use with a TagPlace or State object.
372 *
373 * \note
374 * Trying to set a mode which does not exist forces the mode to
375 * BLEND_MODE_UNDEFINED.
376 *
377 * \param blend_mode The new blend mode (BLEND_MODE_...)
378 *
379 * \sa sswf::BlendMode::SetBlendModeName(const char *blend_mode_name)
380 */
SetBlendMode(blend_mode_t blend_mode)381 void BlendMode::SetBlendMode(blend_mode_t blend_mode)
382 {
383 switch(blend_mode) {
384 default: // case BLEND_MODE_UNDEFINED:
385 f_blend_mode = BLEND_MODE_UNDEFINED;
386 break;
387
388 case BLEND_MODE_NORMAL:
389 case BLEND_MODE_LAYER:
390 case BLEND_MODE_MULTIPLY:
391 case BLEND_MODE_SCREEN:
392 case BLEND_MODE_LIGHTEN:
393 case BLEND_MODE_DARKEN:
394 case BLEND_MODE_DIFFERENCE:
395 case BLEND_MODE_ADD:
396 case BLEND_MODE_SUBTRACT:
397 case BLEND_MODE_INVERT:
398 case BLEND_MODE_ALPHA:
399 case BLEND_MODE_ERASE:
400 case BLEND_MODE_OVERLAY:
401 case BLEND_MODE_HARDLIGHT:
402 f_blend_mode = blend_mode;
403 break;
404
405 }
406
407 return;
408 }
409
410
411 /** \brief Defines the filter by name
412 *
413 * This function is similar to the sswf::BlendMode::SetBlendMode(blend_mode_t blend_mode)
414 * except that it takes a name instead of a number to define the blending mode
415 * to use.
416 *
417 * The supported names are the same as those found in the
418 * sswf::BlendMode::blend_mode_t enumeration without the "BLEND_MODE_"
419 * part and excluding UNDEFINED (you can reset the blend mode to Undefined
420 * by calling sswf::BlendMode::SetBlendMode(sswf::BlendMode::BLEND_MODE_UNDEFINED) instead.)
421 *
422 * \param blend_mode_name The ASCII name of the blend mode to use
423 *
424 * \return The new blend mode value or BLEND_MODE_UNDEFINED when the input
425 * name was not a valid blend mode
426 *
427 * \sa sswf::TagBase::SetBlendMode(blend_mode_t blend_mode)
428 */
SetBlendModeByName(const char * blend_mode_name)429 bool BlendMode::SetBlendModeByName(const char *blend_mode_name)
430 {
431 f_blend_mode = BLEND_MODE_UNDEFINED;
432
433 if(blend_mode_name != 0) switch(blend_mode_name[0]) {
434 case 'A':
435 if(strcasecmp(blend_mode_name, "ADD") == 0) {
436 f_blend_mode = BLEND_MODE_ADD;
437 }
438 else if(strcasecmp(blend_mode_name, "ALPHA") == 0) {
439 f_blend_mode = BLEND_MODE_ALPHA;
440 }
441 break;
442
443 case 'D':
444 if(strcasecmp(blend_mode_name, "DARKEN") == 0) {
445 f_blend_mode = BLEND_MODE_DARKEN;
446 }
447 else if(strcasecmp(blend_mode_name, "DIFFERENCE") == 0) {
448 f_blend_mode = BLEND_MODE_DIFFERENCE;
449 }
450 break;
451
452 case 'E':
453 if(strcasecmp(blend_mode_name, "ERASE") == 0) {
454 f_blend_mode = BLEND_MODE_ERASE;
455 }
456 break;
457
458 case 'H':
459 if(strcasecmp(blend_mode_name, "HARDLIGHT") == 0) {
460 f_blend_mode = BLEND_MODE_HARDLIGHT;
461 }
462 break;
463
464 case 'I':
465 if(strcasecmp(blend_mode_name, "INVERT") == 0) {
466 f_blend_mode = BLEND_MODE_INVERT;
467 }
468 break;
469
470 case 'L':
471 if(strcasecmp(blend_mode_name, "LAYER") == 0) {
472 f_blend_mode = BLEND_MODE_LAYER;
473 }
474 else if(strcasecmp(blend_mode_name, "LIGHTEN") == 0) {
475 f_blend_mode = BLEND_MODE_LIGHTEN;
476 }
477 break;
478
479 case 'M':
480 if(strcasecmp(blend_mode_name, "MULTIPLY") == 0) {
481 f_blend_mode = BLEND_MODE_MULTIPLY;
482 }
483 break;
484
485 case 'N':
486 if(strcasecmp(blend_mode_name, "NORMAL") == 0) {
487 f_blend_mode = BLEND_MODE_NORMAL;
488 }
489 break;
490
491 case 'O':
492 if(strcasecmp(blend_mode_name, "OVERLAY") == 0) {
493 f_blend_mode = BLEND_MODE_OVERLAY;
494 }
495 break;
496
497 case 'S':
498 if(strcasecmp(blend_mode_name, "SCREEN") == 0) {
499 f_blend_mode = BLEND_MODE_SCREEN;
500 }
501 else if(strcasecmp(blend_mode_name, "SUBTRACT") == 0) {
502 f_blend_mode = BLEND_MODE_SUBTRACT;
503 }
504 break;
505
506 }
507
508 return f_blend_mode != BLEND_MODE_UNDEFINED;
509 }
510
511
512
513 /** \brief Save the filter in the specified Data buffer
514 *
515 * This function saves the specified blend mode in the specified Data buffer.
516 *
517 * \param data The Data buffer where the blend mode is to be saved
518 */
Save(Data & data)519 void BlendMode::Save(Data& data)
520 {
521 data.PutByte(f_blend_mode);
522 }
523
524
525 /* The following options fold the documentation; use 'zi' to turn on and off
526 *
527 * vim: foldexpr=getline(v\:lnum)!~'^/\\*\\*'&&getline(v\:lnum)!~'^\ \\*'?0\:1 foldcolumn=2 foldmethod=expr
528 */
529