fix crashes reported by Debian Cylab Mayhem Team
[swftools.git] / src / swfc.c
blobc0b756af64f2e9320e4605110a0fa9823a817359
1 /* swfc.c
2 Compiles swf code (.sc) files into .swf files.
4 Part of the swftools package.
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <memory.h>
27 #include <errno.h>
28 #include <math.h>
29 #include "../config.h"
30 #include "../lib/rfxswf.h"
31 #include "../lib/drawer.h"
32 #include "../lib/log.h"
33 #include "../lib/args.h"
34 #include "../lib/q.h"
35 #include "../lib/mp3.h"
36 #include "../lib/wav.h"
37 #include "parser.h"
38 #include "../lib/png.h"
39 #include "swfc-feedback.h"
40 #include "swfc-interpolation.h"
41 #include "swfc-history.h"
43 //#define DEBUG
44 static char * outputname = "output.swf";
45 static int verbose = 2;
46 static int optimize = 0;
47 static int override_outputname = 0;
48 static int do_cgi = 0;
49 static int change_sets_all = 0;
50 static int do_exports = 0;
51 static char * mainclass = "";
53 static struct options_t options[] = {
54 {"h", "help"},
55 {"V", "version"},
56 {"C", "cgi"},
57 {"v", "verbose"},
58 {"o", "output"},
59 {0,0}
62 int args_callback_option(char*name,char*val)
64 if(!strcmp(name, "V")) {
65 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
66 exit(0);
68 else if(!strcmp(name, "o")) {
69 outputname = val;
70 override_outputname = 1;
71 return 1;
73 else if(!strcmp(name, "O")) {
74 optimize = 1;
75 return 0;
77 else if(!strcmp(name, "C")) {
78 do_cgi = 1;
79 return 0;
81 else if(!strcmp(name, "v")) {
82 verbose ++;
83 return 0;
85 else {
86 printf("Unknown option: -%s\n", name);
87 exit(1);
89 return 0;
91 int args_callback_longoption(char*name,char*val)
93 return args_long2shortoption(options, name, val);
95 void args_callback_usage(char *name)
97 printf("\n");
98 printf("Usage: %s [-o file.swf] file.sc\n", name);
99 printf("\n");
100 printf("-h , --help Print short help message and exit\n");
101 printf("-V , --version Print version info and exit\n");
102 printf("-C , --cgi Output to stdout (for use in CGI environments)\n");
103 printf("-v , --verbose Increase verbosity. \n");
104 printf("-o , --output <filename> Set output file to <filename>.\n");
105 printf("\n");
107 int args_callback_command(char*name,char*val)
109 if(filename) {
110 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
111 filename, name);
113 filename = name;
114 return 0;
117 static struct token_t* file;
119 static int pos;
120 static char*text;
121 static int textlen;
122 static int type;
124 static void readToken()
126 type = file[pos].type;
127 if(type == END) {
128 syntaxerror("unexpected end of file");
130 text = file[pos].text;
131 textlen = strlen(text);
132 line = file[pos].line;
133 column = file[pos].column;
134 pos++;
135 //printf("---> %d(%s) %s\n", type, type_names[type], text);
138 static void pushBack()
140 int p;
141 if(!pos) syntaxerror("internal error 3");
142 pos--;
143 p = pos;
144 if(p) p--;
145 text = file[p].text;
146 textlen = strlen(text);
147 type = file[p].type;
148 line = file[p].line;
149 column = file[p].column;
152 static int noMoreTokens()
154 if(file[pos].type == END)
155 return 1;
156 return 0;
159 enum
161 PT_PUT = 0,
162 PT_CHANGE = 1,
163 PT_SCHANGE = 2,
164 PT_MOVE = 3,
165 PT_SMOVE = 4,
166 PT_SWEEP = 5,
167 PT_JUMP = 6,
168 PT_STARTCLIP = 7,
169 PT_BUTTON = 8
172 // ------------------------------ swf routines ----------------------------
173 struct _character;
174 static struct level
176 int type; //0=swf, 1=sprite, 2=clip, 3=button
178 /* for swf (0): */
179 SWF*swf;
180 char*filename;
181 char as3;
183 /* for sprites (1): */
184 TAG*tag;
185 U16 id;
186 char*name;
187 char*as3name;
188 U16 olddepth;
189 int oldframe;
190 dict_t oldinstances;
191 SRECT oldrect;
192 TAG* cut;
194 SRECT scalegrid;
196 } stack[256];
197 static int stackpos = 0;
199 static dict_t characters;
200 static dict_t images;
201 static dict_t textures;
202 static dict_t outlines;
203 static dict_t gradients;
204 static dict_t filters;
205 static dict_t interpolations;
206 static char idmap[65536];
207 static TAG*tag = 0; //current tag
209 static int id; //current character id
210 static int currentframe; //current frame in current level
211 static SRECT currentrect; //current bounding box in current level
212 static U16 currentdepth;
213 static dict_t instances;
214 static dict_t fonts;
215 static dict_t sounds;
216 static dict_t fontUsage;
218 typedef struct _parameters {
219 int x,y;
220 float scalex, scaley;
221 CXFORM cxform;
222 float rotate;
223 float shear;
224 SPOINT pivot;
225 SPOINT pin;
226 U8 blendmode; //not interpolated
227 FILTERLIST* filters;
228 U16 set; // bits indicating wether a parameter was set in the c_placement function
229 U16 flags; // bits to toggle anything you may care to implement as a toggle
230 int noinstancename;
231 } parameters_t;
233 typedef struct _character {
234 TAG*definingTag;
235 U16 id;
236 SRECT size;
237 } character_t;
239 typedef struct _instance {
240 character_t*character;
241 U16 depth;
242 parameters_t parameters;
243 history_t* history;
244 } instance_t;
246 typedef struct _outline {
247 SHAPE* shape;
248 SRECT bbox;
249 } outline_t;
251 typedef struct _gradient {
252 GRADIENT gradient;
253 char radial;
254 int rotate;
255 } gradient_t;
257 typedef struct _filter {
258 FILTER filter;
259 } filter_t;
261 typedef struct _texture {
262 FILLSTYLE fs;
263 } texture_t;
265 char* interpolationFunctions[] = {"linear", \
266 "quadIn", "quadOut", "quadInOut", \
267 "cubicIn", "cubicOut", "cubicInOut", \
268 "quartIn", "quartOut", "quartInOut", \
269 "quintIn", "quintOut", "quintInOut", \
270 "circleIn", "circleOut", "circleInOut", \
271 "exponentialIn", "exponentialOut", "exponentialInOut", \
272 "sineIn", "sineOut", "sineInOut", \
273 "elasticIn", "elasticOut", "elasticInOut", \
274 "backIn", "backOut", "backInOut", \
275 "bounceIn", "bounceOut", "bounceInOut", \
276 "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
278 static void character_init(character_t*c)
280 memset(c, 0, sizeof(character_t));
283 static character_t* character_new()
285 character_t*c;
286 c = (character_t*)malloc(sizeof(character_t));
287 character_init(c);
288 return c;
291 static void instance_init(instance_t*i)
293 memset(i, 0, sizeof(instance_t));
294 i->history = history_new();
297 static void instance_free(instance_t* i)
299 history_free(i->history);
300 free(i);
303 static instance_t* instance_new()
305 instance_t*c;
306 c = (instance_t*)malloc(sizeof(instance_t));
307 instance_init(c);
308 return c;
311 static void free_instance(void* i)
313 instance_free((instance_t*)i);
316 static void free_font(void* f)
318 swf_FontFree((SWFFONT*)f);
321 static void gradient_free(GRADIENT* grad)
323 free(grad->ratios);
324 free(grad->rgba);
325 free(grad);
328 static void free_gradient(void* grad)
330 gradient_free((GRADIENT*) grad);
333 static void outline_free(outline_t* o)
335 free(o->shape->data);
336 free(o->shape);
337 free(o);
340 static void free_outline(void* o)
342 outline_free((outline_t*)o);
345 static void freeDictionaries()
347 dict_free_all(&instances, 1, free_instance);
348 dict_free_all(&characters, 1, free);
349 dict_free_all(&images, 1, free);
350 dict_free_all(&textures, 1, free);
351 dict_free_all(&outlines, 1, free_outline);
352 dict_free_all(&gradients, 1, free_gradient);
353 dict_free_all(&filters, 1, free);
354 dict_free_all(&fonts, 1, free_font);
355 dict_free_all(&sounds, 1, free);
356 dict_free_all(&interpolations, 1, free);
357 cleanUp = 0;
360 static void freeFontDictionary()
362 dict_free_all(&fonts, 1, free_font);
365 static void incrementid()
367 while(id<65536 && idmap[id]) {
368 id++;
370 if(id>=65536)
371 syntaxerror("Out of character ids.");
372 idmap[id] = 1;
375 static void s_addcharacter(const char*name, U16 id, TAG*ctag, SRECT r)
377 if(dict_lookup(&characters, name))
378 syntaxerror("character %s defined twice", name);
379 character_t* c = character_new();
381 c->definingTag = ctag;
382 c->id = id;
383 c->size = r;
384 dict_put(&characters, name, c);
386 if(do_exports) {
387 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
388 swf_SetU16(tag, id);
389 swf_SetString(tag, name);
390 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
391 swf_SetU16(tag, 1);
392 swf_SetU16(tag, id);
393 swf_SetString(tag, name);
396 static void s_addimage(const char*name, U16 id, TAG*ctag, SRECT r)
398 if(dict_lookup(&images, name))
399 syntaxerror("image %s defined twice", name);
401 character_t* c = character_new();
402 c->definingTag = ctag;
403 c->id = id;
404 c->size = r;
405 dict_put(&images, name, c);
407 static instance_t* s_addinstance(const char*name, character_t*c, U16 depth)
409 if(dict_lookup(&instances, name))
410 syntaxerror("object %s defined twice", name);
411 instance_t* i = instance_new();
412 i->character = c;
413 i->depth = depth;
414 //swf_GetMatrix(0, &i->matrix);
415 dict_put(&instances, name, i);
416 return i;
419 static void parameters_clear(parameters_t*p)
421 p->x = 0; p->y = 0;
422 p->scalex = 1.0; p->scaley = 1.0;
423 p->pin.x = 0; //1??
424 p->pin.y = 0;
425 p->pivot.x = 0; p->pivot.y = 0;
426 p->rotate = 0;
427 p->shear = 0;
428 p->blendmode = 0;
429 p->filters = 0;
430 p->noinstancename = 0;
431 swf_GetCXForm(0, &p->cxform, 1);
434 static void makeMatrix(MATRIX*m, parameters_t*p)
436 SPOINT h;
437 float sx,r1,r0,sy;
439 /* /sx r1\ /x\
440 * \r0 sy/ \y/
443 sx = p->scalex*cos(p->rotate/360*2*M_PI);
444 r1 = -p->scalex*sin(p->rotate/360*2*M_PI)+sx*p->shear;
445 r0 = p->scaley*sin(p->rotate/360*2*M_PI);
446 sy = p->scaley*cos(p->rotate/360*2*M_PI)+r0*p->shear;
448 m->sx = (int)(sx*65536+0.5);
449 m->r1 = (int)(r1*65536+0.5);
450 m->r0 = (int)(r0*65536+0.5);
451 m->sy = (int)(sy*65536+0.5);
453 m->tx = m->ty = 0;
455 h = swf_TurnPoint(p->pin, m);
456 m->tx = p->x - h.x;
457 m->ty = p->y - h.y;
460 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
462 MATRIX m;
463 SRECT r;
464 makeMatrix(&m, p);
465 r = swf_TurnRect(rect, &m);
466 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
467 currentrect.xmax == 0 && currentrect.ymax == 0)
468 currentrect = r;
469 else
470 swf_ExpandRect2(&currentrect, &r);
471 return m;
474 void initBuiltIns()
476 interpolation_t* new;
477 new = (interpolation_t*)malloc(sizeof(interpolation_t));
478 new->function = IF_LINEAR;
479 dict_put(&interpolations, "linear", new);
481 new = (interpolation_t*)malloc(sizeof(interpolation_t));
482 new->function = IF_QUAD_IN;
483 new->slope = 0;
484 dict_put(&interpolations, "quadIn", new);
485 new = (interpolation_t*)malloc(sizeof(interpolation_t));
486 new->function = IF_QUAD_OUT;
487 new->slope = 0;
488 dict_put(&interpolations, "quadOut", new);
489 new = (interpolation_t*)malloc(sizeof(interpolation_t));
490 new->function = IF_QUAD_IN_OUT;
491 new->slope = 0;
492 dict_put(&interpolations, "quadInOut", new);
494 new = (interpolation_t*)malloc(sizeof(interpolation_t));
495 new->function = IF_CUBIC_IN;
496 new->slope = 0;
497 dict_put(&interpolations, "cubicIn", new);
498 new = (interpolation_t*)malloc(sizeof(interpolation_t));
499 new->function = IF_CUBIC_OUT;
500 new->slope = 0;
501 dict_put(&interpolations, "cubicOut", new);
502 new = (interpolation_t*)malloc(sizeof(interpolation_t));
503 new->function = IF_CUBIC_IN_OUT;
504 new->slope = 0;
505 dict_put(&interpolations, "cubicInOut", new);
507 new = (interpolation_t*)malloc(sizeof(interpolation_t));
508 new->function = IF_QUART_IN;
509 new->slope = 0;
510 dict_put(&interpolations, "quartIn", new);
511 new = (interpolation_t*)malloc(sizeof(interpolation_t));
512 new->function = IF_QUART_OUT;
513 new->slope = 0;
514 dict_put(&interpolations, "quartOut", new);
515 new = (interpolation_t*)malloc(sizeof(interpolation_t));
516 new->function = IF_QUART_IN_OUT;
517 new->slope = 0;
518 dict_put(&interpolations, "quartInOut", new);
520 new = (interpolation_t*)malloc(sizeof(interpolation_t));
521 new->function = IF_QUINT_IN;
522 new->slope = 0;
523 dict_put(&interpolations, "quintIn", new);
524 new = (interpolation_t*)malloc(sizeof(interpolation_t));
525 new->function = IF_QUINT_OUT;
526 new->slope = 0;
527 dict_put(&interpolations, "quintOut", new);
528 new = (interpolation_t*)malloc(sizeof(interpolation_t));
529 new->function = IF_QUINT_IN_OUT;
530 new->slope = 0;
531 dict_put(&interpolations, "quintInOut", new);
533 new = (interpolation_t*)malloc(sizeof(interpolation_t));
534 new->function = IF_CIRCLE_IN;
535 dict_put(&interpolations, "circleIn", new);
536 new = (interpolation_t*)malloc(sizeof(interpolation_t));
537 new->function = IF_CIRCLE_OUT;
538 dict_put(&interpolations, "circleOut", new);
539 new = (interpolation_t*)malloc(sizeof(interpolation_t));
540 new->function = IF_CIRCLE_IN_OUT;
541 dict_put(&interpolations, "circleInOut", new);
543 new = (interpolation_t*)malloc(sizeof(interpolation_t));
544 new->function = IF_EXPONENTIAL_IN;
545 dict_put(&interpolations, "exponentialIn", new);
546 new = (interpolation_t*)malloc(sizeof(interpolation_t));
547 new->function = IF_EXPONENTIAL_OUT;
548 dict_put(&interpolations, "exponentialOut", new);
549 new = (interpolation_t*)malloc(sizeof(interpolation_t));
550 new->function = IF_EXPONENTIAL_IN_OUT;
551 dict_put(&interpolations, "exponentialInOut", new);
553 new = (interpolation_t*)malloc(sizeof(interpolation_t));
554 new->function = IF_SINE_IN;
555 dict_put(&interpolations, "sineIn", new);
556 new = (interpolation_t*)malloc(sizeof(interpolation_t));
557 new->function = IF_SINE_OUT;
558 dict_put(&interpolations, "sineOut", new);
559 new = (interpolation_t*)malloc(sizeof(interpolation_t));
560 new->function = IF_SINE_IN_OUT;
561 dict_put(&interpolations, "sineInOut", new);
563 RGBA c;
564 memset(&c, 0, sizeof(RGBA));
565 gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
566 noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
567 noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
568 noGradient->gradient.num = 2;
569 noGradient->gradient.rgba[0] = c;
570 noGradient->gradient.ratios[0] = 0;
571 noGradient->gradient.rgba[1] = c;
572 noGradient->gradient.ratios[1] = 255;
573 noGradient->radial = 0;
574 noGradient->rotate = 0;
575 dict_put(&gradients, "no_gradient", noGradient);
577 noFilters = 0;
578 // put a no_filters entry in the filters dictionary to provoce a message when a user tries
579 // to define a no_filters filter. The real filter=no_filters case is handled in parseFilters.
580 FILTER* dummy = (FILTER*)malloc(sizeof(FILTER));
581 dict_put(&filters, "no_filters", dummy);
582 noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
583 noBlur->passes = 1;
584 dict_put(&filters, "no_blur", noBlur);
585 noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
586 noBevel->passes = 1;
587 noBevel->composite = 1;
588 dict_put(&filters, "no_bevel", noBevel);
589 noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
590 noDropshadow->passes = 1;
591 noDropshadow->composite = 1;
592 dict_put(&filters, "no_dropshadow", noDropshadow);
593 noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
594 noGradientGlow->passes = 1;
595 noGradientGlow->composite = 1;
596 noGradientGlow->gradient = &noGradient->gradient;
597 dict_put(&filters, "no_gradientglow", noGradientGlow);
600 void s_swf(const char*name, SRECT r, int version, int fps, int compress, RGBA background)
602 if(stackpos)
603 syntaxerror(".swf blocks can't be nested");
604 if(stackpos==sizeof(stack)/sizeof(stack[0]))
605 syntaxerror("too many levels of recursion");
607 SWF*swf = (SWF*)malloc(sizeof(SWF));
609 memset(swf, 0, sizeof(swf));
610 swf->fileVersion = version;
611 swf->movieSize = r;
612 swf->frameRate = fps;
613 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
614 swf->compressed = compress;
615 swf_SetRGB(tag,&background);
617 dict_init(&characters, 16);
618 dict_init(&images, 16);
619 dict_init(&textures, 16);
620 dict_init(&outlines, 16);
621 dict_init(&gradients, 16);
622 dict_init(&filters, 16);
623 dict_init(&instances, 16);
624 dict_init(&sounds, 16);
625 dict_init(&interpolations, 16);
626 initBuiltIns();
627 cleanUp = &freeDictionaries;
629 memset(&stack[stackpos], 0, sizeof(stack[0]));
630 stack[stackpos].type = 0;
631 stack[stackpos].filename = strdup(name);
632 stack[stackpos].swf = swf;
633 stack[stackpos].oldframe = -1;
634 stackpos++;
636 currentframe = 0;
637 memset(&currentrect, 0, sizeof(currentrect));
638 currentdepth = 1;
640 memset(idmap, 0, sizeof(idmap));
641 idmap[0]=1; //main movie has ID 0
643 incrementid();
646 void s_sprite(const char*name, SRECT*scalegrid, const char*as3name)
648 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
649 swf_SetU16(tag, id); //id
650 swf_SetU16(tag, 0); //frames
652 memset(&stack[stackpos], 0, sizeof(stack[0]));
653 stack[stackpos].type = 1;
654 stack[stackpos].oldframe = currentframe;
655 stack[stackpos].olddepth = currentdepth;
656 stack[stackpos].oldrect = currentrect;
657 stack[stackpos].oldinstances = instances;
658 stack[stackpos].tag = tag;
659 stack[stackpos].id = id;
660 stack[stackpos].name = strdup(name);
661 stack[stackpos].as3name = strdup(as3name);
662 if(scalegrid) {
663 stack[stackpos].scalegrid = *scalegrid;
664 } else {
665 memset(&stack[stackpos].scalegrid, 0, sizeof(SRECT));
668 /* FIXME: those four fields should be bundled together */
669 dict_init(&instances, 16);
670 currentframe = 0;
671 currentdepth = 1;
672 memset(&currentrect, 0, sizeof(currentrect));
674 stackpos++;
675 incrementid();
678 typedef struct _buttonrecord
680 U16 id;
681 MATRIX matrix;
682 CXFORM cxform;
683 char set;
684 } buttonrecord_t;
686 typedef struct _button
688 int endofshapes;
689 int nr_actions;
690 buttonrecord_t records[4];
691 } button_t;
693 static button_t mybutton;
695 void s_button(const char*name, const char*as3name)
697 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
698 swf_SetU16(tag, id); //id
699 swf_ButtonSetFlags(tag, 0); //menu=no
701 memset(&mybutton, 0, sizeof(mybutton));
703 memset(&stack[stackpos], 0, sizeof(stack[0]));
704 stack[stackpos].type = 3;
705 stack[stackpos].tag = tag;
706 stack[stackpos].id = id;
707 stack[stackpos].name = strdup(name);
708 stack[stackpos].as3name = strdup(as3name);
709 stack[stackpos].oldrect = currentrect;
710 memset(&currentrect, 0, sizeof(currentrect));
712 stackpos++;
713 incrementid();
715 void s_buttonput(const char*character, const char*as, parameters_t p)
717 character_t* c = dict_lookup(&characters, character);
718 MATRIX m;
719 int flags = 0;
720 const char*o = as,*s = as;
721 buttonrecord_t r;
722 if(!stackpos || (stack[stackpos-1].type != 3)) {
723 syntaxerror(".show may only appear in .button");
725 if(!c) {
726 syntaxerror("character %s not known (in .shape %s)", character, character);
728 if(mybutton.endofshapes) {
729 syntaxerror("a .do may not precede a .show", character, character);
732 m = s_instancepos(c->size, &p);
734 r.id = c->id;
735 r.matrix = m;
736 r.cxform = p.cxform;
737 r.set = 1;
739 while(1) {
740 if(*s==',' || *s==0) {
741 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
742 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
743 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
744 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
745 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
746 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
748 if(!*s)
749 break;
750 s++;
753 static void setbuttonrecords(TAG*tag)
755 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
756 if(!mybutton.endofshapes) {
757 int t;
759 if(!mybutton.records[3].set) {
760 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
763 for(t=0;t<4;t++) {
764 if(mybutton.records[t].set) {
765 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
768 swf_SetU8(tag,0); // end of button records
769 mybutton.endofshapes = 1;
773 void s_buttonaction(int flags, const char*action)
775 ActionTAG* a = 0;
776 if(flags==0) {
777 return;
779 if(!stackpos || !stack[stackpos-1].tag ||
780 stack[stackpos-1].tag->id != ST_DEFINEBUTTON2) {
781 syntaxerror("Need to be inside a button for .on_* commands");
783 setbuttonrecords(stack[stackpos-1].tag);
785 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
786 if(!a) {
787 syntaxerror("Couldn't compile ActionScript");
790 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
791 swf_ActionSet(stack[stackpos-1].tag, a);
792 mybutton.nr_actions++;
794 swf_ActionFree(a);
797 static void setactionend(TAG*tag)
799 if(!mybutton.nr_actions) {
800 /* no actions means we didn't have an actionoffset,
801 which means we can't signal the end of the
802 buttonaction records, so, *sigh*, we have
803 to insert a dummy record */
804 swf_SetU16(tag, 0); //offset
805 swf_SetU16(tag, 0); //condition
806 swf_SetU8(tag, 0); //action
810 static void s_endButton()
812 SRECT r;
813 setbuttonrecords(stack[stackpos-1].tag);
814 setactionend(stack[stackpos-1].tag);
815 stackpos--;
817 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
819 r = currentrect;
821 tag = stack[stackpos].tag;
822 currentrect = stack[stackpos].oldrect;
824 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
826 if(*stack[stackpos].as3name) {
827 tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
828 swf_SetU16(tag, 1);
829 swf_SetU16(tag, stack[stackpos].id);
830 swf_SetString(tag, stack[stackpos].as3name);
833 free(stack[stackpos].name);
836 TAG* removeFromTo(TAG*from, TAG*to)
838 TAG*save = from->prev;
839 while(from!=to) {
840 TAG*next = from->next;
841 if(swf_isAllowedSpriteTag(from))
842 swf_DeleteTag(0, from);
843 from = next;
845 save->next = 0;
846 return save;
849 static int parametersChange(history_t* history, int frame)
851 int willChange = 0;
853 willChange = willChange || history_change(history, frame, "x");
854 willChange = willChange || history_change(history, frame, "y");
855 willChange = willChange || history_change(history, frame, "scalex");
856 willChange = willChange || history_change(history, frame, "scaley");
857 willChange = willChange || history_change(history, frame, "cxform.r0");
858 willChange = willChange || history_change(history, frame, "cxform.g0");
859 willChange = willChange || history_change(history, frame, "cxform.b0");
860 willChange = willChange || history_change(history, frame, "cxform.a0");
861 willChange = willChange || history_change(history, frame, "cxform.r1");
862 willChange = willChange || history_change(history, frame, "cxform.g1");
863 willChange = willChange || history_change(history, frame, "cxform.b1");
864 willChange = willChange || history_change(history, frame, "cxform.a1");
865 willChange = willChange || history_change(history, frame, "rotate");
866 willChange = willChange || history_change(history, frame, "shear");
867 willChange = willChange || history_change(history, frame, "pivot.x");
868 willChange = willChange || history_change(history, frame, "pivot.y");
869 willChange = willChange || history_change(history, frame, "pin.x");
870 willChange = willChange || history_change(history, frame, "pin.y");
871 willChange = willChange || history_change(history, frame, "blendmode");
872 willChange = willChange || history_changeFilter(history, frame);
874 return willChange;
877 static void free_filterlist(FILTERLIST* f_list)
879 int i;
880 for (i = 0; i < f_list->num; i++)
882 if(f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
883 gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
884 free(f_list->filter[i]);
886 free(f_list);
889 static void readParameters(history_t* history, parameters_t* p, int frame)
891 p->x = history_value(history, frame, "x");
892 p->y = history_value(history, frame, "y");
893 p->scalex = history_value(history, frame, "scalex");
894 p->scaley = history_value(history, frame, "scaley");
895 p->cxform.r0 = history_value(history, frame, "cxform.r0");
896 p->cxform.g0 = history_value(history, frame, "cxform.g0");
897 p->cxform.b0 = history_value(history, frame, "cxform.b0");
898 p->cxform.a0 = history_value(history, frame, "cxform.a0");
899 p->cxform.r1 = history_value(history, frame, "cxform.r1");
900 p->cxform.g1 = history_value(history, frame, "cxform.g1");
901 p->cxform.b1 = history_value(history, frame, "cxform.b1");
902 p->cxform.a1 = history_value(history, frame, "cxform.a1");
903 p->rotate = history_rotateValue(history, frame);
904 p->shear = history_value(history, frame, "shear");
905 p->pivot.x = history_value(history, frame, "pivot.x");
906 p->pivot.y = history_value(history, frame, "pivot.y");
907 p->pin.x = history_value(history, frame, "pin.x");
908 p->pin.y = history_value(history, frame, "pin.y");
909 p->blendmode = history_value(history, frame, "blendmode");
910 p->filters = history_filterValue(history, frame);
913 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, const char*name, parameters_t*p, char move)
915 SWFPLACEOBJECT po;
916 FILTERLIST flist;
917 swf_GetPlaceObject(NULL, &po);
918 po.id = id;
919 po.depth = depth;
920 po.matrix = m;
921 po.cxform = p->cxform;
922 po.name = (char*)name;
923 po.move = move;
924 if(move)
925 po.id = 0;
926 if(p->blendmode) {
927 po.blendmode = p->blendmode;
929 if(p->filters)
930 po.filters = p->filters;
931 swf_SetPlaceObject(tag, &po);
934 static void writeInstance(void* _i)
936 instance_t*i = (instance_t*)_i;
937 parameters_t p;
938 MATRIX m;
939 int frame = i->history->firstFrame;
940 TAG* tag = i->history->firstTag;
941 history_processFlags(i->history);
942 while (tag && frame < currentframe)
944 frame++;
945 while (tag && tag->id != ST_SHOWFRAME)
946 tag = tag->next;
947 if(parametersChange(i->history, frame))
949 readParameters(i->history, &p, frame);
950 m = s_instancepos(i->character->size, &p);
952 if(p.blendmode || p.filters)
953 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
954 else
955 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
956 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
957 if(p.filters)
958 free_filterlist(p.filters);
959 } else if(tag) {
960 tag = tag->next;
965 void dumpSWF(SWF*swf)
967 TAG* tag = swf->firstTag;
968 printf("vvvvvvvvvvvvvvvvvvvvv\n");
969 while(tag) {
970 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
971 tag = tag->next;
973 printf("^^^^^^^^^^^^^^^^^^^^^\n");
976 static void s_endSprite()
978 SRECT r = currentrect;
980 stackpos--;
981 instance_t *i;
983 dict_foreach_value(&instances, writeInstance);
985 if(stack[stackpos].cut)
986 tag = removeFromTo(stack[stackpos].cut, tag);
988 // the writeInstance loop above may have inserted tags after what used to be the current tag,
989 // so let's make sure 'tag' point to the current tag again.
990 while (tag->next)
991 tag = tag->next;
993 tag = swf_InsertTag(tag, ST_SHOWFRAME);
994 tag = swf_InsertTag(tag, ST_END);
996 tag = stack[stackpos].tag;
997 swf_FoldSprite(tag);
999 if(stack[stackpos].scalegrid.xmin | stack[stackpos].scalegrid.ymin |
1000 stack[stackpos].scalegrid.xmax | stack[stackpos].scalegrid.ymax)
1002 tag = swf_InsertTag(tag, ST_DEFINESCALINGGRID);
1003 swf_SetU16(tag, stack[stackpos].id);
1004 swf_SetRect(tag, &stack[stackpos].scalegrid);
1007 if(tag->next != 0)
1008 syntaxerror("internal error(7)");
1009 /* TODO: before clearing, prepend "<spritename>." to names and
1010 copy into old instances dict */
1011 dict_free_all(&instances, 1, free_instance);
1013 currentframe = stack[stackpos].oldframe;
1014 currentrect = stack[stackpos].oldrect;
1015 currentdepth = stack[stackpos].olddepth;
1016 instances = stack[stackpos].oldinstances;
1018 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
1020 if(*stack[stackpos].as3name) {
1021 tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
1022 swf_SetU16(tag, 1);
1023 swf_SetU16(tag, stack[stackpos].id);
1024 swf_SetString(tag, stack[stackpos].as3name);
1028 free(stack[stackpos].name);
1031 static void s_endSWF()
1033 int fi;
1034 SWF* swf;
1035 char*filename;
1036 char*mc="";
1038 dict_foreach_value(&instances, writeInstance);
1040 if(stack[stackpos].cut)
1041 tag = removeFromTo(stack[stackpos].cut, tag);
1043 stackpos--;
1045 swf = stack[stackpos].swf;
1046 filename = stack[stackpos].filename;
1048 // the writeInstance loop above may have inserted tags after what used yo be the current tag,
1049 // so let's make sure 'tag' point to the current tag again.
1050 while (tag->next)
1051 tag = tag->next;
1053 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1054 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
1055 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1057 if(stack[0].as3) {
1058 TAG*tag = swf->firstTag;
1059 tag = swf_InsertTag(tag, ST_DOABC);
1060 void*code = as3_getcode();
1061 swf_WriteABC(tag, code);
1062 if(*mainclass)
1063 mc = mainclass;
1064 else if(as3_getglobalclass())
1065 mc = as3_getglobalclass();
1066 if(*mc) {
1067 tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
1068 swf_SetU16(tag, 1);
1069 swf_SetU16(tag, 0);
1070 swf_SetString(tag, mc);
1071 } else {
1072 warning("no global public MovieClip subclass");
1074 as3_destroy();
1077 tag = swf_InsertTag(tag, ST_END);
1079 swf_OptimizeTagOrder(swf);
1081 if(optimize) {
1082 swf_Optimize(swf);
1085 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1086 swf->movieSize = currentrect; /* "autocrop" */
1089 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1090 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1091 swf->movieSize.ymax += 20;
1092 warning("Empty bounding box for movie");
1095 if(do_cgi || !strcmp(filename, "-"))
1096 fi = fileno(stdout);
1097 else
1098 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1099 if(fi<0) {
1100 syntaxerror("couldn't create output file %s", filename);
1102 if(do_cgi)
1103 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1104 else
1105 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1107 close(fi);
1109 freeDictionaries();
1111 swf_FreeTags(swf);
1112 free(swf);
1113 free(filename);
1116 void s_close()
1118 if(stackpos) {
1119 if(stack[stackpos-1].type == 0)
1120 syntaxerror("End of file encountered in .flash block");
1121 if(stack[stackpos-1].type == 1)
1122 syntaxerror("End of file encountered in .sprite block");
1123 if(stack[stackpos-1].type == 2)
1124 syntaxerror("End of file encountered in .clip block");
1128 int s_getframe()
1130 return currentframe+1;
1133 void s_frame(int nr, int cut, const char*name, char anchor)
1135 int t;
1136 TAG*now = tag;
1138 if(nr<1)
1139 syntaxerror("Illegal frame number");
1140 nr--; // internally, frame 1 is frame 0
1142 for(t=currentframe;t<nr;t++) {
1143 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1144 if(t==nr-1 && name && *name) {
1145 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1146 swf_SetString(tag, name);
1147 if(anchor)
1148 swf_SetU8(tag, 1); //make this an anchor
1151 if(nr == 0 && currentframe == 0 && name && *name) {
1152 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1153 swf_SetString(tag, name);
1154 if(anchor)
1155 swf_SetU8(tag, 1); //make this an anchor
1158 if(cut) {
1159 if(now == tag) {
1160 syntaxerror("Can't cut, frame empty");
1162 stack[stackpos].cut = tag;
1165 currentframe = nr;
1168 int parseColor2(const char*str, RGBA*color);
1170 int addFillStyle(SHAPE*s, SRECT*r, const char*name)
1172 RGBA color;
1173 character_t*image;
1174 gradient_t*gradient;
1175 texture_t*texture;
1176 if(name[0] == '#') {
1177 parseColor2(name, &color);
1178 return swf_ShapeAddSolidFillStyle(s, &color);
1179 } else if((texture = dict_lookup(&textures, name))) {
1180 return swf_ShapeAddFillStyle2(s, &texture->fs);
1181 } else if((image = dict_lookup(&images, name))) {
1182 MATRIX m;
1183 swf_GetMatrix(0, &m);
1184 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1185 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1186 m.tx = r->xmin;
1187 m.ty = r->ymin;
1188 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1189 } else if((gradient = dict_lookup(&gradients, name))) {
1190 SRECT r2;
1191 MATRIX rot,m;
1192 double ccos,csin;
1193 swf_GetMatrix(0, &rot);
1194 ccos = cos(-gradient->rotate*2*M_PI/360);
1195 csin = sin(-gradient->rotate*2*M_PI/360);
1196 rot.sx = ccos*65536;
1197 rot.r1 = -csin*65536;
1198 rot.r0 = csin*65536;
1199 rot.sy = ccos*65536;
1200 r2 = swf_TurnRect(*r, &rot);
1201 swf_GetMatrix(0, &m);
1202 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1203 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1204 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1205 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1206 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1207 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1208 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1209 } else if(parseColor2(name, &color)) {
1210 return swf_ShapeAddSolidFillStyle(s, &color);
1211 } else {
1212 syntaxerror("not a color/fillstyle: %s", name);
1213 return 0;
1217 RGBA black={r:0,g:0,b:0,a:0};
1218 void s_box(const char*name, int width, int height, RGBA color, int linewidth, const char*texture)
1220 SRECT r,r2;
1221 SHAPE* s;
1222 int ls1=0,fs1=0;
1223 r2.xmin = 0;
1224 r2.ymin = 0;
1225 r2.xmax = width;
1226 r2.ymax = height;
1227 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1228 swf_ShapeNew(&s);
1229 if(linewidth) {
1230 linewidth = linewidth>=20?linewidth-20:0;
1231 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1233 if(texture)
1234 fs1 = addFillStyle(s, &r2, texture);
1236 swf_SetU16(tag,id);
1237 r.xmin = r2.xmin-linewidth/2;
1238 r.ymin = r2.ymin-linewidth/2;
1239 r.xmax = r2.xmax+linewidth/2;
1240 r.ymax = r2.ymax+linewidth/2;
1241 swf_SetRect(tag,&r);
1242 swf_SetShapeHeader(tag,s);
1243 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1244 swf_ShapeSetLine(tag,s,width,0);
1245 swf_ShapeSetLine(tag,s,0,height);
1246 swf_ShapeSetLine(tag,s,-width,0);
1247 swf_ShapeSetLine(tag,s,0,-height);
1248 swf_ShapeSetEnd(tag);
1249 swf_ShapeFree(s);
1251 s_addcharacter(name, id, tag, r);
1252 incrementid();
1255 void s_filled(const char*name, const char*outlinename, RGBA color, int linewidth, const char*texture)
1257 SRECT rect,r2;
1258 SHAPE* s;
1259 int ls1,fs1=0;
1260 outline_t* outline;
1261 outline = dict_lookup(&outlines, outlinename);
1262 if(!outline) {
1263 syntaxerror("outline %s not defined", outlinename);
1265 r2 = outline->bbox;
1267 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1268 swf_ShapeNew(&s);
1269 if(linewidth) {
1270 linewidth = linewidth>=20?linewidth-20:0;
1271 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1273 if(texture)
1274 fs1 = addFillStyle(s, &r2, texture);
1276 swf_SetU16(tag,id);
1277 rect.xmin = r2.xmin-linewidth/2;
1278 rect.ymin = r2.ymin-linewidth/2;
1279 rect.xmax = r2.xmax+linewidth/2;
1280 rect.ymax = r2.ymax+linewidth/2;
1282 swf_SetRect(tag,&rect);
1283 swf_SetShapeStyles(tag, s);
1284 swf_ShapeCountBits(s,0,0);
1285 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1286 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1287 swf_SetShapeBits(tag, s);
1288 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1289 swf_ShapeFree(s);
1291 s_addcharacter(name, id, tag, rect);
1292 incrementid();
1295 void s_circle(const char*name, int r, RGBA color, int linewidth, const char*texture)
1297 SRECT rect,r2;
1298 SHAPE* s;
1299 int ls1=0,fs1=0;
1300 r2.xmin = r2.ymin = 0;
1301 r2.xmax = 2*r;
1302 r2.ymax = 2*r;
1304 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1305 swf_ShapeNew(&s);
1306 if(linewidth) {
1307 linewidth = linewidth>=20?linewidth-20:0;
1308 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1310 if(texture)
1311 fs1 = addFillStyle(s, &r2, texture);
1312 swf_SetU16(tag,id);
1313 rect.xmin = r2.xmin-linewidth/2;
1314 rect.ymin = r2.ymin-linewidth/2;
1315 rect.xmax = r2.xmax+linewidth/2;
1316 rect.ymax = r2.ymax+linewidth/2;
1318 swf_SetRect(tag,&rect);
1319 swf_SetShapeHeader(tag,s);
1320 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1321 swf_ShapeSetCircle(tag, s, r,r,r,r);
1322 swf_ShapeSetEnd(tag);
1323 swf_ShapeFree(s);
1325 s_addcharacter(name, id, tag, rect);
1326 incrementid();
1329 void s_textshape(const char*name, const char*fontname, float size, const char*_text)
1331 int g;
1332 U8*text = (U8*)_text;
1333 outline_t* outline;
1335 SWFFONT*font;
1336 font = dict_lookup(&fonts, fontname);
1337 if(!font)
1338 syntaxerror("font \"%s\" not known!", fontname);
1340 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1341 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1342 s_box(name, 0, 0, black, 20, 0);
1343 return;
1345 g = font->ascii2glyph[text[0]];
1347 outline = malloc(sizeof(outline_t));
1348 memset(outline, 0, sizeof(outline_t));
1349 outline->shape = font->glyph[g].shape;
1350 outline->bbox = font->layout->bounds[g];
1353 drawer_t draw;
1354 swf_Shape11DrawerInit(&draw, 0);
1355 swf_DrawText(&draw, font, (int)(size*100), (char*)_text);
1356 draw.finish(&draw);
1357 outline->shape = swf_ShapeDrawerToShape(&draw);
1358 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1359 draw.dealloc(&draw);
1362 if(dict_lookup(&outlines, name))
1363 syntaxerror("outline %s defined twice", name);
1364 dict_put(&outlines, name, outline);
1367 void s_text(const char*name, const char*fontname, const char*text, int size, RGBA color)
1369 SRECT r;
1370 MATRIX _m,*m=0;
1371 SWFFONT*font;
1372 font = dict_lookup(&fonts, fontname);
1373 if(!font)
1374 syntaxerror("font \"%s\" not known!", fontname);
1376 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1377 swf_SetU16(tag, id);
1378 if(!font->numchars) {
1379 s_box(name, 0, 0, black, 20, 0);
1380 return;
1382 r = swf_SetDefineText(tag, font, &color, (char*)text, size);
1384 if(stack[0].swf->fileVersion >= 8) {
1385 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1386 swf_SetU16(tag, id);
1387 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1388 swf_SetU32(tag, 0);//thickness
1389 swf_SetU32(tag, 0);//sharpness
1390 swf_SetU8(tag, 0);//reserved
1393 s_addcharacter(name, id, tag, r);
1394 incrementid();
1397 void s_quicktime(const char*name, const char*url)
1399 SRECT r;
1400 MATRIX _m,*m=0;
1402 memset(&r, 0, sizeof(r));
1404 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1405 swf_SetU16(tag, id);
1406 swf_SetString(tag, url);
1408 s_addcharacter(name, id, tag, r);
1409 incrementid();
1412 void s_video(const char *name, int width, int height)
1414 SRECT r;
1416 memset(&r, 0, sizeof(r));
1418 tag = swf_InsertTag(tag, ST_DEFINEVIDEOSTREAM);
1419 swf_SetU16(tag, id);
1420 swf_SetU16(tag, 0); // numframes
1421 swf_SetU16(tag, width);
1422 swf_SetU16(tag, height);
1423 swf_SetU8(tag, 0); // videoflags
1424 swf_SetU8(tag, 0); // codecid
1426 s_addcharacter(name, id, tag, r);
1427 incrementid();
1430 void s_edittext(const char*name, const char*fontname, int size, int width, int height, const char*text, RGBA*color, int maxlength, const char*variable, int flags, int align)
1432 SWFFONT*font = 0;
1433 EditTextLayout layout;
1434 SRECT r;
1436 if(fontname && *fontname) {
1437 flags |= ET_USEOUTLINES;
1438 font = dict_lookup(&fonts, fontname);
1439 if(!font)
1440 syntaxerror("font \"%s\" not known!", fontname);
1442 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1443 swf_SetU16(tag, id);
1444 layout.align = align;
1445 layout.leftmargin = 0;
1446 layout.rightmargin = 0;
1447 layout.indent = 0;
1448 layout.leading = 0;
1449 r.xmin = 0;
1450 r.ymin = 0;
1451 r.xmax = width;
1452 r.ymax = height;
1454 swf_SetEditText(tag, flags, r, (char*)text, color, maxlength, font?font->id:0, size, &layout, (char*)variable);
1456 s_addcharacter(name, id, tag, r);
1457 incrementid();
1460 /* type: either "jpeg" or "png"
1462 void s_image(const char*name, const char*type, const char*filename, int quality)
1464 /* an image is actually two folded: 1st bitmap, 2nd character.
1465 Both of them can be used separately */
1467 /* step 1: the bitmap */
1468 SRECT r;
1469 int imageID = id;
1470 unsigned width, height;
1471 if(!strcmp(type,"jpeg")) {
1472 #ifndef HAVE_JPEGLIB
1473 warning("no jpeg support compiled in");
1474 s_box(name, 0, 0, black, 20, 0);
1475 return;
1476 #else
1477 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1478 swf_SetU16(tag, imageID);
1480 if(swf_SetJPEGBits(tag, (char*)filename, quality) < 0) {
1481 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1484 swf_GetJPEGSize(filename, &width, &height);
1486 r.xmin = 0;
1487 r.ymin = 0;
1488 r.xmax = width*20;
1489 r.ymax = height*20;
1491 s_addimage(name, id, tag, r);
1492 incrementid();
1493 #endif
1494 } else if(!strcmp(type,"png")) {
1495 RGBA*data = 0;
1496 swf_SetU16(tag, imageID);
1498 png_load(filename, &width, &height, (unsigned char**)&data);
1500 if(!data) {
1501 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1504 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1505 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1506 swf_SetU16(tag, imageID);
1507 swf_SetLosslessImage(tag, data, width, height);
1508 free(data);
1510 r.xmin = 0;
1511 r.ymin = 0;
1512 r.xmax = width*20;
1513 r.ymax = height*20;
1514 s_addimage(name, id, tag, r);
1515 incrementid();
1516 } else {
1517 warning("image type \"%s\" not supported yet!", type);
1518 s_box(name, 0, 0, black, 20, 0);
1519 return;
1522 /* step 2: the character */
1523 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1524 swf_SetU16(tag, id);
1525 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1527 s_addcharacter(name, id, tag, r);
1528 incrementid();
1531 void s_getBitmapSize(const char*name, int*width, int*height)
1533 character_t* image = dict_lookup(&images, name);
1534 gradient_t* gradient = dict_lookup(&gradients,name);
1535 if(image) {
1536 *width = image->size.xmax;
1537 *height = image->size.ymax;
1538 return;
1540 if(gradient) {
1541 /* internal SWF gradient size */
1542 if(gradient->radial) {
1543 *width = 16384;
1544 *height = 16384;
1545 } else {
1546 *width = 32768;
1547 *height = 32768;
1549 return;
1551 syntaxerror("No such bitmap/gradient: %s", name);
1554 void s_texture(const char*name, const char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1556 if(dict_lookup(&textures, name))
1557 syntaxerror("texture %s defined twice", name);
1558 gradient_t* gradient = dict_lookup(&gradients, object);
1559 character_t* bitmap = dict_lookup(&images, object);
1560 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1561 parameters_t p;
1562 FILLSTYLE*fs = &texture->fs;
1564 memset(&p, 0, sizeof(parameters_t));
1566 if(bitmap) {
1567 fs->type = FILL_TILED;
1568 fs->id_bitmap = bitmap->id;
1569 } else if(gradient) {
1570 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1571 fs->gradient = gradient->gradient;
1573 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1574 makeMatrix(&fs->m, &p);
1575 if(gradient && !gradient->radial) {
1576 MATRIX m = fs->m;
1577 SPOINT p1,p2;
1578 m.tx = 0;
1579 m.ty = 0;
1580 p1.x = 16384;
1581 p1.y = 16384;
1582 p2 = swf_TurnPoint(p1, &m);
1583 fs->m.tx += p2.x;
1584 fs->m.ty += p2.y;
1586 if(bitmap) {
1587 fs->m.sx *= 20;
1588 fs->m.sy *= 20;
1591 dict_put(&textures, name, texture);
1594 void s_createfont(const char*name, const char*filename, const char*glyphs, char flashtype)
1596 if(dict_lookup(&fonts, name))
1597 syntaxerror("font %s defined twice", name);
1599 SWFFONT* font = swf_LoadFont(filename, flashtype);
1600 if(font == 0) {
1601 warning("Couldn't open font file \"%s\"", filename);
1602 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1603 memset(font, 0, sizeof(SWFFONT));
1604 dict_put(&fonts, name, font);
1605 return;
1607 swf_FontPrepareForEditText(font);
1609 if(!strcmp(glyphs, "all")) {
1610 swf_FontUseAll(font);
1611 font->use->glyphs_specified = 1;
1612 } else {
1613 if(!glyphs[0]) {
1614 swf_FontInitUsage(font);
1615 } else {
1616 swf_FontUseUTF8(font, (const U8*)glyphs, 0xffff);
1617 font->use->glyphs_specified = 1;
1620 dict_put(&fonts, name, font);
1623 void s_font(const char*name, const char*filename)
1625 SWFFONT* font;
1626 font = dict_lookup(&fonts, name);
1627 font->id = id;
1628 swf_FontReduce_swfc(font);
1630 if(font->version>=3 && stack[0].swf->fileVersion < 8) {
1631 warning("flashtype not supported for flash versions 8 and below");
1634 tag = swf_InsertTag(tag, font->version==3?ST_DEFINEFONT3:ST_DEFINEFONT2);
1635 swf_FontSetDefine2(tag, font);
1637 if(do_exports) {
1638 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1639 swf_SetU16(tag, 1);
1640 swf_SetU16(tag, id);
1641 swf_SetString(tag, name);
1644 incrementid();
1649 typedef struct _sound_t
1651 U16 id;
1652 TAG*tag;
1653 } sound_t;
1655 void s_sound(const char*name, const char*filename)
1657 struct WAV wav, wav2;
1658 struct MP3 mp3;
1659 sound_t* sound;
1660 U16*samples = NULL;
1661 unsigned numsamples = 1;
1662 unsigned blocksize = 1152;
1663 int is_mp3 = 0;
1665 if(dict_lookup(&sounds, name))
1666 syntaxerror("sound %s defined twice", name);
1668 if(wav_read(&wav, filename))
1670 int t;
1671 wav_convert2mono(&wav, &wav2, 44100);
1672 samples = (U16*)wav2.data;
1673 numsamples = wav2.size/2;
1674 free(wav.data);
1675 #ifdef WORDS_BIGENDIAN
1676 /* swap bytes */
1677 for(t=0;t<numsamples;t++)
1678 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1679 #endif
1681 else
1682 if(mp3_read(&mp3, filename))
1684 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1685 blocksize = 1;
1686 is_mp3 = 1;
1688 else
1690 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1691 samples = 0;
1692 numsamples = 0;
1695 if(numsamples%blocksize != 0)
1697 // apply padding, so that block is a multiple of blocksize
1698 int numblocks = (numsamples+blocksize-1)/blocksize;
1699 int numsamples2;
1700 U16* samples2;
1701 numsamples2 = numblocks * blocksize;
1702 samples2 = malloc(sizeof(U16)*numsamples2);
1703 memcpy(samples2, samples, numsamples*sizeof(U16));
1704 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1705 numsamples = numsamples2;
1706 free(samples);
1707 samples = samples2;
1710 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1711 swf_SetU16(tag, id); //id
1712 if(is_mp3)
1714 swf_SetSoundDefineMP3(
1715 tag, mp3.data, mp3.size,
1716 mp3.SampRate,
1717 mp3.Channels,
1718 mp3.NumFrames);
1719 mp3_clear(&mp3);
1721 else
1722 swf_SetSoundDefine(tag, samples, numsamples);
1724 if(do_exports) {
1725 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1726 swf_SetU16(tag, id);
1727 swf_SetString(tag, name);
1728 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1729 swf_SetU16(tag, 1);
1730 swf_SetU16(tag, id);
1731 swf_SetString(tag, name);
1734 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1735 sound->tag = tag;
1736 sound->id = id;
1738 dict_put(&sounds, name, sound);
1740 incrementid();
1742 if(samples)
1743 free(samples);
1746 static char* gradient_getToken(const char**p)
1748 const char*start;
1749 char*result;
1750 while(**p && strchr(" \t\n\r", **p)) {
1751 (*p)++;
1753 start = *p;
1754 while(**p && !strchr(" \t\n\r", **p)) {
1755 (*p)++;
1757 result = malloc((*p)-start+1);
1758 memcpy(result,start,(*p)-start+1);
1759 result[(*p)-start] = 0;
1760 return result;
1763 float parsePercent(const char*str);
1764 RGBA parseColor(const char*str);
1766 GRADIENT parseGradient(const char*str)
1768 GRADIENT gradient;
1769 int lastpos = -1;
1770 const char* p = str;
1771 memset(&gradient, 0, sizeof(GRADIENT));
1772 gradient.ratios = rfx_calloc(16*sizeof(U8));
1773 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1775 while(*p)
1777 char*posstr,*colorstr;
1778 int pos;
1779 RGBA color;
1780 posstr = gradient_getToken(&p);
1781 if(!*posstr)
1783 free(posstr);
1784 break;
1786 pos = (int)(parsePercent(posstr)*255.0);
1787 if(pos == lastpos)
1788 pos++;
1789 if(!*p)
1791 rfx_free(gradient.ratios);
1792 rfx_free(gradient.rgba);
1793 free(posstr);
1794 syntaxerror("Error in shape data: Color expected after %s", posstr);
1796 colorstr = gradient_getToken(&p);
1797 color = parseColor(colorstr);
1798 if(gradient.num == 16)
1800 warning("gradient record too big- max size is 16, rest ignored");
1801 break;
1803 gradient.ratios[gradient.num] = pos;
1804 gradient.rgba[gradient.num] = color;
1805 gradient.num++;
1806 free(posstr);
1807 free(colorstr);
1808 lastpos = pos;
1810 return gradient;
1813 FILTERLIST* parseFilters(char* list)
1815 if(!strcmp(list, "no_filters"))
1816 return 0;
1817 FILTER* f;
1818 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1819 f_list->num = 0;
1820 char* f_start = list;
1821 char* f_end;
1822 while (f_start)
1824 f_end = strchr(f_start, ',');
1825 if(f_end)
1826 *f_end = '\0';
1827 f = dict_lookup(&filters, f_start);
1828 if(!f)
1830 free(f_list);
1831 syntaxerror("unknown filter %s", f_start);
1833 if(f_list->num == 8)
1835 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1836 break;
1838 f_list->filter[f_list->num] = f;
1839 f_list->num++;
1840 if(f_end)
1842 *f_end = ',';
1843 f_start = f_end + 1;
1845 else
1846 f_start = 0;
1848 return f_list;
1851 void s_gradient(const char*name, const char*text, int radial, int rotate)
1853 gradient_t* gradient;
1854 gradient = malloc(sizeof(gradient_t));
1855 memset(gradient, 0, sizeof(gradient_t));
1856 gradient->gradient = parseGradient(text);
1857 gradient->radial = radial;
1858 gradient->rotate = rotate;
1860 dict_put(&gradients, name, gradient);
1863 void s_gradientglow(const char*name, const char*gradient, float blurx, float blury,
1864 float angle, float distance, float strength, char innershadow,
1865 char knockout, char composite, char ontop, int passes)
1867 if(dict_lookup(&filters, name))
1868 syntaxerror("filter %s defined twice", name);
1870 gradient_t* g = dict_lookup(&gradients, gradient);
1871 if(!g)
1872 syntaxerror("unknown gradient %s", gradient);
1874 composite = 1;
1876 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1877 filter->type = FILTERTYPE_GRADIENTGLOW;
1878 filter->gradient = &g->gradient;
1879 filter->blurx = blurx;
1880 filter->blury = blury;
1881 filter->strength = strength;
1882 filter->angle = angle;
1883 filter->distance = distance;
1884 filter->innershadow = innershadow;
1885 filter->knockout = knockout;
1886 filter->composite = composite;
1887 filter->ontop = ontop;
1888 filter->passes = passes;
1890 dict_put(&filters, name, filter);
1893 void s_dropshadow(const char*name, RGBA color, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, int passes)
1895 if(dict_lookup(&filters, name))
1896 syntaxerror("filter %s defined twice", name);
1898 composite = 1;
1899 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1900 filter->type = FILTERTYPE_DROPSHADOW;
1901 filter->color= color;
1902 filter->blurx = blurx;
1903 filter->blury = blury;
1904 filter->strength = strength;
1905 filter->angle = angle;
1906 filter->distance = distance;
1907 filter->innershadow = innershadow;
1908 filter->knockout = knockout;
1909 filter->composite = composite;
1910 filter->passes = passes;
1912 dict_put(&filters, name, filter);
1915 void s_bevel(const char*name, RGBA shadow, RGBA highlight, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, char ontop, int passes)
1917 if(dict_lookup(&filters, name))
1918 syntaxerror("filter %s defined twice", name);
1920 composite = 1;
1921 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1922 filter->type = FILTERTYPE_BEVEL;
1923 filter->shadow = shadow;
1924 filter->highlight = highlight;
1925 filter->blurx = blurx;
1926 filter->blury = blury;
1927 filter->strength = strength;
1928 filter->angle = angle;
1929 filter->distance = distance;
1930 filter->innershadow = innershadow;
1931 filter->knockout = knockout;
1932 filter->composite = composite;
1933 filter->ontop = ontop;
1934 filter->passes = passes;
1936 dict_put(&filters, name, filter);
1939 void s_blur(const char*name, double blurx, double blury, int passes)
1941 if(dict_lookup(&filters, name))
1942 syntaxerror("filter %s defined twice", name);
1944 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1945 filter->type = FILTERTYPE_BLUR;
1946 filter->blurx = blurx;
1947 filter->blury = blury;
1948 filter->passes = passes;
1950 dict_put(&filters, name, filter);
1953 void s_action(const char*text)
1955 if(stack[0].swf->fileVersion < 9) {
1956 ActionTAG* a = 0;
1957 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1958 if(!a) {
1959 swf_ActionFree(a);
1960 syntaxerror("Couldn't compile ActionScript");
1962 tag = swf_InsertTag(tag, ST_DOACTION);
1963 swf_ActionSet(tag, a);
1964 swf_ActionFree(a);
1965 } else {
1966 as3_parse_bytearray(stack[0].filename, text, strlen(text));
1967 stack[0].as3 = 1;
1971 void s_initaction(const char*character, const char*text)
1973 ActionTAG* a = 0;
1974 character_t*c = 0;
1975 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1976 if(!a)
1978 swf_ActionFree(a);
1979 syntaxerror("Couldn't compile ActionScript");
1982 c = (character_t*)dict_lookup(&characters, character);
1984 tag = swf_InsertTag(tag, ST_DOINITACTION);
1985 swf_SetU16(tag, c->id);
1986 swf_ActionSet(tag, a);
1988 swf_ActionFree(a);
1991 int s_swf3action(const char*name, const char*action)
1993 ActionTAG* a = 0;
1994 instance_t* object = 0;
1995 if(name)
1996 object = (instance_t*)dict_lookup(&instances, name);
1997 if(!object && name && *name) {
1998 /* we have a name, but couldn't find it. Abort. */
1999 return 0;
2001 a = action_SetTarget(0, name);
2002 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
2003 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
2004 else if(!strcmp(action, "stop")) a = action_Stop(a);
2005 else if(!strcmp(action, "play")) a = action_Play(a);
2006 a = action_SetTarget(a, "");
2007 a = action_End(a);
2009 tag = swf_InsertTag(tag, ST_DOACTION);
2010 swf_ActionSet(tag, a);
2011 swf_ActionFree(a);
2012 return 1;
2015 void s_outline(const char*name, const char*format, const char*source)
2017 if(dict_lookup(&outlines, name))
2018 syntaxerror("outline %s defined twice", name);
2020 outline_t* outline;
2022 drawer_t draw;
2023 SHAPE* shape;
2024 SHAPE2* shape2;
2025 SRECT bounds;
2027 //swf_Shape10DrawerInit(&draw, 0);
2028 swf_Shape11DrawerInit(&draw, 0);
2030 draw_string(&draw, source);
2031 draw.finish(&draw);
2032 shape = swf_ShapeDrawerToShape(&draw);
2033 bounds = swf_ShapeDrawerGetBBox(&draw);
2034 draw.dealloc(&draw);
2036 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
2037 outline->shape = shape;
2038 outline->bbox = bounds;
2040 dict_put(&outlines, name, outline);
2043 int s_playsound(const char*name, int loops, int nomultiple, int stop)
2045 sound_t* sound;
2046 SOUNDINFO info;
2047 if(!name)
2048 return 0;
2049 sound = dict_lookup(&sounds, name);
2050 if(!sound)
2051 return 0;
2053 tag = swf_InsertTag(tag, ST_STARTSOUND);
2054 swf_SetU16(tag, sound->id); //id
2055 memset(&info, 0, sizeof(info));
2056 info.stop = stop;
2057 info.loops = loops;
2058 info.nomultiple = nomultiple;
2059 swf_SetSoundInfo(tag, &info);
2060 return 1;
2063 void s_includeswf(const char*name, const char*filename, const char*as3name)
2065 int f;
2066 SWF swf;
2067 TAG* ftag;
2068 SRECT r;
2069 TAG* s;
2070 int level = 0;
2071 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
2072 f = open(filename,O_RDONLY|O_BINARY);
2073 if(f<0) {
2074 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
2075 s_box(name, 0, 0, black, 20, 0);
2076 return;
2078 if(swf_ReadSWF(f,&swf)<0) {
2079 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
2080 s_box(name, 0, 0, black, 20, 0);
2081 return;
2083 close(f);
2085 /* FIXME: The following sets the bounding Box for the character.
2086 It is wrong for two reasons:
2087 a) It may be too small (in case objects in the movie clip at the borders)
2088 b) it may be too big (because the poor movie never got autocropped)
2090 r = swf.movieSize;
2092 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2093 swf_SetU16(tag, id);
2094 swf_SetU16(tag, swf.frameCount);
2096 swf_Relocate(&swf, idmap);
2098 ftag = swf.firstTag;
2099 level = 1;
2100 while(ftag) {
2101 int t;
2102 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2103 if(cutout[t] == ftag->id) {
2104 ftag = ftag->next;
2105 continue;
2107 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2108 level++;
2109 if(ftag->id == ST_END)
2110 level--;
2111 if(!level)
2112 break;
2114 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2115 /* We simply dump all tags right after the sprite
2116 header, relying on the fact that swf_OptimizeTagOrder() will
2117 sort things out for us later.
2118 We also rely on the fact that the imported SWF is well-formed.
2120 tag = swf_InsertTag(tag, ftag->id);
2121 swf_SetBlock(tag, ftag->data, ftag->len);
2124 ftag = ftag->next;
2126 if(!ftag)
2127 syntaxerror("Included file %s contains errors", filename);
2128 tag = swf_InsertTag(tag, ST_END);
2130 swf_FreeTags(&swf);
2132 s_addcharacter(name, id, tag, r);
2134 if(*as3name) {
2135 tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
2136 swf_SetU16(tag, 1);
2137 swf_SetU16(tag, id);
2138 swf_SetString(tag, as3name);
2140 incrementid();
2142 SRECT s_getCharBBox(const char*name)
2144 character_t* c = dict_lookup(&characters, name);
2145 if(!c) syntaxerror("character '%s' unknown(2)", name);
2146 return c->size;
2148 SRECT s_getInstanceBBox(const char*name)
2150 instance_t * i = dict_lookup(&instances, name);
2151 character_t * c;
2152 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2153 c = i->character;
2154 if(!c) syntaxerror("internal error(5)");
2155 return c->size;
2157 void s_getParameters(const char*name, parameters_t* p)
2159 instance_t * i = dict_lookup(&instances, name);
2160 if(!i)
2161 syntaxerror("instance '%s' unknown(10)", name);
2162 if(change_sets_all)
2163 readParameters(i->history, p, currentframe);
2164 else
2165 *p = i->parameters;
2168 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2170 history_begin(i->history, "x", currentframe, tag, p->x);
2171 history_begin(i->history, "y", currentframe, tag, p->y);
2172 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2173 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2174 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2175 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2176 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2177 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2178 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2179 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2180 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2181 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2182 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2183 history_begin(i->history, "shear", currentframe, tag, p->shear);
2184 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2185 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2186 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2187 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2188 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2189 history_beginFilter(i->history, currentframe, tag, p->filters);
2190 history_begin(i->history, "flags", currentframe, tag, 0);
2193 void s_startclip(const char*instance, const char*character, parameters_t p)
2195 character_t* c = dict_lookup(&characters, character);
2196 instance_t* i;
2197 MATRIX m;
2198 if(!c) {
2199 syntaxerror("character %s not known", character);
2201 i = s_addinstance(instance, c, currentdepth);
2202 i->parameters = p;
2203 m = s_instancepos(i->character->size, &p);
2205 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2206 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2207 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2209 stack[stackpos].tag = tag;
2210 stack[stackpos].type = 2;
2211 stackpos++;
2213 setStartparameters(i, &p, tag);
2214 currentdepth++;
2216 void s_endClip()
2218 SWFPLACEOBJECT p;
2219 stackpos--;
2220 swf_SetTagPos(stack[stackpos].tag, 0);
2221 swf_GetPlaceObject(stack[stackpos].tag, &p);
2222 p.clipdepth = currentdepth;
2223 //p.name = 0;
2224 swf_ClearTag(stack[stackpos].tag);
2225 swf_SetPlaceObject(stack[stackpos].tag, &p);
2226 currentdepth++;
2229 void s_put(const char*instance, const char*character, parameters_t p)
2231 character_t* c = dict_lookup(&characters, character);
2232 instance_t* i;
2233 MATRIX m;
2234 if(!c)
2235 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2237 i = s_addinstance(instance, c, currentdepth);
2238 i->parameters = p;
2239 m = s_instancepos(i->character->size, &p);
2241 if(p.blendmode || p.filters)
2243 if(stack[0].swf->fileVersion < 8)
2245 if(p.blendmode)
2246 warning("blendmodes only supported for flash version>=8");
2247 else
2248 warning("filters only supported for flash version>=8");
2250 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2252 else
2253 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2254 setPlacement(tag, c->id, currentdepth, m, p.noinstancename ? NULL : instance, &p, 0);
2255 setStartparameters(i, &p, tag);
2256 currentdepth++;
2259 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2261 if(p.set & SF_X)
2262 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2263 if(p.set & SF_Y)
2264 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2265 if(p.set & SF_SCALEX)
2266 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2267 if(p.set & SF_SCALEY)
2268 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2269 if(p.set & SF_CX_R)
2271 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2272 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2274 if(p.set & SF_CX_G)
2276 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2277 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2279 if(p.set & SF_CX_B)
2281 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2282 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2284 if(p.set & SF_CX_A)
2286 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2287 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2289 if(p.set & SF_ROTATE)
2290 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2291 if(p.set & SF_SHEAR)
2292 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2293 if(p.set & SF_PIVOT)
2295 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2296 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2298 if(p.set & SF_PIN)
2300 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2301 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2303 if(p.set & SF_BLEND)
2304 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2305 if(p.set & SF_FILTER)
2306 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2309 void s_jump(const char* instance, parameters_t p)
2311 instance_t* i = dict_lookup(&instances, instance);
2312 if(!i)
2313 syntaxerror("instance %s not known", instance);
2314 recordChanges(i->history, p, CF_JUMP, 0);
2317 void s_change(const char*instance, parameters_t p, interpolation_t* inter)
2319 instance_t* i = dict_lookup(&instances, instance);
2320 if(!i)
2321 syntaxerror("instance %s not known", instance);
2322 recordChanges(i->history, p, CF_CHANGE, inter);
2325 void s_sweep(const char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2327 instance_t* i = dict_lookup(&instances, instance);
2328 if(!i)
2329 syntaxerror("instance %s not known", instance);
2330 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2333 void s_toggle(const char* instance, U16 flagsOn, U16 flagsOff)
2335 instance_t* i = dict_lookup(&instances, instance);
2336 if(!i)
2337 syntaxerror("instance %s not known", instance);
2338 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2339 flags |= flagsOn;
2340 flags &= flagsOff;
2341 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2344 void s_delinstance(const char*instance)
2346 instance_t* i = dict_lookup(&instances, instance);
2347 if(!i)
2348 syntaxerror("instance %s not known", instance);
2349 writeInstance(i);
2350 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2351 swf_SetU16(tag, i->depth);
2352 dict_del(&instances, instance);
2353 free(i);
2356 void s_schange(const char*instance, parameters_t p, interpolation_t* inter)
2358 instance_t* i = dict_lookup(&instances, instance);
2359 if(!i)
2360 syntaxerror("instance %s not known", instance);
2361 recordChanges(i->history, p, CF_SCHANGE, inter);
2364 void s_end()
2366 if(!stackpos)
2367 syntaxerror(".end unexpected");
2368 switch (stack[stackpos-1].type)
2370 case 0:
2371 s_endSWF();
2372 break;
2373 case 1:
2374 s_endSprite();
2375 break;
2376 case 2:
2377 s_endClip();
2378 break;
2379 case 3:
2380 s_endButton();
2381 break;
2382 default:
2383 syntaxerror("internal error 1");
2387 // ------------------------------------------------------------------------
2389 typedef int command_func_t(map_t*args);
2391 SRECT parseBox(const char*str)
2393 SRECT r = {0,0,0,0};
2394 float xmin, xmax, ymin, ymax;
2395 char*x = strchr(str, 'x');
2396 char*d1=0,*d2=0;
2397 if(!strcmp(str, "autocrop")) {
2398 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2399 return r;
2401 if(!x) goto error;
2402 d1 = strchr(x+1, ':');
2403 if(d1)
2404 d2 = strchr(d1+1, ':');
2405 if(!d1) {
2406 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2407 goto error;
2408 xmin = ymin = 0;
2410 else if(d1 && !d2) {
2411 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2412 goto error;
2413 xmax += xmin;
2414 ymin = 0;
2416 else {
2417 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2418 goto error;
2419 xmax += xmin;
2420 ymax += ymin;
2422 r.xmin = (SCOORD)(xmin*20);
2423 r.ymin = (SCOORD)(ymin*20);
2424 r.xmax = (SCOORD)(xmax*20);
2425 r.ymax = (SCOORD)(ymax*20);
2426 return r;
2427 error:
2428 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2429 return r;
2431 float parseFloat(const char*str)
2433 return atof(str);
2435 int parseInt(const char*str)
2437 int t;
2438 int l=strlen(str);
2439 int s=0;
2440 if(str[0]=='+' || str[0]=='-')
2441 s++;
2443 for(t=s;t<l;t++)
2444 if(str[t]<'0' || str[t]>'9')
2445 syntaxerror("Not an Integer: \"%s\"", str);
2446 return atoi(str);
2448 static double parseRawTwip(const char*str)
2450 char*dot;
2451 int sign=1;
2452 if(str[0]=='+' || str[0]=='-') {
2453 if(str[0]=='-')
2454 sign = -1;
2455 str++;
2457 dot = strchr(str, '.');
2458 if(!dot) {
2459 int l=strlen(str);
2460 int t;
2461 return sign*parseInt(str);
2462 } else {
2463 char* old = strdup(str);
2464 int l=strlen(dot+1);
2465 const char*s;
2466 *dot++ = 0;
2467 for(s=str;s<dot-1;s++) {
2468 if(*s<'0' || *s>'9')
2470 free(old);
2471 syntaxerror("Not a coordinate: \"%s\"", str);
2474 for(s=dot;*s;s++) {
2475 if(*s<'0' || *s>'9')
2477 free(old);
2478 syntaxerror("Not a coordinate: \"%s\"", str);
2481 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2482 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2483 dot[2] = 0;
2484 l=2;
2485 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2487 free(old);
2488 if(l==0)
2489 return sign*(atoi(str));
2490 if(l==1)
2491 return sign*(atoi(str)+0.1*atoi(dot));
2492 if(l==2)
2493 return sign*(atoi(str)+0.01*atoi(dot));
2495 return 0;
2498 static dict_t defines;
2499 static int defines_initialized = 0;
2500 static mem_t define_values;
2502 static double parseNameOrTwip(const char*s)
2504 int l = 0;
2505 double v;
2506 if(defines_initialized) {
2507 l = PTR_AS_INT(dict_lookup(&defines, s));
2509 if(l) {
2510 return *(int*)&define_values.buffer[l-1];
2511 } else {
2512 return parseRawTwip(s);
2516 /* automatically generated by yiyiyacc, http://www.quiss.org/yiyiyacc/ */
2517 static double parseExpression(char*s)
2519 int chr2index[256];
2520 memset(chr2index, -1, sizeof(chr2index));
2521 chr2index['+'] = 0;
2522 chr2index['-'] = 1;
2523 chr2index['*'] = 2;
2524 chr2index['/'] = 3;
2525 chr2index['('] = 5;
2526 chr2index[')'] = 6;
2527 chr2index['\0'] = 7;
2529 int stackpos = 1;
2530 int stack[256];
2531 double values[256];
2532 stack[0]=0;
2533 values[0]=0;
2534 int accept = 18;
2535 int left[10]={11,8,8,8,8,9,9,9,10,10}; //production left side
2536 int plen[10]={1,3,2,3,1,3,3,1,1,3}; //production size
2537 int table[18][12] = {
2538 {0, 4, 0, 0, 5, 6, 0, 0, 1, 2, 3, 0},
2539 {7, 8, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0},
2540 {-4, -4, 9, 10, 0, 0, -4, -4, 0, 0, 0, 0},
2541 {-7, -7, -7, -7, 0, 0, -7, -7, 0, 0, 0, 0},
2542 {0, 0, 0, 0, 5, 6, 0, 0, 0, 11, 3, 0},
2543 {-8, -8, -8, -8, 0, 0, -8, -8, 0, 0, 0, 0},
2544 {0, 4, 0, 0, 5, 6, 0, 0, 12, 2, 3, 0},
2545 {0, 0, 0, 0, 5, 6, 0, 0, 0, 13, 3, 0},
2546 {0, 0, 0, 0, 5, 6, 0, 0, 0, 14, 3, 0},
2547 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 15, 0},
2548 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 16, 0},
2549 {-2, -2, 9, 10, 0, 0, -2, -2, 0, 0, 0, 0},
2550 {7, 8, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0},
2551 {-1, -1, 9, 10, 0, 0, -1, -1, 0, 0, 0, 0},
2552 {-3, -3, 9, 10, 0, 0, -3, -3, 0, 0, 0, 0},
2553 {-5, -5, -5, -5, 0, 0, -5, -5, 0, 0, 0, 0},
2554 {-6, -6, -6, -6, 0, 0, -6, -6, 0, 0, 0, 0},
2555 {-9, -9, -9, -9, 0, 0, -9, -9, 0, 0, 0, 0}};
2557 char*p = s;
2558 while(1) {
2559 char*pnext = p+1;
2560 int action;
2561 double value = 0;
2562 if(!stackpos) {
2563 fprintf(stderr, "Error in expression\n");
2564 return 0.0;
2567 if(chr2index[*p]<0) {
2568 action = table[stack[stackpos-1]][4];
2569 if(action>0) {
2570 while(chr2index[*pnext]<0)
2571 pnext++;
2572 char save = *pnext;
2573 *pnext = 0;
2574 value = parseNameOrTwip(p);
2575 *pnext = save;
2577 } else {
2578 action = table[stack[stackpos-1]][chr2index[*p]];
2581 if(action == accept) {
2582 return values[stack[stackpos-1]];
2583 } else if(action>0) { // shift
2584 if(stackpos>254) {
2585 fprintf(stderr, "Stack overflow while parsing expression\n");
2586 return 0.0;
2588 values[stackpos]=value;
2589 stack[stackpos++]=action;
2590 p=pnext;
2591 } else if(action<0) { // reduce
2592 stackpos-=plen[-action];
2593 stack[stackpos] = table[stack[stackpos-1]][left[-action]];
2594 switch(-action) {
2595 case 1:
2596 values[stackpos] = values[stackpos+0] + values[stackpos+2];
2597 break;
2598 case 2:
2599 values[stackpos] = 0 - values[stackpos+1];
2600 break;
2601 case 3:
2602 values[stackpos] = values[stackpos+0] - values[stackpos+2];
2603 break;
2604 case 5:
2605 values[stackpos] = values[stackpos+0] * values[stackpos+2];
2606 break;
2607 case 6:
2608 values[stackpos] = values[stackpos+0] / values[stackpos+2];
2609 break;
2610 case 9:
2611 values[stackpos] = values[stackpos+1];
2612 break;
2614 stackpos++;
2615 } else {
2616 fprintf(stderr, "Syntax error in expression\n");
2617 return 0.0;
2622 int parseTwip(const char*str)
2624 char*str2 = (char*)str;
2625 int v = (int)(parseExpression(str2)*20);
2626 return v;
2629 int parseArc(const char* str)
2631 if(!strcmp(str, "short"))
2632 return 1;
2633 if(!strcmp(str, "long"))
2634 return 0;
2635 syntaxerror("invalid value for the arc parameter: %s", str);
2636 return 1;
2639 int parseDir(const char* str)
2641 if(!strcmp(str, "clockwise"))
2642 return 1;
2643 if(!strcmp(str, "counterclockwise"))
2644 return 0;
2645 syntaxerror("invalid value for the dir parameter: %s", str);
2646 return 1;
2649 int isPoint(const char*str)
2651 if(strchr(str, '('))
2652 return 1;
2653 else
2654 return 0;
2657 SPOINT parsePoint(const char*str)
2659 SPOINT p;
2660 char tmp[80];
2661 int l = strlen(str);
2662 char*comma = strchr(str, ',');
2663 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2664 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2665 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2666 p.x = parseTwip(tmp);
2667 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2668 p.y = parseTwip(tmp);
2669 return p;
2672 int parseColor2(const char*str, RGBA*color)
2674 int l = strlen(str);
2675 int r,g,b,a;
2676 int t;
2678 struct {unsigned char r,g,b;char*name;} colors[] =
2679 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2680 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2681 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2682 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2683 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2684 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2685 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2686 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2687 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2688 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2689 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2690 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2692 a=255;r=g=b=0;
2694 if(str[0]=='#' && (l==7 || l==9)) {
2695 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2696 return 0;
2697 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2698 return 0;
2699 color->r = r; color->g = g; color->b = b; color->a = a;
2700 return 1;
2702 int len=strlen(str);
2703 int alpha = 255;
2704 if(strchr(str, '/')) {
2705 len = strchr(str, '/')-str;
2706 sscanf(str+len+1,"%02x", &alpha);
2708 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2709 if(!strncmp(str, colors[t].name, len)) {
2710 r = colors[t].r;
2711 g = colors[t].g;
2712 b = colors[t].b;
2713 a = alpha;
2714 color->r = r; color->g = g; color->b = b; color->a = a;
2715 return 1;
2717 return 0;
2720 RGBA parseColor(const char*str)
2722 RGBA c;
2723 if(!parseColor2(str, &c))
2724 syntaxerror("Expression '%s' is not a color", str);
2725 return c;
2728 typedef struct _muladd {
2729 S16 mul;
2730 S16 add;
2731 } MULADD;
2733 MULADD parseMulAdd(const char*str)
2735 float add, mul;
2736 char* str2 = (char*)malloc(strlen(str)+5);
2737 int i;
2738 MULADD m;
2739 strcpy(str2, str);
2740 strcat(str2, " 0");
2741 add = 0;
2742 mul = 1.0;
2743 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2744 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2745 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2746 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2747 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2748 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2749 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2750 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2751 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2752 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2753 else {
2754 syntaxerror("'%s' is not a valid color transform expression", str);
2756 m.add = (int)(add*256);
2757 m.mul = (int)(mul*256);
2758 free(str2);
2759 return m;
2762 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2764 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2765 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2766 MULADD r;
2767 if(a<-32768) a=-32768;
2768 if(a>32767) a=32767;
2769 if(m<-32768) m=-32768;
2770 if(m>32767) m=32767;
2771 r.add = a;
2772 r.mul = (int)m;
2773 return r;
2776 float parsePxOrPercent(const char*fontname, const char*str)
2778 int l = strlen(str);
2779 if(strchr(str, '%'))
2780 return parsePercent(str);
2781 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2782 float p = atof(str);
2783 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2785 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2786 return 0;
2789 float parsePercent(const char*str)
2791 int l = strlen(str);
2792 if(!l)
2793 return 1.0;
2794 if(str[l-1]=='%') {
2795 return atof(str)/100.0;
2797 syntaxerror("Expression '%s' is not a percentage", str);
2798 return 0;
2800 int isPercent(const char*str)
2802 return str[strlen(str)-1]=='%';
2804 int parseNewSize(const char*str, int size)
2806 if(isPercent(str))
2807 return parsePercent(str)*size;
2808 else
2809 return (int)(atof(str)*20);
2812 int isColor(char*str)
2814 RGBA c;
2815 return parseColor2(str, &c);
2818 static const char* lu(map_t* args, char*name)
2820 const char* value = map_lookup(args, name);
2821 if(!value) {
2822 map_dump(args, stdout, "");
2823 syntaxerror("internal error 2: value %s should be set", name);
2825 return value;
2828 static int c_flash(map_t*args)
2830 const char* filename = map_lookup(args, "filename");
2831 const char* compressstr = lu(args, "compress");
2832 const char* change_modestr = lu(args, "change-sets-all");
2833 const char* exportstr = lu(args, "export");
2834 SRECT bbox = parseBox(lu(args, "bbox"));
2835 int version = parseInt(lu(args, "version"));
2836 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2837 RGBA color = parseColor(lu(args, "background"));
2838 int compress = 0;
2840 if(!filename || !*filename) {
2841 /* for compatibility */
2842 filename = map_lookup(args, "name");
2843 if(!filename || !*filename) {
2844 filename = 0;
2845 } else {
2846 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2847 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2851 if(!filename || override_outputname)
2852 filename = outputname;
2854 if(!strcmp(compressstr, "default"))
2855 compress = version>=6;
2856 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2857 compress = 1;
2858 else if(!strcmp(compressstr, "no"))
2859 compress = 0;
2860 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2862 if(!strcmp(change_modestr, "yes"))
2863 change_sets_all = 1;
2864 else
2865 if(strcmp(change_modestr, "no"))
2866 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2868 do_exports=atoi(exportstr);
2869 mainclass=strdup(lu(args, "mainclass"));
2871 s_swf(filename, bbox, version, fps, compress, color);
2872 return 0;
2874 int isRelative(const char*str)
2876 return !strncmp(str, "<plus>", 6) ||
2877 !strncmp(str, "<minus>", 7);
2879 const char* getOffset(const char*str)
2881 if(!strncmp(str, "<plus>", 6))
2882 return str+6;
2883 if(!strncmp(str, "<minus>", 7))
2884 return str+7;
2885 syntaxerror("internal error (347)");
2886 return 0;
2888 int getSign(const char*str)
2890 if(!strncmp(str, "<plus>", 6))
2891 return 1;
2892 if(!strncmp(str, "<minus>", 7))
2893 return -1;
2894 syntaxerror("internal error (348)");
2895 return 0;
2898 static dict_t points;
2899 static mem_t mpoints;
2900 static int points_initialized = 0;
2902 static int c_interpolation(map_t *args)
2904 int i;
2905 const char* name = lu(args, "name");
2906 if(dict_lookup(&interpolations, name))
2907 syntaxerror("interpolation %s defined twice", name);
2909 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2910 const char* functionstr = lu(args, "function");
2911 inter->function = 0;
2912 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2913 if(!strcmp(functionstr,interpolationFunctions[i]))
2915 inter->function = i + 1;
2916 break;
2918 if(!inter->function)
2919 syntaxerror("unknown interpolation function %s", functionstr);
2920 inter->speed = parseFloat(lu(args, "speed"));
2921 inter->amplitude = parseTwip(lu(args, "amplitude"));
2922 inter->growth = parseFloat(lu(args, "growth"));
2923 inter->bounces = parseInt(lu(args, "bounces"));
2924 inter->damping = parseFloat(lu(args, "damping"));
2925 inter->slope = parseFloat(lu(args, "slope"));
2927 dict_put(&interpolations, name, inter);
2928 return 0;
2931 SPOINT getPoint(SRECT r, const char*name)
2933 int l=0;
2934 if(!strcmp(name, "center")) {
2935 SPOINT p;
2936 p.x = (r.xmin + r.xmax)/2;
2937 p.y = (r.ymin + r.ymax)/2;
2938 return p;
2940 if(!strcmp(name, "bottom-center")) {
2941 SPOINT p;
2942 p.x = (r.xmin + r.xmax)/2;
2943 p.y = r.ymax;
2944 return p;
2946 if(!strcmp(name, "top-center")) {
2947 SPOINT p;
2948 p.x = (r.xmin + r.xmax)/2;
2949 p.y = r.ymin;
2950 return p;
2952 if(!strcmp(name, "top-left")) {
2953 SPOINT p;
2954 p.x = r.xmin;
2955 p.y = r.ymin;
2956 return p;
2958 if(!strcmp(name, "top-right")) {
2959 SPOINT p;
2960 p.x = r.xmax;
2961 p.y = r.ymin;
2962 return p;
2964 if(!strcmp(name, "bottom-right")) {
2965 SPOINT p;
2966 p.x = r.xmax;
2967 p.y = r.ymax;
2968 return p;
2970 if(!strcmp(name, "bottom-left")) {
2971 SPOINT p;
2972 p.x = r.xmin;
2973 p.y = r.ymax;
2974 return p;
2976 if(!strcmp(name, "left-center")) {
2977 SPOINT p;
2978 p.x = r.xmin;
2979 p.y = (r.ymin + r.ymax)/2;
2980 return p;
2982 if(!strcmp(name, "right-center")) {
2983 SPOINT p;
2984 p.x = r.xmax;
2985 p.y = (r.ymin + r.ymax)/2;
2986 return p;
2990 if(points_initialized)
2991 l = PTR_AS_INT(dict_lookup(&points, name));
2992 if(l==0) {
2993 syntaxerror("Invalid point: \"%s\".", name);
2995 return *(SPOINT*)&mpoints.buffer[l-1];
2999 static int texture2(const char*name, const char*object, map_t*args, int errors)
3001 SPOINT pos,size;
3002 const char*xstr = map_lookup(args, "x");
3003 const char*ystr = map_lookup(args, "y");
3004 const char*widthstr = map_lookup(args, "width");
3005 const char*heightstr = map_lookup(args, "height");
3006 const char*scalestr = map_lookup(args, "scale");
3007 const char*scalexstr = map_lookup(args, "scalex");
3008 const char*scaleystr = map_lookup(args, "scaley");
3009 const char*rotatestr = map_lookup(args, "rotate");
3010 const char* shearstr = map_lookup(args, "shear");
3011 const char* radiusstr = map_lookup(args, "r");
3012 float x=0,y=0;
3013 float scalex = 1.0, scaley = 1.0;
3014 float rotate=0, shear=0;
3015 float r = 0;
3016 if(!*xstr && !*ystr) {
3017 if(errors)
3018 syntaxerror("x and y must be set");
3019 return 0;
3021 if(*scalestr && (*scalexstr || *scaleystr)) {
3022 syntaxerror("scale and scalex/scaley can't both be set");
3023 return 0;
3025 if((*widthstr || *heightstr) && *radiusstr) {
3026 syntaxerror("width/height and radius can't both be set");
3028 if(*radiusstr) {
3029 widthstr = radiusstr;
3030 heightstr = radiusstr;
3032 if(!*xstr) xstr="0";
3033 if(!*ystr) ystr="0";
3034 if(!*rotatestr) rotatestr="0";
3035 if(!*shearstr) shearstr="0";
3037 if(*scalestr) {
3038 scalex = scaley = parsePercent(scalestr);
3039 } else if(*scalexstr || *scaleystr) {
3040 if(scalexstr) scalex = parsePercent(scalexstr);
3041 if(scaleystr) scaley = parsePercent(scaleystr);
3042 } else if(*widthstr || *heightstr) {
3043 int width=0;
3044 int height=0;
3045 s_getBitmapSize(object, &width, &height);
3046 if(*widthstr)
3047 scalex = (float)parseTwip(widthstr)/(float)width;
3048 if(*heightstr)
3049 scaley = (float)parseTwip(heightstr)/(float)height;
3051 x = parseTwip(xstr);
3052 y = parseTwip(ystr);
3053 rotate = parseFloat(rotatestr);
3054 shear = parseFloat(shearstr);
3056 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
3058 return 0;
3061 static int c_texture(map_t*args)
3063 const char*name = lu(args, "instance");
3064 const char*object = lu(args, "character");
3065 return texture2(name, object, args, 1);
3068 static int c_gradient(map_t*args)
3070 const char*name = lu(args, "name");
3071 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
3072 int rotate = parseInt(lu(args, "rotate"));
3074 readToken();
3075 if(type != RAWDATA)
3076 syntaxerror("colon (:) expected");
3078 if(dict_lookup(&gradients, name))
3079 syntaxerror("gradient %s defined twice", name);
3081 s_gradient(name, text, radial, rotate);
3083 /* check whether we also have placement information,
3084 which would make this a positioned gradient.
3085 If there is placement information, texture2() will
3086 add a texture, which has priority over the gradient.
3088 texture2(name, name, args, 0);
3089 return 0;
3092 static const char* checkFiltername(map_t* args)
3094 const char* name = lu(args, "name");
3095 if(strchr(name, ','))
3096 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
3097 return name;
3100 static int c_blur(map_t*args)
3102 const char*name = checkFiltername(args);
3103 const char*blurstr = lu(args, "blur");
3104 const char*blurxstr = lu(args, "blurx");
3105 const char*blurystr = lu(args, "blury");
3106 float blurx=1.0, blury=1.0;
3107 if(blurstr[0]) {
3108 blurx = parseFloat(blurstr);
3109 blury = parseFloat(blurstr);
3111 if(blurxstr[0])
3112 blurx = parseFloat(blurxstr);
3113 if(blurystr[0])
3114 blury = parseFloat(blurystr);
3115 int passes = parseInt(lu(args, "passes"));
3116 s_blur(name, blurx, blury, passes);
3117 return 0;
3120 static int c_gradientglow(map_t*args)
3122 const char*name = checkFiltername(args);
3123 const char*gradient = lu(args, "gradient");
3124 const char*blurstr = lu(args, "blur");
3125 const char*blurxstr = lu(args, "blurx");
3126 const char*blurystr = lu(args, "blury");
3127 float blurx=1.0, blury=1.0;
3128 if(blurstr[0]) {
3129 blurx = parseFloat(blurstr);
3130 blury = parseFloat(blurstr);
3132 if(blurxstr[0])
3133 blurx = parseFloat(blurxstr);
3134 if(blurystr[0])
3135 blury = parseFloat(blurystr);
3137 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3138 float distance = parseFloat(lu(args, "distance"));
3139 float strength = parseFloat(lu(args, "strength"));
3140 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3141 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3142 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3143 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3144 int passes = parseInt(lu(args, "passes"));
3146 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3147 return 0;
3150 static int c_dropshadow(map_t*args)
3152 const char*name = checkFiltername(args);
3153 RGBA color = parseColor(lu(args, "color"));
3154 const char*blurstr = lu(args, "blur");
3155 const char*blurxstr = lu(args, "blurx");
3156 const char*blurystr = lu(args, "blury");
3157 float blurx=1.0, blury=1.0;
3158 if(blurstr[0]) {
3159 blurx = parseFloat(blurstr);
3160 blury = parseFloat(blurstr);
3162 if(blurxstr[0])
3163 blurx = parseFloat(blurxstr);
3164 if(blurystr[0])
3165 blury = parseFloat(blurystr);
3167 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3168 float distance = parseFloat(lu(args, "distance"));
3169 float strength = parseFloat(lu(args, "strength"));
3170 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3171 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3172 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3173 int passes = parseInt(lu(args, "passes"));
3175 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3176 return 0;
3179 static int c_bevel(map_t*args)
3181 const char*name = checkFiltername(args);
3182 RGBA shadow = parseColor(lu(args, "shadow"));
3183 RGBA highlight = parseColor(lu(args, "highlight"));
3184 const char*blurstr = lu(args, "blur");
3185 const char*blurxstr = lu(args, "blurx");
3186 const char*blurystr = lu(args, "blury");
3187 float blurx=1.0, blury=1.0;
3188 if(blurstr[0]) {
3189 blurx = parseFloat(blurstr);
3190 blury = parseFloat(blurstr);
3192 if(blurxstr[0])
3193 blurx = parseFloat(blurxstr);
3194 if(blurystr[0])
3195 blury = parseFloat(blurystr);
3197 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3198 float distance = parseFloat(lu(args, "distance"));
3199 float strength = parseFloat(lu(args, "strength"));
3200 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3201 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3202 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3203 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3204 int passes = parseInt(lu(args, "passes"));
3206 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3207 return 0;
3210 static int c_define(map_t*args)
3212 const char*name = lu(args, "name");
3213 const char*value = lu(args, "value");
3215 if(!defines_initialized) {
3216 dict_init(&defines, 16);
3217 mem_init(&define_values);
3218 defines_initialized = 1;
3220 int val = parseTwip(value);
3221 int pos = mem_put(&define_values, &val, sizeof(val));
3222 dict_put(&defines, name, INT_AS_PTR(pos + 1));
3223 return 0;
3225 static int c_point(map_t*args)
3227 const char*name = lu(args, "name");
3228 int pos;
3229 SPOINT p;
3230 if(!points_initialized) {
3231 dict_init(&points, 16);
3232 mem_init(&mpoints);
3233 points_initialized = 1;
3235 p.x = parseTwip(lu(args, "x"));
3236 p.y = parseTwip(lu(args, "y"));
3237 pos = mem_put(&mpoints, &p, sizeof(p));
3238 dict_put(&points, name, INT_AS_PTR(pos+1));
3239 return 0;
3241 static int c_play(map_t*args)
3243 const char*name = lu(args, "name");
3244 const char*loop = lu(args, "loop");
3245 const char*nomultiple = lu(args, "nomultiple");
3246 int nm = 0;
3247 if(!strcmp(nomultiple, "nomultiple"))
3248 nm = 1;
3249 else
3250 nm = parseInt(nomultiple);
3252 if(s_playsound(name, parseInt(loop), nm, 0)) {
3253 return 0;
3254 } else if(s_swf3action(name, "play")) {
3255 return 0;
3257 return 0;
3260 static int c_stop(map_t*args)
3262 const char*name = map_lookup(args, "name");
3264 if(s_playsound(name, 0,0,1))
3265 return 0;
3266 else if(s_swf3action(name, "stop"))
3267 return 0;
3268 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3269 return 0;
3272 static int c_nextframe(map_t*args)
3274 const char*name = lu(args, "name");
3276 if(s_swf3action(name, "nextframe")) {
3277 return 0;
3279 syntaxerror("I don't know anything about movie \"%s\"", name);
3280 return 0;
3283 static int c_previousframe(map_t*args)
3285 const char*name = lu(args, "name");
3287 if(s_swf3action(name, "previousframe")) {
3288 return 0;
3290 syntaxerror("I don't know anything about movie \"%s\"", name);
3291 return 0;
3294 static int c_movement(map_t*args, int type)
3296 const char*instance = lu(args, "name");
3298 const char* xstr="";
3299 const char* ystr="";
3300 SRECT oldbbox;
3301 parameters_t p;
3302 U16 set = 0x0000;
3304 xstr = lu(args, "x");
3305 ystr = lu(args, "y");
3307 s_getParameters(instance, &p);
3309 /* x,y position */
3310 if(xstr[0])
3312 if(isRelative(xstr))
3314 if(type == PT_PUT || type == PT_STARTCLIP)
3315 syntaxerror("relative x values not allowed for initial put or startclip");
3316 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3318 else
3320 p.x = parseTwip(xstr);
3322 set = set | SF_X;
3324 if(ystr[0])
3326 if(isRelative(ystr))
3328 if(type == PT_PUT || type == PT_STARTCLIP)
3329 syntaxerror("relative y values not allowed for initial put or startclip");
3330 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3332 else
3334 p.y = parseTwip(ystr);
3336 set = set | SF_Y;
3339 if(change_sets_all)
3340 set = SF_ALL;
3341 p.set = set;
3343 switch (type)
3345 case PT_MOVE:
3347 const char* interstr = lu(args, "interpolation");
3348 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3349 if(!inter)
3350 syntaxerror("unknown interpolation %s", interstr);
3351 s_change(instance, p, inter);
3353 break;
3354 case PT_SMOVE:
3356 const char* interstr = lu(args, "interpolation");
3357 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3358 if(!inter)
3359 syntaxerror("unknown interpolation %s", interstr);
3360 s_schange(instance, p, inter);
3362 break;
3363 case PT_SWEEP:
3365 const char* rstr = lu(args, "r");
3366 int radius = parseTwip(rstr);
3367 if(radius <= 0)
3368 syntaxerror("sweep not possible: radius must be greater than 0.");
3369 const char* dirstr = lu(args, "dir");
3370 int clockwise = parseDir(dirstr);
3371 const char* arcstr = lu(args, "arc");
3372 int short_arc = parseArc(arcstr);
3373 const char* interstr = lu(args, "interpolation");
3374 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3375 if(!inter)
3376 syntaxerror("unknown interpolation %s", interstr);
3377 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3379 break;
3381 return 0;
3384 static int c_placement(map_t*args, int type)
3386 const char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3387 const char*character = 0;
3389 const char* luminancestr = lu(args, "luminance");
3390 const char* scalestr = lu(args, "scale");
3391 const char* scalexstr = lu(args, "scalex");
3392 const char* scaleystr = lu(args, "scaley");
3393 const char* rotatestr = lu(args, "rotate");
3394 const char* shearstr = lu(args, "shear");
3395 const char* xstr="", *pivotstr="";
3396 const char* ystr="", *anglestr="";
3397 const char*above = lu(args, "above"); /*FIXME*/
3398 const char*below = lu(args, "below");
3399 const char* rstr = lu(args, "red");
3400 const char* gstr = lu(args, "green");
3401 const char* bstr = lu(args, "blue");
3402 const char* astr = lu(args, "alpha");
3403 const char* pinstr = lu(args, "pin");
3404 const char* as = map_lookup(args, "as");
3405 const char* blendmode = lu(args, "blend");
3406 const char* filterstr = lu(args, "filter");
3407 const char* noinstancenamestr = "";
3408 U8 blend;
3409 MULADD r,g,b,a;
3410 float oldwidth;
3411 float oldheight;
3412 SRECT oldbbox;
3413 MULADD luminance;
3414 parameters_t p;
3415 U16 set = 0x0000;
3417 if(type==PT_PUT)
3418 noinstancenamestr = lu(args, "noinstancename");
3420 if(type==9)
3421 { // (?) .rotate or .arcchange
3422 pivotstr = lu(args, "pivot");
3423 anglestr = lu(args, "angle");
3425 else
3427 xstr = lu(args, "x");
3428 ystr = lu(args, "y");
3431 if(luminancestr[0])
3432 luminance = parseMulAdd(luminancestr);
3433 else
3435 luminance.add = 0;
3436 luminance.mul = 256;
3439 if(scalestr[0])
3441 if(scalexstr[0]||scaleystr[0])
3442 syntaxerror("scalex/scaley and scale cannot both be set");
3443 scalexstr = scaleystr = scalestr;
3446 if(type == PT_PUT || type == PT_STARTCLIP) {
3447 // put or startclip
3448 character = lu(args, "character");
3449 parameters_clear(&p);
3450 } else if(type == PT_BUTTON) {
3451 character = lu(args, "name");
3452 parameters_clear(&p);
3453 // button's show
3454 } else {
3455 s_getParameters(instance, &p);
3458 /* noinstancename */
3459 p.noinstancename = !strcmp(noinstancenamestr, "noinstancename");
3461 /* x,y position */
3462 if(xstr[0])
3464 if(isRelative(xstr))
3466 if(type == PT_PUT || type == PT_STARTCLIP)
3467 syntaxerror("relative x values not allowed for initial put or startclip");
3468 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3470 else
3472 p.x = parseTwip(xstr);
3474 set = set | SF_X;
3476 if(ystr[0])
3478 if(isRelative(ystr))
3480 if(type == PT_PUT || type == PT_STARTCLIP)
3481 syntaxerror("relative y values not allowed for initial put or startclip");
3482 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3484 else
3486 p.y = parseTwip(ystr);
3488 set = set | SF_Y;
3491 /* scale, scalex, scaley */
3492 if(character)
3493 oldbbox = s_getCharBBox(character);
3494 else
3495 oldbbox = s_getInstanceBBox(instance);
3496 oldwidth = oldbbox.xmax - oldbbox.xmin;
3497 oldheight = oldbbox.ymax - oldbbox.ymin;
3498 if(scalexstr[0])
3500 if(oldwidth==0)
3501 p.scalex = 1.0;
3502 else
3503 if(scalexstr[0])
3504 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3505 set = set | SF_SCALEX;
3507 if(scaleystr[0])
3509 if(oldheight==0)
3510 p.scaley = 1.0;
3511 else
3512 if(scaleystr[0])
3513 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3514 set = set | SF_SCALEY;
3517 /* rotation */
3518 if(rotatestr[0])
3520 if(isRelative(rotatestr))
3521 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3522 else
3523 p.rotate = parseFloat(rotatestr);
3524 set = set | SF_ROTATE;
3527 /* shearing */
3528 if(shearstr[0])
3530 if(isRelative(shearstr))
3531 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3532 else
3533 p.shear = parseFloat(shearstr);
3534 set = set | SF_SHEAR;
3537 if(pivotstr[0])
3539 if(isPoint(pivotstr))
3540 p.pivot = parsePoint(pivotstr);
3541 else
3542 p.pivot = getPoint(oldbbox, pivotstr);
3543 set = set | SF_PIVOT;
3546 if(pinstr[0])
3548 if(isPoint(pinstr))
3549 p.pin = parsePoint(pinstr);
3550 else
3551 p.pin = getPoint(oldbbox, pinstr);
3552 set = set | SF_PIN;
3555 /* color transform */
3557 if(rstr[0] || luminancestr[0])
3559 MULADD r;
3560 if(rstr[0])
3561 r = parseMulAdd(rstr);
3562 else
3564 r.add = p.cxform.r0;
3565 r.mul = p.cxform.r1;
3567 r = mergeMulAdd(r, luminance);
3568 p.cxform.r0 = r.mul;
3569 p.cxform.r1 = r.add;
3570 set = set | SF_CX_R;
3572 if(gstr[0] || luminancestr[0])
3574 MULADD g;
3575 if(gstr[0])
3576 g = parseMulAdd(gstr);
3577 else
3579 g.add = p.cxform.g0;
3580 g.mul = p.cxform.g1;
3582 g = mergeMulAdd(g, luminance);
3583 p.cxform.g0 = g.mul;
3584 p.cxform.g1 = g.add;
3585 set = set | SF_CX_G;
3587 if(bstr[0] || luminancestr[0])
3589 MULADD b;
3590 if(bstr[0])
3591 b = parseMulAdd(bstr);
3592 else
3594 b.add = p.cxform.b0;
3595 b.mul = p.cxform.b1;
3597 b = mergeMulAdd(b, luminance);
3598 p.cxform.b0 = b.mul;
3599 p.cxform.b1 = b.add;
3600 set = set | SF_CX_B;
3602 if(astr[0])
3604 MULADD a = parseMulAdd(astr);
3605 p.cxform.a0 = a.mul;
3606 p.cxform.a1 = a.add;
3607 set = set | SF_CX_A;
3610 if(blendmode[0])
3612 int t;
3613 blend = 255;
3614 for(t = 0; blendModeNames[t]; t++)
3616 if(!strcmp(blendModeNames[t], blendmode))
3618 blend = t;
3619 break;
3622 if(blend == 255)
3624 syntaxerror("unknown blend mode: '%s'", blendmode);
3626 p.blendmode = blend;
3627 set = set | SF_BLEND;
3630 if(filterstr[0])
3632 p.filters = parseFilters((char*)filterstr);
3633 set = set | SF_FILTER;
3636 if(type == PT_CHANGE && set & (SF_X | SF_Y))
3637 warning("As of version 0.8.2 using the .change command to modify an \
3638 object's position on the stage is considered deprecated. Future \
3639 versions may consider x and y parameters for the .change command \
3640 to be illegal; please use the .move command.");
3642 if(change_sets_all)
3643 set = SF_ALL;
3644 p.set = set;
3646 switch (type)
3648 case PT_PUT:
3649 s_put(instance, character, p);
3650 break;
3651 case PT_CHANGE:
3653 const char* interstr = lu(args, "interpolation");
3654 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3655 if(!inter)
3656 syntaxerror("unknown interpolation %s", interstr);
3657 s_change(instance, p, inter);
3659 break;
3660 case PT_SCHANGE:
3662 const char* interstr = lu(args, "interpolation");
3663 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3664 if(!inter)
3665 syntaxerror("unknown interpolation %s", interstr);
3666 s_schange(instance, p, inter);
3668 break;
3669 case PT_JUMP:
3670 s_jump(instance, p);
3671 break;
3672 case PT_STARTCLIP:
3673 s_startclip(instance, character, p);
3674 break;
3675 case PT_BUTTON:
3676 if(as && as[0])
3677 s_buttonput(character, as, p);
3678 else
3679 s_buttonput(character, "shape", p);
3680 break;
3681 // default:
3683 return 0;
3685 static int c_put(map_t*args)
3687 c_placement(args, PT_PUT);
3688 return 0;
3690 static int c_change(map_t*args)
3692 if(currentframe == 0)
3693 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3694 c_placement(args, PT_CHANGE);
3695 return 0;
3697 static int c_schange(map_t*args)
3699 c_placement(args, PT_SCHANGE);
3700 return 0;
3702 static int c_move(map_t* args)
3704 c_movement(args, PT_MOVE);
3705 return 0;
3707 static int c_smove(map_t* args)
3709 c_movement(args, PT_SMOVE);
3710 return 0;
3712 static int c_sweep(map_t* args)
3714 c_movement(args, PT_SWEEP);
3715 return 0;
3717 static int c_arcchange(map_t*args)
3719 c_placement(args, 0);
3720 return 0;
3722 static int c_jump(map_t*args)
3724 c_placement(args, PT_JUMP);
3725 return 0;
3727 static int c_startclip(map_t*args)
3729 c_placement(args, PT_STARTCLIP);
3730 return 0;
3732 static int c_show(map_t*args)
3734 c_placement(args, PT_BUTTON);
3735 return 0;
3737 static int c_toggle(map_t* args)
3739 const char*instance = lu(args, "name");
3740 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3741 const char* alignstr = lu(args, "fixed_alignment");
3742 if(!strcmp(alignstr, "on"))
3743 flagsOn += IF_FIXED_ALIGNMENT;
3744 else
3745 if(!strcmp(alignstr, "off"))
3746 flagsOff -= IF_FIXED_ALIGNMENT;
3747 else
3748 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3749 s_toggle(instance, flagsOn, flagsOff);
3750 return 0;
3752 static int c_del(map_t*args)
3754 const char*instance = lu(args, "name");
3755 s_delinstance(instance);
3756 return 0;
3758 static int c_end(map_t*args)
3760 s_end();
3761 return 0;
3763 static int c_sprite(map_t*args)
3765 const char* name = lu(args, "name");
3766 const char* scalinggrid = lu(args, "scalinggrid");
3767 const char* as3name = lu(args, "as3name");
3769 if(scalinggrid && *scalinggrid) {
3770 SRECT r = parseBox(scalinggrid);
3771 s_sprite(name, &r, as3name);
3772 } else {
3773 s_sprite(name, 0, as3name);
3775 return 0;
3777 static int c_frame(map_t*args)
3779 const char*framestr = lu(args, "n");
3780 const char*cutstr = lu(args, "cut");
3782 const char*name = lu(args, "name");
3783 const char*anchor = lu(args, "anchor");
3784 char buf[40];
3786 if(!strcmp(anchor, "anchor") && !*name)
3787 name = framestr;
3789 int frame;
3790 int cut = 0;
3791 if(strcmp(cutstr, "no"))
3792 cut = 1;
3793 if(isRelative(framestr)) {
3794 frame = s_getframe();
3795 if(getSign(framestr)<0)
3796 syntaxerror("relative frame expressions must be positive");
3797 frame += parseInt(getOffset(framestr));
3799 else {
3800 frame = parseInt(framestr);
3801 if(s_getframe() >= frame
3802 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3803 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3805 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3806 return 0;
3808 static int c_primitive(map_t*args)
3810 const char*name = lu(args, "name");
3811 const char*command = lu(args, "commandname");
3812 int width=0, height=0, r=0;
3813 int linewidth = parseTwip(lu(args, "line"));
3814 const char*colorstr = lu(args, "color");
3815 RGBA color = parseColor(colorstr);
3816 const char*fillstr = lu(args, "fill");
3817 int dofill = 1;
3818 int type=0;
3819 const char* font;
3820 const char* text;
3821 const char* outline=0;
3822 RGBA fill;
3823 if(!strcmp(command, "circle"))
3824 type = 1;
3825 else if(!strcmp(command, "filled"))
3826 type = 2;
3828 if(type==0) {
3829 width = parseTwip(lu(args, "width"));
3830 height = parseTwip(lu(args, "height"));
3831 } else if(type==1) {
3832 r = parseTwip(lu(args, "r"));
3833 } else if(type==2) {
3834 outline = lu(args, "outline");
3837 if(!strcmp(fillstr, "fill"))
3838 fillstr = colorstr;
3839 if(!strcmp(fillstr, "none"))
3840 fillstr = 0;
3841 if(width<0 || height<0 || linewidth<0 || r<0)
3842 syntaxerror("values width, height, line, r must be positive");
3844 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3845 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3846 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3847 return 0;
3850 static int c_textshape(map_t*args)
3852 const char*name = lu(args, "name");
3853 const char*text = lu(args, "text");
3854 const char*font = lu(args, "font");
3855 float size = parsePxOrPercent(font, lu(args, "size"));
3857 s_textshape(name, font, size, text);
3858 return 0;
3861 static int c_swf(map_t*args)
3863 const char*name = lu(args, "name");
3864 const char*filename = lu(args, "filename");
3865 const char*command = lu(args, "commandname");
3866 const char*as3name = lu(args, "as3name");
3868 if(!strcmp(command, "shape"))
3869 warning("Please use .swf instead of .shape");
3870 s_includeswf(name, filename, as3name);
3871 return 0;
3874 static int c_font(map_t*args)
3876 const char*name = lu(args, "name");
3877 const char*filename = lu(args, "filename");
3878 s_font(name, filename);
3879 return 0;
3882 static int c_sound(map_t*args)
3884 const char*name = lu(args, "name");
3885 const char*filename = lu(args, "filename");
3886 s_sound(name, filename);
3887 return 0;
3890 static int c_text(map_t*args)
3892 const char*name = lu(args, "name");
3893 const char*text = lu(args, "text");
3894 const char*font = lu(args, "font");
3895 float size = parsePxOrPercent(font, lu(args, "size"));
3896 RGBA color = parseColor(lu(args, "color"));
3897 s_text(name, font, text, (int)(size*100), color);
3898 return 0;
3901 static int c_soundtrack(map_t*args)
3903 return 0;
3906 static int c_quicktime(map_t*args)
3908 const char*name = lu(args, "name");
3909 const char*url = lu(args, "url");
3910 s_quicktime(name, url);
3911 return 0;
3914 static int c_video(map_t*args)
3916 const char*name = lu(args, "name");
3917 int width = parseInt(lu(args, "width"));
3918 int height = parseInt(lu(args, "height"));
3919 s_video(name, width, height);
3920 return 0;
3923 static int c_image(map_t*args)
3925 const char*command = lu(args, "commandname");
3926 const char*name = lu(args, "name");
3927 const char*filename = lu(args, "filename");
3928 if(!strcmp(command,"jpeg")) {
3929 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3930 s_image(name, "jpeg", filename, quality);
3931 } else {
3932 s_image(name, "png", filename, 0);
3934 return 0;
3937 static int c_outline(map_t*args)
3939 const char*name = lu(args, "name");
3940 const char*format = lu(args, "format");
3942 readToken();
3943 if(type != RAWDATA)
3944 syntaxerror("colon (:) expected");
3946 s_outline(name, format, text);
3947 return 0;
3950 int fakechar(map_t*args)
3952 const char*name = lu(args, "name");
3953 s_box(name, 0, 0, black, 20, 0);
3954 return 0;
3957 static int c_egon(map_t*args) {return fakechar(args);}
3958 static int c_button(map_t*args) {
3959 const char*name = lu(args, "name");
3960 const char*as3name = lu(args, "as3name");
3961 s_button(name, as3name);
3962 return 0;
3964 static int current_button_flags = 0;
3965 static int c_on_press(map_t*args)
3967 const char*position = lu(args, "position");
3968 const char*action = "";
3969 if(!strcmp(position, "inside")) {
3970 current_button_flags |= BC_OVERUP_OVERDOWN;
3971 } else if(!strcmp(position, "outside")) {
3972 //current_button_flags |= BC_IDLE_OUTDOWN;
3973 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3974 } else if(!strcmp(position, "anywhere")) {
3975 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3977 readToken();
3978 if(type == RAWDATA) {
3979 action = text;
3980 s_buttonaction(current_button_flags, action);
3981 current_button_flags = 0;
3983 else
3984 pushBack();
3985 return 0;
3987 static int c_on_release(map_t*args)
3989 const char*position = lu(args, "position");
3990 const char*action = "";
3991 if(!strcmp(position, "inside")) {
3992 current_button_flags |= BC_OVERDOWN_OVERUP;
3993 } else if(!strcmp(position, "outside")) {
3994 current_button_flags |= BC_OUTDOWN_IDLE;
3995 } else if(!strcmp(position, "anywhere")) {
3996 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3998 readToken();
3999 if(type == RAWDATA) {
4000 action = text;
4001 s_buttonaction(current_button_flags, action);
4002 current_button_flags = 0;
4004 else
4005 pushBack();
4006 return 0;
4008 static int c_on_move_in(map_t*args)
4010 const char*position = lu(args, "state");
4011 const char*action = "";
4012 if(!strcmp(position, "pressed")) {
4013 current_button_flags |= BC_OUTDOWN_OVERDOWN;
4014 } else if(!strcmp(position, "not_pressed")) {
4015 current_button_flags |= BC_IDLE_OVERUP;
4016 } else if(!strcmp(position, "any")) {
4017 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
4019 readToken();
4020 if(type == RAWDATA) {
4021 action = text;
4022 s_buttonaction(current_button_flags, action);
4023 current_button_flags = 0;
4025 else
4026 pushBack();
4027 return 0;
4029 static int c_on_move_out(map_t*args)
4031 const char*position = lu(args, "state");
4032 const char*action = "";
4033 if(!strcmp(position, "pressed")) {
4034 current_button_flags |= BC_OVERDOWN_OUTDOWN;
4035 } else if(!strcmp(position, "not_pressed")) {
4036 current_button_flags |= BC_OVERUP_IDLE;
4037 } else if(!strcmp(position, "any")) {
4038 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
4040 readToken();
4041 if(type == RAWDATA) {
4042 action = text;
4043 s_buttonaction(current_button_flags, action);
4044 current_button_flags = 0;
4046 else
4047 pushBack();
4048 return 0;
4050 static int c_on_key(map_t*args)
4052 const char*key = lu(args, "key");
4053 const char*action = "";
4054 if(strlen(key)==1) {
4055 /* ascii */
4056 if(key[0]>=32) {
4057 current_button_flags |= 0x4000 + (key[0]*0x200);
4058 } else {
4059 syntaxerror("invalid character: %c"+key[0]);
4060 return 1;
4062 } else {
4063 /* TODO:
4064 <ctrl-x> = 0x200*(x-'a')
4065 esc = = 0x3600
4066 space = = 0x4000;
4068 syntaxerror("invalid key: %s",key);
4070 readToken();
4071 if(type == RAWDATA) {
4072 action = text;
4073 s_buttonaction(current_button_flags, action);
4074 current_button_flags = 0;
4076 else
4077 pushBack();
4078 return 0;
4081 static int c_edittext(map_t*args)
4083 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @autosize=0"},
4084 const char*name = lu(args, "name");
4085 const char*font = lu(args, "font");
4086 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
4087 int width = parseTwip(lu(args, "width"));
4088 int height = parseTwip(lu(args, "height"));
4089 const char*text = lu(args, "text");
4090 RGBA color = parseColor(lu(args, "color"));
4091 int maxlength = parseInt(lu(args, "maxlength"));
4092 const char*variable = lu(args, "variable");
4093 const char*passwordstr = lu(args, "password");
4094 const char*wordwrapstr = lu(args, "wordwrap");
4095 const char*multilinestr = lu(args, "multiline");
4096 const char*htmlstr = lu(args, "html");
4097 const char*noselectstr = lu(args, "noselect");
4098 const char*readonlystr = lu(args, "readonly");
4099 const char*borderstr = lu(args, "border");
4100 const char*autosizestr = lu(args, "autosize");
4101 const char*alignstr = lu(args, "align");
4102 int align = -1;
4104 int flags = 0;
4105 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
4106 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
4107 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
4108 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
4109 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
4110 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
4111 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
4112 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
4113 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
4114 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
4115 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
4116 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
4117 else syntaxerror("Unknown alignment: %s", alignstr);
4119 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
4120 return 0;
4123 static int c_morphshape(map_t*args) {return fakechar(args);}
4124 static int c_movie(map_t*args) {return fakechar(args);}
4126 static char* readfile(char*filename)
4128 FILE*fi = fopen(filename, "rb");
4129 int l;
4130 char*text;
4131 if(!fi)
4132 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
4133 fseek(fi, 0, SEEK_END);
4134 l = ftell(fi);
4135 fseek(fi, 0, SEEK_SET);
4136 text = rfx_alloc(l+1);
4137 int r = fread(text, l, 1, fi);
4138 if(r<1)
4139 syntaxerror("Couldn't read file %s: %s", filename, strerror(errno));
4140 text[l]=0;
4141 fclose(fi);
4142 return text;
4145 static int c_action(map_t*args)
4147 const char* filename = map_lookup(args, "filename");
4148 if(!filename ||!*filename) {
4149 readToken();
4150 if(type != RAWDATA) {
4151 syntaxerror("colon (:) expected");
4153 s_action(text);
4154 } else {
4155 s_action(readfile((char*)filename));
4158 return 0;
4161 static int c_initaction(map_t*args)
4163 const char* character = lu(args, "name");
4164 const char* filename = map_lookup(args, "filename");
4165 if(!filename ||!*filename) {
4166 readToken();
4167 if(type != RAWDATA) {
4168 syntaxerror("colon (:) expected");
4170 s_initaction(character, text);
4171 } else {
4172 s_initaction(character, readfile((char*)filename));
4175 return 0;
4178 static struct {
4179 char*command;
4180 command_func_t* func;
4181 char*arguments;
4182 } arguments[] =
4183 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1 @mainclass="},
4184 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
4185 // "import" type stuff
4186 {"swf", c_swf, "name filename as3name="},
4187 {"shape", c_swf, "name filename"},
4188 {"jpeg", c_image, "name filename quality=80%"},
4189 {"png", c_image, "name filename"},
4190 {"movie", c_movie, "name filename"},
4191 {"sound", c_sound, "name filename"},
4192 {"font", c_font, "name filename glyphs= @flashtype="},
4193 {"soundtrack", c_soundtrack, "filename"},
4194 {"quicktime", c_quicktime, "url"},
4195 {"video", c_video, "name width= height="},
4197 // generators of primitives
4199 {"define", c_define, "name value=0"},
4200 {"point", c_point, "name x=0 y=0"},
4201 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4202 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4203 {"outline", c_outline, "name format=simple"},
4204 {"textshape", c_textshape, "name font size=100% text"},
4206 // filters
4207 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4208 {"gradientglow", c_gradientglow, "name gradient blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 @ontop=0 passes=1"},
4209 {"dropshadow", c_dropshadow, "name color blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 passes=1"},
4210 {"bevel", c_bevel, "name shadow highlight blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 @ontop=0 passes=1"},
4212 // character generators
4213 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4214 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4215 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4217 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4218 {"text", c_text, "name text font size=100% color=white"},
4219 {"edittext", c_edittext, "name font= size=100% width height text="" color=white maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @border=0 @autosize=0 align="},
4220 {"morphshape", c_morphshape, "name start end"},
4221 {"button", c_button, "name as3name="},
4222 {"show", c_show, "name x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= as="},
4223 {"on_press", c_on_press, "position=inside"},
4224 {"on_release", c_on_release, "position=anywhere"},
4225 {"on_move_in", c_on_move_in, "state=not_pressed"},
4226 {"on_move_out", c_on_move_out, "state=not_pressed"},
4227 {"on_key", c_on_key, "key=any"},
4229 // control tags
4230 {"play", c_play, "name loop=0 @nomultiple=0"},
4231 {"stop", c_stop, "name= "},
4232 {"nextframe", c_nextframe, "name"},
4233 {"previousframe", c_previousframe, "name"},
4235 // object placement tags
4236 {"put", c_put, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= @noinstancename=0"},
4237 {"startclip", c_startclip, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= @noinstancename=0"},
4238 {"move", c_move, "name x= y= interpolation=linear"},
4239 {"smove", c_smove, "name x= y= interpolation=linear"},
4240 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4241 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4242 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4243 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4244 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4245 {"del", c_del, "name"},
4246 // virtual object placement
4247 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4248 // switching
4249 {"toggle", c_toggle, "name fixed_alignment="},
4251 // commands which start a block
4252 //startclip (see above)
4253 {"sprite", c_sprite, "name scalinggrid= as3name="},
4254 {"action", c_action, "filename="},
4255 {"initaction", c_initaction, "name filename="},
4257 {"end", c_end, ""}
4261 static map_t parseArguments(char*command, char*pattern)
4263 char*x;
4264 char*d,*e;
4266 string_t name[64];
4267 string_t value[64];
4268 int set[64];
4269 int isboolean[64];
4270 int pos;
4271 int len;
4272 int t;
4273 string_t t1,t2;
4274 map_t result;
4275 map_init(&result);
4277 string_set(&t1, "commandname");
4278 string_set(&t2, command);
4279 map_put(&result, t1, t2);
4281 if(!pattern || !*pattern)
4282 return result;
4284 x = pattern;
4286 pos = 0;
4288 if(!strncmp("<i> ", x, 3)) {
4289 readToken();
4290 if(type == COMMAND || type == RAWDATA) {
4291 pushBack();
4292 syntaxerror("character name expected");
4294 name[pos].str = "instance";
4295 name[pos].len = 8;
4296 value[pos].str = text;
4297 value[pos].len = strlen(text);
4298 set[pos] = 1;
4299 pos++;
4301 if(type == ASSIGNMENT)
4302 readToken();
4304 name[pos].str = "character";
4305 name[pos].len = 9;
4306 value[pos].str = text;
4307 value[pos].len = strlen(text);
4308 set[pos] = 1;
4309 pos++;
4311 x+=4;
4314 while(*x) {
4315 isboolean[pos] = (x[0] =='@');
4316 if(isboolean[pos])
4317 x++;
4319 d = strchr(x, ' ');
4320 e = strchr(x, '=');
4321 if(!d)
4322 d=&x[strlen(x)];
4323 set[pos] = 0;
4325 if(!e || d<e) {
4326 // no default
4327 name[pos].str = x;
4328 name[pos].len = d-x;
4329 value[pos].str = 0;
4330 value[pos].len = 0;
4331 } else {
4332 name[pos].str = x;
4333 name[pos].len = e-x;
4334 value[pos].str = e+1;
4335 value[pos].len = d-e-1;
4337 pos++;
4338 if(!*d) break;
4339 x=d+1;
4341 len = pos;
4343 /* for(t=0;t<len;t++) {
4344 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4345 isboolean[t]?"(boolean)":"");
4348 while(1) {
4349 readToken();
4350 if(type == RAWDATA || type == COMMAND) {
4351 pushBack();
4352 break;
4355 // first, search for boolean arguments
4356 for(pos=0;pos<len;pos++)
4358 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4359 set[pos] = 1;
4360 if(type == ASSIGNMENT)
4361 readToken();
4362 value[pos].str = text;
4363 value[pos].len = strlen(text);
4364 /*printf("setting boolean parameter %s (to %s)\n",
4365 strdup_n(name[pos], namelen[pos]),
4366 strdup_n(value[pos], valuelen[pos]));*/
4367 break;
4371 // second, search for normal arguments
4372 if(pos==len)
4373 for(pos=0;pos<len;pos++)
4375 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4376 (type != ASSIGNMENT && !set[pos])) {
4377 if(set[pos]) {
4378 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4380 if(type == ASSIGNMENT)
4381 readToken();
4382 set[pos] = 1;
4383 value[pos].str = text;
4384 value[pos].len = strlen(text);
4385 #if 0//def DEBUG
4386 printf("setting parameter %s (to %s)\n",
4387 strdup_n(name[pos].str, name[pos].len),
4388 strdup_n(value[pos].str, value[pos].len));
4389 #endif
4390 break;
4393 if(pos==len) {
4394 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4397 #if 0//def DEBUG
4398 for(t=0;t<len;t++) {
4399 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4401 #endif
4402 for(t=0;t<len;t++) {
4403 if(value[t].str && value[t].str[0] == '*') {
4404 //relative default- take value from some other parameter
4405 int s;
4406 for(s=0;s<len;s++) {
4407 if(value[s].len == value[t].len-1 &&
4408 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4409 value[t].str = value[s].str;
4412 if(value[t].str == 0) {
4413 pushBack();
4414 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4418 /* ok, now construct the dictionary from the parameters */
4420 for(t=0;t<len;t++)
4422 map_put(&result, name[t], value[t]);
4424 return result;
4426 static void parseArgumentsForCommand(char*command)
4428 int t;
4429 map_t args;
4430 int nr = -1;
4431 msg("<verbose> parse Command: %s (line %d)", command, line);
4433 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4434 if(!strcmp(arguments[t].command, command)) {
4436 /* ugly hack- will be removed soon (once documentation and .sc generating
4437 utilities have been changed) */
4438 if(!strcmp(command, "swf") && !stackpos) {
4439 warning("Please use .flash instead of .swf- this will be mandatory soon");
4440 command = "flash";
4441 t = 0;
4444 args = parseArguments(command, arguments[t].arguments);
4445 nr = t;
4446 break;
4449 if(nr<0)
4450 syntaxerror("command %s not known", command);
4452 #ifndef EMPTY
4453 // catch missing .flash directives at the beginning of a file
4454 if(strcmp(command, "flash") && !stackpos)
4456 syntaxerror("No movie defined- use .flash first");
4458 #endif
4460 #ifdef DEBUG
4461 printf(".%s\n", command);fflush(stdout);
4462 map_dump(&args, stdout, "\t");fflush(stdout);
4463 #endif
4465 #ifndef EMPTY
4466 (*arguments[nr].func)(&args);
4467 #else
4468 if(!strcmp(command, "action") || !strcmp(command, "initaction") ||
4469 !strcmp(command, "outline") || !strcmp(command, "gradient")) {
4470 readToken();
4471 if(type != RAWDATA) {
4472 syntaxerror("colon (:) expected");
4475 #endif
4476 map_clear(&args);
4477 return;
4481 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4482 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4483 * No syntax checking is done */
4484 static void analyseArgumentsForCommand(char*command)
4486 int t;
4487 map_t args;
4488 int nr = -1;
4489 U8* glyphs_to_include;
4490 msg("<verbose> analyse Command: %s (line %d)", command, line);
4492 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4494 if(!strcmp(arguments[t].command, command))
4496 args = parseArguments(command, arguments[t].arguments);
4497 nr = t;
4498 break;
4501 #ifdef DEBUG
4502 printf(".%s\n", command);fflush(stdout);
4503 map_dump(&args, stdout, "\t");fflush(stdout);
4504 #endif
4505 const char* name = lu(&args, "name");
4506 if(!strcmp(command, "font"))
4508 const char* fontfile = lu(&args, "filename");
4509 const char* glyphs = lu(&args, "glyphs");
4510 const char* flashtype = lu(&args, "flashtype");
4511 s_createfont(name, fontfile, glyphs, flashtype[0]);
4512 } else {
4513 SWFFONT* font = dict_lookup(&fonts, lu(&args, "font"));
4514 if(!font) {
4515 //that's ok... it might be an edittext with a system font
4516 //syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4517 } else
4518 if(font->use && !font->use->glyphs_specified) {
4519 if(!strcmp(command, "edittext"))
4521 swf_FontUseAll(font);
4522 font->use->glyphs_specified = 1;
4524 else
4525 swf_FontUseUTF8(font, (U8*)lu(&args, "text"), 0xffff);
4528 map_clear(&args);
4529 return;
4532 void skipParameters()
4535 readToken();
4536 while (type != COMMAND);
4537 pushBack();
4540 void findFontUsage()
4542 char* fontRelated = "font;text;textshape;edittext;";
4543 while(!noMoreTokens())
4545 readToken();
4546 if(type != COMMAND)
4547 syntaxerror("command expected");
4548 if(strstr(fontRelated, text))
4549 analyseArgumentsForCommand(text);
4550 else
4551 if(strcmp(text, "end"))
4552 skipParameters();
4556 void firstPass()
4558 pos = 0;
4559 id = 0;
4560 dict_init(&fonts, 16);
4561 cleanUp = &freeFontDictionary;
4562 findFontUsage();
4565 int main (int argc,char ** argv)
4567 int t;
4568 processargs(argc, argv);
4569 initLog(0,-1,0,0,-1,verbose);
4571 if(!filename) {
4572 args_callback_usage(argv[0]);
4573 exit(1);
4576 file = generateTokens(filename);
4577 if(!file) {
4578 fprintf(stderr, "parser returned error.\n");
4579 return 1;
4581 firstPass();
4582 pos=0;
4583 t=0;
4585 while(!noMoreTokens()) {
4586 readToken();
4587 if(type != COMMAND)
4588 syntaxerror("command expected");
4589 parseArgumentsForCommand(text);
4592 s_close();
4593 freeTokens(file);
4595 return 0;