1 /*
2 Ming, an SWF output library
3 Copyright (C) 2002 Opaque Industries - http://www.opaque.net/
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include <stdlib.h>
21 /* not used? #include <string.h> */
22 #include <math.h>
23
24 #include "blocks/placeobject.h"
25 #include "blocks/character.h"
26 #include "blocks/matrix.h"
27 #include "displaylist.h"
28 #include "position.h"
29 #include "blocks/soundstream.h"
30 #include "blocks/outputblock.h"
31 #include "blocks/button.h"
32 #include "blocks/videostream.h"
33 #include "blocks/blocktypes.h"
34 #include "blocks/filter.h"
35 #include "blocks/sprite.h"
36 #include "blocks/scalinggrid.h"
37 #include "libming.h"
38
39 #define ITEM_NEW (1<<0)
40 #define ITEM_REMOVED (1<<1)
41 #define ITEM_TRANSFORMED (1<<2)
42 #define ITEM_CXFORMCHANGED (1<<3)
43 #define ITEM_RATIOCHANGED (1<<4)
44
45 #define ITEM_CHANGED (ITEM_TRANSFORMED|ITEM_CXFORMCHANGED|ITEM_RATIOCHANGED|ITEM_NEW)
46
47 struct SWFDisplayList_s
48 {
49 SWFSoundStream soundStream;
50 SWFDisplayItem head;
51 SWFDisplayItem tail;
52 byte isSprite;
53 int depth;
54 };
55
56
57 void
destroySWFDisplayItem(SWFDisplayItem displayItem)58 destroySWFDisplayItem(SWFDisplayItem displayItem)
59 {
60 if ( displayItem->position )
61 destroySWFPosition(displayItem->position);
62
63 if ( displayItem->matrix )
64 destroySWFMatrix(displayItem->matrix);
65
66 /* character is freed in blocklist */
67
68 free(displayItem);
69 }
70
71
72 void
destroySWFDisplayList(SWFDisplayList displayList)73 destroySWFDisplayList(SWFDisplayList displayList)
74 {
75 SWFDisplayItem item = displayList->head, next;
76
77 while ( item != NULL )
78 {
79 next = item->next;
80 destroySWFDisplayItem(item);
81 item = next;
82 }
83
84 free(displayList);
85 }
86
87
88 SWFDisplayList
newSWFDisplayList()89 newSWFDisplayList()
90 {
91 SWFDisplayList list = (SWFDisplayList)malloc(sizeof(struct SWFDisplayList_s));
92
93 /* If malloc failed, return NULL to signify this */
94 if (NULL == list)
95 return NULL;
96
97 list->isSprite = FALSE;
98 list->head = NULL;
99 list->tail = NULL;
100 list->soundStream = NULL;
101 list->depth = 0;
102
103 return list;
104 }
105
106
107 SWFDisplayList
newSWFSpriteDisplayList()108 newSWFSpriteDisplayList()
109 {
110 SWFDisplayList list = (SWFDisplayList)malloc(sizeof(struct SWFDisplayList_s));
111
112 /* If malloc failed, return NULL to signify this */
113 if (NULL == list)
114 return NULL;
115
116 list->isSprite = TRUE;
117 list->head = NULL;
118 list->tail = NULL;
119 list->soundStream = NULL;
120 list->depth = 0;
121
122 return list;
123 }
124
125 void
SWFDisplayItem_replace(SWFDisplayItem item,SWFCharacter character)126 SWFDisplayItem_replace(SWFDisplayItem item, SWFCharacter character)
127 {
128 item->character = character;
129
130 if ( item->block )
131 destroySWFPlaceObject2Block(item->block);
132 item->block = newSWFPlaceObject2Block(item->depth);
133 item->flags = ITEM_NEW;
134 item->isPlaced = 0;
135 SWFPlaceObject2Block_setMove(item->block);
136 SWFPlaceObject2Block_setCharacter(item->block, character);
137 }
138
139 SWFDisplayItem
SWFDisplayList_add(SWFDisplayList list,SWFBlockList blocklist,SWFCharacter character)140 SWFDisplayList_add(SWFDisplayList list, SWFBlockList blocklist, SWFCharacter character)
141 {
142 SWFDisplayItem item = (SWFDisplayItem) malloc(sizeof(struct SWFDisplayItem_s));
143
144 /* If malloc failed, return NULL to signify this */
145 if (NULL == item)
146 return NULL;
147
148 item->flags = ITEM_NEW;
149 item->next = NULL;
150 item->depth = ++list->depth;
151
152 item->matrix = newSWFMatrix(1, 0, 0, 1, 0, 0);
153
154 /* If newSWFMatrix() failed, return NULL to signify this */
155 if (NULL == item->matrix)
156 {
157 free(item);
158 return NULL;
159 }
160
161 item->position = newSWFPosition(item->matrix);
162
163 /* If newSWFPosition() failed, return NULL to signify this */
164 if (NULL == item->position)
165 {
166 destroySWFMatrix(item->matrix);
167 free(item);
168 return NULL;
169 }
170
171 item->block = newSWFPlaceObject2Block(item->depth);
172
173 /* If newSWFPlaceObject2Block() failed, return NULL to signify this */
174 if (NULL == item->block)
175 {
176 destroySWFPosition(item->position);
177 destroySWFMatrix(item->matrix);
178 free(item);
179 return NULL;
180 }
181
182 item->character = character;
183 item->isPlaced = 0;
184 item->blocklist = blocklist;
185
186 SWFPlaceObject2Block_setCharacter(item->block, character);
187 SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
188
189 if ( list->tail )
190 list->tail->next = item;
191 else
192 list->head = item;
193
194 item->prev = list->tail;
195 list->tail = item;
196 // back pointer for endmask
197 item->list = list;
198 return item;
199 }
200
201
202 void
SWFDisplayItem_remove(SWFDisplayItem item)203 SWFDisplayItem_remove(SWFDisplayItem item)
204 {
205 item->flags |= ITEM_REMOVED;
206 }
207
208 void
SWFDisplayItem_removeFromList(SWFDisplayItem item,SWFBlockList blocklist)209 SWFDisplayItem_removeFromList(SWFDisplayItem item, SWFBlockList blocklist)
210 {
211 SWFDisplayList list;
212
213 if(item == NULL || item->list == NULL || blocklist == NULL)
214 return;
215
216 list = item->list;
217 if(item->next)
218 item->next->prev = item->prev;
219
220 if(item->prev)
221 item->prev->next = item->next;
222
223 if(item == list->head)
224 list->head = item->next;
225 if(item == list->tail)
226 list->tail = item->prev;
227
228 if(item->isPlaced)
229 SWFBlockList_addBlock(blocklist,
230 (SWFBlock)newSWFRemoveObject2Block(item->depth));
231
232 destroySWFDisplayItem(item);
233 }
234
235 static void
checkBlock(SWFDisplayItem item)236 checkBlock(SWFDisplayItem item)
237 {
238 if ( item->block == NULL )
239 item->block = newSWFPlaceObject2Block(item->depth);
240
241 if ( (item->flags & ITEM_NEW) == 0 )
242 SWFPlaceObject2Block_setMove(item->block);
243 }
244
245
246 SWFCharacter
SWFDisplayItem_getCharacter(SWFDisplayItem item)247 SWFDisplayItem_getCharacter(SWFDisplayItem item)
248 {
249 return item->character;
250 }
251
252
253 int
SWFDisplayItem_getDepth(SWFDisplayItem item)254 SWFDisplayItem_getDepth(SWFDisplayItem item)
255 {
256 return item->depth;
257 }
258
259
260 void
SWFDisplayItem_setDepth(SWFDisplayItem item,int depth)261 SWFDisplayItem_setDepth(SWFDisplayItem item, int depth)
262 {
263 item->depth = depth;
264
265 checkBlock(item);
266
267 if ( (item->flags & ITEM_NEW) == 0 )
268 {
269 /* warn.. */
270 return;
271 }
272
273 SWFPlaceObject2Block_setDepth(item->block, depth);
274 }
275
276
277 SWFMatrix
SWFDisplayItem_getMatrix(SWFDisplayItem item)278 SWFDisplayItem_getMatrix(SWFDisplayItem item)
279 {
280 checkBlock(item);
281 return item->matrix;
282 }
283
284
285 void
SWFDisplayItem_move(SWFDisplayItem item,double x,double y)286 SWFDisplayItem_move(SWFDisplayItem item, double x, double y)
287 {
288 checkBlock(item);
289 SWFPosition_move(item->position, x, y);
290 SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
291 }
292
293
294 void
SWFDisplayItem_moveTo(SWFDisplayItem item,double x,double y)295 SWFDisplayItem_moveTo(SWFDisplayItem item, double x, double y)
296 {
297 checkBlock(item);
298 SWFPosition_moveTo(item->position, x, y);
299 SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
300 }
301
302
303 void
SWFDisplayItem_getPosition(SWFDisplayItem item,double * x,double * y)304 SWFDisplayItem_getPosition(SWFDisplayItem item, double *x, double *y)
305 {
306 // returns the current position of this display item into the provided
307 // pointers, respects NULL values
308
309 checkBlock(item);
310 SWFPosition_getXY(item->position, x, y);
311 }
312
313
314 void
SWFDisplayItem_rotate(SWFDisplayItem item,double degrees)315 SWFDisplayItem_rotate(SWFDisplayItem item, double degrees)
316 {
317 checkBlock(item);
318 SWFPosition_rotate(item->position, degrees);
319 SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
320 }
321
322
323 void
SWFDisplayItem_rotateTo(SWFDisplayItem item,double degrees)324 SWFDisplayItem_rotateTo(SWFDisplayItem item, double degrees)
325 {
326 checkBlock(item);
327 SWFPosition_rotateTo(item->position, degrees);
328 SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
329 }
330
331
332 void
SWFDisplayItem_getRotation(SWFDisplayItem item,double * degrees)333 SWFDisplayItem_getRotation(SWFDisplayItem item, double *degrees)
334 {
335 // returns the current rotation of this display item into the given
336 // pointer, respects NULL value
337
338 checkBlock(item);
339
340 if ( degrees != NULL )
341 *degrees = SWFPosition_getRotation(item->position);
342 }
343
344
345 void
SWFDisplayItem_scale(SWFDisplayItem item,double xScale,double yScale)346 SWFDisplayItem_scale(SWFDisplayItem item, double xScale, double yScale)
347 {
348 checkBlock(item);
349 SWFPosition_scaleXY(item->position, xScale, yScale);
350 SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
351 }
352
353
354 void
SWFDisplayItem_scaleTo(SWFDisplayItem item,double xScale,double yScale)355 SWFDisplayItem_scaleTo(SWFDisplayItem item, double xScale, double yScale)
356 {
357 checkBlock(item);
358 SWFPosition_scaleXYTo(item->position, xScale, yScale);
359 SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
360 }
361
362
363 void
SWFDisplayItem_getScale(SWFDisplayItem item,double * xScale,double * yScale)364 SWFDisplayItem_getScale(SWFDisplayItem item, double *xScale, double *yScale)
365 {
366 // returns the current x- and y-scale of this display item into the given
367 // pointers, respects NULL values
368
369 checkBlock(item);
370 SWFPosition_getXYScale(item->position, xScale, yScale);
371 }
372
373
374 void
SWFDisplayItem_skewX(SWFDisplayItem item,double x)375 SWFDisplayItem_skewX(SWFDisplayItem item, double x)
376 {
377 checkBlock(item);
378 SWFPosition_skewX(item->position, x);
379 SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
380 }
381
382
383 void
SWFDisplayItem_skewXTo(SWFDisplayItem item,double x)384 SWFDisplayItem_skewXTo(SWFDisplayItem item, double x)
385 {
386 checkBlock(item);
387 SWFPosition_skewXTo(item->position, x);
388 SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
389 }
390
391
392 void
SWFDisplayItem_skewY(SWFDisplayItem item,double y)393 SWFDisplayItem_skewY(SWFDisplayItem item, double y)
394 {
395 checkBlock(item);
396 SWFPosition_skewY(item->position, y);
397 SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
398 }
399
400
401 void
SWFDisplayItem_skewYTo(SWFDisplayItem item,double y)402 SWFDisplayItem_skewYTo(SWFDisplayItem item, double y)
403 {
404 checkBlock(item);
405 SWFPosition_skewYTo(item->position, y);
406 SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
407 }
408
409
410 void
SWFDisplayItem_getSkew(SWFDisplayItem item,double * xSkew,double * ySkew)411 SWFDisplayItem_getSkew(SWFDisplayItem item, double *xSkew, double *ySkew)
412 {
413 // returns the current x- and y-skew of this display item into the given
414 // pointers, respects NULL values
415
416 checkBlock(item);
417 SWFPosition_getXYSkew(item->position, xSkew, ySkew);
418 }
419
420
421 void
SWFDisplayItem_setMatrix(SWFDisplayItem item,double a,double b,double c,double d,double x,double y)422 SWFDisplayItem_setMatrix(SWFDisplayItem item,
423 double a, double b, double c, double d, double x, double y)
424 {
425 checkBlock(item);
426 SWFPosition_setMatrix(item->position, a, b, c, d, x, y);
427 SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
428 }
429
430 /*
431 * This function assigns a name to a display item.
432 * The assigend name can be used in AS as a reference to this item
433 */
434 void
SWFDisplayItem_setName(SWFDisplayItem item,const char * name)435 SWFDisplayItem_setName(SWFDisplayItem item, const char *name)
436 {
437 checkBlock(item);
438
439 if ( (item->flags & ITEM_NEW) == 0 )
440 {
441 /* warn.. */
442 return;
443 }
444 /* item->block is never null when ITEM_NEW set */
445 SWFPlaceObject2Block_setName(item->block, name);
446 }
447
448 /*
449 * This function sets masklevel for the current display item
450 * This item masks other display items above it. If this items
451 * depth is 1 and its masklevel is set to 4, all items with depth
452 * >= 5 are masked.
453 */
454 void
SWFDisplayItem_setMaskLevel(SWFDisplayItem item,int masklevel)455 SWFDisplayItem_setMaskLevel(SWFDisplayItem item, int masklevel)
456 {
457 checkBlock(item);
458
459 if ( (item->flags & ITEM_NEW) == 0 )
460 {
461 /* warn.. */
462 return;
463 }
464
465 /* item->block is never null when ITEM_NEW set */
466 SWFPlaceObject2Block_setMaskLevel(item->block, masklevel);
467 }
468
469
470 void
SWFDisplayItem_endMask(SWFDisplayItem item)471 SWFDisplayItem_endMask(SWFDisplayItem item)
472 {
473 checkBlock(item);
474 SWFPlaceObject2Block_setMaskLevel(item->block, item->list->depth);
475 }
476
477
478 void
SWFDisplayItem_setRatio(SWFDisplayItem item,float ratio)479 SWFDisplayItem_setRatio(SWFDisplayItem item, float ratio)
480 {
481 int res;
482 checkBlock(item);
483 if(ratio < 0)
484 {
485 SWF_warn("SWFDisplayItem_setRatio: ratio must be inside [0...1]\n");
486 ratio = 0;
487 }
488 else if (ratio > 1.0)
489 {
490 SWF_warn("SWFDisplayItem_setRatio: ratio must be inside [0...1]\n");
491 ratio = 1.0;
492 }
493 res = (int)floor(ratio * 65535);
494 SWFPlaceObject2Block_setRatio(item->block, res);
495 }
496
497
498 void
SWFDisplayItem_setCXform(SWFDisplayItem item,SWFCXform cXform)499 SWFDisplayItem_setCXform(SWFDisplayItem item, SWFCXform cXform)
500 {
501 checkBlock(item);
502 SWFPlaceObject2Block_setCXform(item->block, cXform);
503 }
504
505
506 void
SWFDisplayItem_setColorAdd(SWFDisplayItem item,int r,int g,int b,int a)507 SWFDisplayItem_setColorAdd(SWFDisplayItem item, int r, int g, int b, int a)
508 {
509 checkBlock(item);
510 SWFPlaceObject2Block_setColorAdd(item->block, r, g, b, a);
511 }
512
513
514 void
SWFDisplayItem_setColorMult(SWFDisplayItem item,float r,float g,float b,float a)515 SWFDisplayItem_setColorMult(SWFDisplayItem item,
516 float r, float g, float b, float a)
517 {
518 checkBlock(item);
519 SWFPlaceObject2Block_setColorMult(item->block, r, g, b, a);
520 }
521
522
523 void
SWFDisplayItem_addAction(SWFDisplayItem item,SWFAction action,int flags)524 SWFDisplayItem_addAction(SWFDisplayItem item, SWFAction action, int flags)
525 {
526 checkBlock(item);
527
528 if ( (item->flags & ITEM_NEW) == 0 )
529 {
530 /* warn.. */
531 return;
532 }
533
534 /* item->block is never null when ITEM_NEW set */
535 SWFPlaceObject2Block_addAction(item->block, action, flags);
536 }
537
538 /*
539 * adds a surface filter
540 * Adds a bitmap filter to the display object.
541 * Also sets cache-as-bitmap flag.
542 * See SWFFilter for possible filter objects. Filter can
543 * only be applied to buttons, sprite/movieclips and text
544 */
SWFDisplayItem_addFilter(SWFDisplayItem item,SWFFilter filter)545 void SWFDisplayItem_addFilter(SWFDisplayItem item,
546 SWFFilter filter /* filter */)
547 {
548 SWFBlock block;
549 block = (SWFBlock)item->character;
550 if(!SWFFilter_testBlockType(block->type))
551 {
552 SWF_warn("Filter can only be applied to buttons, sprite/movieclips and text\n");
553 return;
554 }
555 checkBlock(item);
556 SWFPlaceObject2Block_setCacheFlag(item->block, 1);
557 SWFPlaceObject2Block_addFilter(item->block, filter);
558
559 }
560
561
562 /*
563 * set blend mdoe
564 * Sets an alternative blend mode instead of default alpha blend.
565 * possible modes are:
566 * SWFBLEND_MODE_NORMAL
567 * SWFBLEND_MODE_LAYER
568 * SWFBLEND_MODE_MULT
569 * SWFBLEND_MODE_SCREEN
570 * SWFBLEND_MODE_DARKEN
571 * SWFBLEND_MODE_ADD
572 * SWFBLEND_MODE_SUB
573 * SWFBLEND_MODE_DIFF
574 * SWFBLEND_MODE_DIFF
575 * SWFBLEND_MODE_INV
576 * SWFBLDEN_MODE_ALPHA
577 * SWFBLEND_MDOE_ERASE
578 * SWFBLEND_MDOE_OVERLAY
579 * SWFBLEND_MODE_HARDLIGHT
580 */
SWFDisplayItem_setBlendMode(SWFDisplayItem item,int mode)581 void SWFDisplayItem_setBlendMode(SWFDisplayItem item,
582 int mode /* blend mode */)
583 {
584 checkBlock(item);
585 SWFPlaceObject2Block_setBlendMode(item->block, mode);
586 }
587
588
589 /*
590 * set cashing flag
591 * If this flag ist set, the character can be cached as a bitmap. This might
592 * improve rednering speed, if the object dos no change often.
593 * This feature is for SWF version >= 8 only.
594 */
SWFDisplayItem_cacheAsBitmap(SWFDisplayItem item,int flag)595 void SWFDisplayItem_cacheAsBitmap(SWFDisplayItem item,
596 int flag /* flag 0 or 1 */)
597 {
598 checkBlock(item);
599 SWFPlaceObject2Block_setCacheFlag(item->block, flag);
600 }
601
602 void
SWFDisplayList_setSoundStream(SWFDisplayList list,SWFSoundStream stream)603 SWFDisplayList_setSoundStream(SWFDisplayList list, SWFSoundStream stream)
604 {
605 list->soundStream = stream;
606 }
607
608
609 void
SWFDisplayList_rewindSoundStream(SWFDisplayList list)610 SWFDisplayList_rewindSoundStream(SWFDisplayList list)
611 {
612 // XXX - this is a hack, should be replaced..
613
614 if ( list->soundStream )
615 SWFSoundStream_rewind(list->soundStream);
616 }
617
618 void
SWFDisplayList_writeBlocks(SWFDisplayList list,SWFBlockList blocklist)619 SWFDisplayList_writeBlocks(SWFDisplayList list, SWFBlockList blocklist)
620 {
621 SWFDisplayItem item = list->head, next;
622 SWFCharacter character;
623
624 if ( list->soundStream )
625 {
626 SWFBlock stream = SWFSoundStream_getStreamBlock(list->soundStream);
627
628 if ( stream )
629 SWFBlockList_addBlock(blocklist, stream);
630 }
631
632 while ( item != NULL )
633 {
634 character = item->character;
635
636 // if ( character != NULL )
637 // SWFBlockList_resolveCharacterDependencies(blocklist, character);
638
639 if ( item->flags & ITEM_REMOVED )
640 {
641 next = item->next;
642 SWFDisplayItem_removeFromList(item, blocklist);
643 item = next;
644 continue;
645 }
646
647 if ( character != NULL &&
648 !SWFBlock_isDefined((SWFBlock)character) &&
649 !list->isSprite )
650 {
651 SWFBlockList_addBlock(blocklist, (SWFBlock)character);
652 }
653
654 if ( item->block != NULL )
655 {
656 if(!item->isPlaced && character->onPlace)
657 character->onPlace(item, blocklist);
658 SWFBlockList_addBlock(blocklist, (SWFBlock)item->block);
659 item->isPlaced = 1;
660 }
661
662 if (character && character->onFrame)
663 character->onFrame(item, blocklist);
664
665 item->flags = 0;
666 item->block = NULL;
667
668 item = item->next;
669 }
670 }
671
672 /*
673 * This function writes the item object immediately to the blocklist.
674 * Usually MING waits with writing a display item until a frame is closed
675 * through a nextFrame() call, because a display items state could be altered
676 * for the current frame. By using SWFDisplayItem_flush() MING does not wait
677 * and writes the frame immediately. Therefore a user can influence the
678 * swf tag oder. Changing a display items state after calling flush() takes
679 * effect in the next frame.
680 */
681 void
SWFDisplayItem_flush(SWFDisplayItem item)682 SWFDisplayItem_flush(SWFDisplayItem item /* item to write */)
683 {
684 SWFCharacter character;
685 if(item == NULL)
686 return;
687
688 character = item->character;
689 if (item->flags & ITEM_REMOVED)
690 {
691 SWFDisplayItem_removeFromList(item, item->blocklist);
692 return;
693 }
694
695 if (character != NULL && !SWFBlock_isDefined((SWFBlock)character))
696 {
697 SWFBlockList_addBlock(item->blocklist, (SWFBlock)character);
698 }
699
700 if ( item->block != NULL )
701 {
702 if(!item->isPlaced && character->onPlace)
703 character->onPlace(item, item->blocklist);
704 SWFBlockList_addBlock(item->blocklist, (SWFBlock)item->block);
705 item->isPlaced = 1;
706 }
707
708 item->flags = 0;
709 item->block = NULL;
710 }
711
712 /*
713 * Local variables:
714 * tab-width: 2
715 * c-basic-offset: 2
716 * End:
717 */
718