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 */
29 #include "../config.h"
30 #include "../lib/rfxswf.h"
31 #include "../lib/drawer.h"
32 #include "../lib/log.h"
33 #include "../lib/args.h"
35 #include "../lib/mp3.h"
36 #include "../lib/wav.h"
38 #include "../lib/png.h"
39 #include "swfc-feedback.h"
40 #include "swfc-interpolation.h"
41 #include "swfc-history.h"
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;
51 static struct options_t options[] = {
60 int args_callback_option(char*name,char*val)
62 if(!strcmp(name, "V")) {
63 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
66 else if(!strcmp(name, "o")) {
68 override_outputname = 1;
71 else if(!strcmp(name, "O")) {
75 else if(!strcmp(name, "C")) {
79 else if(!strcmp(name, "v")) {
84 printf("Unknown option: -%s\n", name);
89 int args_callback_longoption(char*name,char*val)
91 return args_long2shortoption(options, name, val);
93 void args_callback_usage(char *name)
96 printf("Usage: %s [-o file.swf] file.sc\n", name);
98 printf("-h , --help Print short help message and exit\n");
99 printf("-V , --version Print version info and exit\n");
100 printf("-C , --cgi Output to stdout (for use in CGI environments)\n");
101 printf("-v , --verbose Increase verbosity. \n");
102 printf("-o , --output <filename> Set output file to <filename>.\n");
105 int args_callback_command(char*name,char*val)
108 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
115 static struct token_t* file;
122 static void readToken()
124 type = file[pos].type;
126 syntaxerror("unexpected end of file");
128 text = file[pos].text;
129 textlen = strlen(text);
130 line = file[pos].line;
131 column = file[pos].column;
133 //printf("---> %d(%s) %s\n", type, type_names[type], text);
136 static void pushBack()
139 if(!pos) syntaxerror("internal error 3");
144 textlen = strlen(text);
147 column = file[p].column;
150 static int noMoreTokens()
152 if(file[pos].type == END)
157 // ------------------------------ swf routines ----------------------------
161 int type; //0=swf, 1=sprite, 2=clip, 3=button
167 /* for sprites (1): */
173 dictionary_t oldinstances;
178 static int stackpos = 0;
180 static dictionary_t characters;
181 static dictionary_t images;
182 static dictionary_t textures;
183 static dictionary_t outlines;
184 static dictionary_t gradients;
185 static dictionary_t filters;
186 static dictionary_t interpolations;
187 static char idmap[65536];
188 static TAG*tag = 0; //current tag
190 static int id; //current character id
191 static int currentframe; //current frame in current level
192 static SRECT currentrect; //current bounding box in current level
193 static U16 currentdepth;
194 static dictionary_t instances;
195 static dictionary_t fonts;
196 static dictionary_t sounds;
197 static dictionary_t fontUsage;
199 typedef struct _parameters {
201 float scalex, scaley;
207 U8 blendmode; //not interpolated
209 U16 set; // bits indicating wether a parameter was set in the c_placement function
212 typedef struct _character {
218 typedef struct _instance {
219 character_t*character;
221 parameters_t parameters;
226 typedef struct _outline {
231 typedef struct _gradient {
237 typedef struct _filter {
241 typedef struct _texture {
245 char* interpolationFunctions[] = {"linear", \
246 "quadIn", "quadOut", "quadInOut", \
247 "cubicIn", "cubicOut", "cubicInOut", \
248 "quartIn", "quartOut", "quartInOut", \
249 "quintIn", "quintOut", "quintInOut", \
250 "circleIn", "circleOut", "circleInOut", \
251 "exponentialIn", "exponentialOut", "exponentialInOut", \
252 "sineIn", "sineOut", "sineInOut", \
253 "elasticIn", "elasticOut", "elasticInOut", \
254 "backIn", "backOut", "backInOut", \
255 "bounceIn", "bounceOut", "bounceInOut", \
256 "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
258 static void character_init(character_t*c)
260 memset(c, 0, sizeof(character_t));
263 static character_t* character_new()
266 c = (character_t*)malloc(sizeof(character_t));
271 static void instance_init(instance_t*i)
273 memset(i, 0, sizeof(instance_t));
274 i->history = history_new();
277 static void instance_free(instance_t* i)
279 history_free(i->history);
283 static instance_t* instance_new()
286 c = (instance_t*)malloc(sizeof(instance_t));
291 static void free_instance(void* i)
293 instance_free((instance_t*)i);
296 static void free_font(void* f)
298 swf_FontFree((SWFFONT*)f);
301 static void gradient_free(GRADIENT* grad)
308 static void free_gradient(void* grad)
310 gradient_free((GRADIENT*) grad);
313 static void outline_free(outline_t* o)
315 free(o->shape->data);
320 static void free_outline(void* o)
322 outline_free((outline_t*)o);
325 static void freeDictionaries()
327 dictionary_free_all(&instances, free_instance);
328 dictionary_free_all(&characters, free);
329 dictionary_free_all(&images, free);
330 dictionary_free_all(&textures, free);
331 dictionary_free_all(&outlines, free_outline);
332 dictionary_free_all(&gradients, free_gradient);
333 dictionary_free_all(&filters, free);
334 dictionary_free_all(&fonts, free_font);
335 dictionary_free_all(&sounds, free);
336 dictionary_free_all(&interpolations, free);
339 static void freeFontDictionary()
341 dictionary_free_all(&fonts, free_font);
344 static void incrementid()
348 syntaxerror("Out of character ids.");
353 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
355 if(dictionary_lookup(&characters, name))
356 syntaxerror("character %s defined twice", name);
357 character_t* c = character_new();
359 c->definingTag = ctag;
362 dictionary_put2(&characters, name, c);
364 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
366 swf_SetString(tag, name);
367 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
370 swf_SetString(tag, name);
372 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
374 if(dictionary_lookup(&images, name))
375 syntaxerror("image %s defined twice", name);
377 character_t* c = character_new();
378 c->definingTag = ctag;
381 dictionary_put2(&images, name, c);
383 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
385 if(dictionary_lookup(&instances, name))
386 syntaxerror("object %s defined twice", name);
387 instance_t* i = instance_new();
390 //swf_GetMatrix(0, &i->matrix);
391 dictionary_put2(&instances, name, i);
395 static void parameters_clear(parameters_t*p)
398 p->scalex = 1.0; p->scaley = 1.0;
401 p->pivot.x = 0; p->pivot.y = 0;
406 swf_GetCXForm(0, &p->cxform, 1);
409 static void makeMatrix(MATRIX*m, parameters_t*p)
418 sx = p->scalex*cos(p->rotate/360*2*M_PI);
419 r1 = -p->scalex*sin(p->rotate/360*2*M_PI)+sx*p->shear;
420 r0 = p->scaley*sin(p->rotate/360*2*M_PI);
421 sy = p->scaley*cos(p->rotate/360*2*M_PI)+r0*p->shear;
423 m->sx = (int)(sx*65536+0.5);
424 m->r1 = (int)(r1*65536+0.5);
425 m->r0 = (int)(r0*65536+0.5);
426 m->sy = (int)(sy*65536+0.5);
430 h = swf_TurnPoint(p->pin, m);
435 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
440 r = swf_TurnRect(rect, &m);
441 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
442 currentrect.xmax == 0 && currentrect.ymax == 0)
445 swf_ExpandRect2(¤trect, &r);
451 interpolation_t* new;
452 new = (interpolation_t*)malloc(sizeof(interpolation_t));
453 new->function = IF_LINEAR;
454 dictionary_put2(&interpolations, "linear", new);
456 new = (interpolation_t*)malloc(sizeof(interpolation_t));
457 new->function = IF_QUAD_IN;
458 dictionary_put2(&interpolations, "quadIn", new);
459 new = (interpolation_t*)malloc(sizeof(interpolation_t));
460 new->function = IF_QUAD_OUT;
461 dictionary_put2(&interpolations, "quadOut", new);
462 new = (interpolation_t*)malloc(sizeof(interpolation_t));
463 new->function = IF_QUAD_IN_OUT;
464 dictionary_put2(&interpolations, "quadInOut", new);
466 new = (interpolation_t*)malloc(sizeof(interpolation_t));
467 new->function = IF_CUBIC_IN;
468 dictionary_put2(&interpolations, "cubicIn", new);
469 new = (interpolation_t*)malloc(sizeof(interpolation_t));
470 new->function = IF_CUBIC_OUT;
471 dictionary_put2(&interpolations, "cubicOut", new);
472 new = (interpolation_t*)malloc(sizeof(interpolation_t));
473 new->function = IF_CUBIC_IN_OUT;
474 dictionary_put2(&interpolations, "cubicInOut", new);
476 new = (interpolation_t*)malloc(sizeof(interpolation_t));
477 new->function = IF_QUART_IN;
478 dictionary_put2(&interpolations, "quartIn", new);
479 new = (interpolation_t*)malloc(sizeof(interpolation_t));
480 new->function = IF_QUART_OUT;
481 dictionary_put2(&interpolations, "quartOut", new);
482 new = (interpolation_t*)malloc(sizeof(interpolation_t));
483 new->function = IF_QUART_IN_OUT;
484 dictionary_put2(&interpolations, "quartInOut", new);
486 new = (interpolation_t*)malloc(sizeof(interpolation_t));
487 new->function = IF_QUINT_IN;
488 dictionary_put2(&interpolations, "quintIn", new);
489 new = (interpolation_t*)malloc(sizeof(interpolation_t));
490 new->function = IF_QUINT_OUT;
491 dictionary_put2(&interpolations, "quintOut", new);
492 new = (interpolation_t*)malloc(sizeof(interpolation_t));
493 new->function = IF_QUINT_IN_OUT;
494 dictionary_put2(&interpolations, "quintInOut", new);
496 new = (interpolation_t*)malloc(sizeof(interpolation_t));
497 new->function = IF_CIRCLE_IN;
498 dictionary_put2(&interpolations, "circleIn", new);
499 new = (interpolation_t*)malloc(sizeof(interpolation_t));
500 new->function = IF_CIRCLE_OUT;
501 dictionary_put2(&interpolations, "circleOut", new);
502 new = (interpolation_t*)malloc(sizeof(interpolation_t));
503 new->function = IF_CIRCLE_IN_OUT;
504 dictionary_put2(&interpolations, "circleInOut", new);
506 new = (interpolation_t*)malloc(sizeof(interpolation_t));
507 new->function = IF_EXPONENTIAL_IN;
508 dictionary_put2(&interpolations, "exponentialIn", new);
509 new = (interpolation_t*)malloc(sizeof(interpolation_t));
510 new->function = IF_EXPONENTIAL_OUT;
511 dictionary_put2(&interpolations, "exponentialOut", new);
512 new = (interpolation_t*)malloc(sizeof(interpolation_t));
513 new->function = IF_EXPONENTIAL_IN_OUT;
514 dictionary_put2(&interpolations, "exponentialInOut", new);
516 new = (interpolation_t*)malloc(sizeof(interpolation_t));
517 new->function = IF_SINE_IN;
518 dictionary_put2(&interpolations, "sineIn", new);
519 new = (interpolation_t*)malloc(sizeof(interpolation_t));
520 new->function = IF_SINE_OUT;
521 dictionary_put2(&interpolations, "sineOut", new);
522 new = (interpolation_t*)malloc(sizeof(interpolation_t));
523 new->function = IF_SINE_IN_OUT;
524 dictionary_put2(&interpolations, "sineInOut", new);
527 memset(&c, 0, sizeof(RGBA));
528 gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
529 noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
530 noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
531 noGradient->gradient.num = 2;
532 noGradient->gradient.rgba[0] = c;
533 noGradient->gradient.ratios[0] = 0;
534 noGradient->gradient.rgba[1] = c;
535 noGradient->gradient.ratios[1] = 255;
536 noGradient->radial = 0;
537 noGradient->rotate = 0;
538 dictionary_put2(&gradients, "no_gradient", noGradient);
541 // put a no_filters entry in the filters dictionary to provoce a message when a user tries
542 // to define a no_filters filter. The real filter=no_filters case is handled in parseFilters.
543 char* dummy = (char*)malloc(2);
544 dictionary_put2(&filters, "no_filters", dummy);
545 noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
547 dictionary_put2(&filters, "no_blur", noBlur);
548 noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
550 noBevel->composite = 1;
551 dictionary_put2(&filters, "no_bevel", noBevel);
552 noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
553 noDropshadow->passes = 1;
554 noDropshadow->composite = 1;
555 dictionary_put2(&filters, "no_dropshadow", noDropshadow);
556 noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
557 noGradientGlow->passes = 1;
558 noGradientGlow->composite = 1;
559 noGradientGlow->gradient = &noGradient->gradient;
560 dictionary_put2(&filters, "no_gradientglow", noGradientGlow);
563 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
566 syntaxerror(".swf blocks can't be nested");
567 if(stackpos==sizeof(stack)/sizeof(stack[0]))
568 syntaxerror("too many levels of recursion");
570 SWF*swf = (SWF*)malloc(sizeof(SWF));
572 memset(swf, 0, sizeof(swf));
573 swf->fileVersion = version;
575 swf->frameRate = fps;
576 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
577 swf->compressed = compress;
578 swf_SetRGB(tag,&background);
580 dictionary_init(&characters);
581 dictionary_init(&images);
582 dictionary_init(&textures);
583 dictionary_init(&outlines);
584 dictionary_init(&gradients);
585 dictionary_init(&filters);
586 dictionary_init(&instances);
587 dictionary_init(&sounds);
588 dictionary_init(&interpolations);
590 cleanUp = &freeDictionaries;
592 memset(&stack[stackpos], 0, sizeof(stack[0]));
593 stack[stackpos].type = 0;
594 stack[stackpos].filename = strdup(name);
595 stack[stackpos].swf = swf;
596 stack[stackpos].oldframe = -1;
600 memset(¤trect, 0, sizeof(currentrect));
603 memset(idmap, 0, sizeof(idmap));
607 void s_sprite(char*name)
609 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
610 swf_SetU16(tag, id); //id
611 swf_SetU16(tag, 0); //frames
613 memset(&stack[stackpos], 0, sizeof(stack[0]));
614 stack[stackpos].type = 1;
615 stack[stackpos].oldframe = currentframe;
616 stack[stackpos].olddepth = currentdepth;
617 stack[stackpos].oldrect = currentrect;
618 stack[stackpos].oldinstances = instances;
619 stack[stackpos].tag = tag;
620 stack[stackpos].id = id;
621 stack[stackpos].name = strdup(name);
623 /* FIXME: those four fields should be bundled together */
624 dictionary_init(&instances);
627 memset(¤trect, 0, sizeof(currentrect));
633 typedef struct _buttonrecord
641 typedef struct _button
645 buttonrecord_t records[4];
648 static button_t mybutton;
650 void s_button(char*name)
652 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
653 swf_SetU16(tag, id); //id
654 swf_ButtonSetFlags(tag, 0); //menu=no
656 memset(&mybutton, 0, sizeof(mybutton));
658 memset(&stack[stackpos], 0, sizeof(stack[0]));
659 stack[stackpos].type = 3;
660 stack[stackpos].tag = tag;
661 stack[stackpos].id = id;
662 stack[stackpos].name = strdup(name);
663 stack[stackpos].oldrect = currentrect;
664 memset(¤trect, 0, sizeof(currentrect));
669 void s_buttonput(char*character, char*as, parameters_t p)
671 character_t* c = dictionary_lookup(&characters, character);
676 if(!stackpos || (stack[stackpos-1].type != 3)) {
677 syntaxerror(".show may only appear in .button");
680 syntaxerror("character %s not known (in .shape %s)", character, character);
682 if(mybutton.endofshapes) {
683 syntaxerror("a .do may not precede a .show", character, character);
686 m = s_instancepos(c->size, &p);
694 if(*s==',' || *s==0) {
695 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
696 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
697 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
698 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
699 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
700 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
707 static void setbuttonrecords(TAG*tag)
709 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
710 if(!mybutton.endofshapes) {
713 if(!mybutton.records[3].set) {
714 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
718 if(mybutton.records[t].set) {
719 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
722 swf_SetU8(tag,0); // end of button records
723 mybutton.endofshapes = 1;
727 void s_buttonaction(int flags, char*action)
733 setbuttonrecords(stack[stackpos-1].tag);
735 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
737 syntaxerror("Couldn't compile ActionScript");
740 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
741 swf_ActionSet(stack[stackpos-1].tag, a);
742 mybutton.nr_actions++;
747 static void setactionend(TAG*tag)
749 if(!mybutton.nr_actions) {
750 /* no actions means we didn't have an actionoffset,
751 which means we can't signal the end of the
752 buttonaction records, so, *sigh*, we have
753 to insert a dummy record */
754 swf_SetU16(tag, 0); //offset
755 swf_SetU16(tag, 0); //condition
756 swf_SetU8(tag, 0); //action
760 static void s_endButton()
763 setbuttonrecords(stack[stackpos-1].tag);
764 setactionend(stack[stackpos-1].tag);
767 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
771 tag = stack[stackpos].tag;
772 currentrect = stack[stackpos].oldrect;
774 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
775 free(stack[stackpos].name);
778 TAG* removeFromTo(TAG*from, TAG*to)
780 TAG*save = from->prev;
782 TAG*next = from->next;
790 static int parametersChange(history_t* history, int frame)
794 willChange = willChange || history_change(history, frame, "x");
795 willChange = willChange || history_change(history, frame, "y");
796 willChange = willChange || history_change(history, frame, "scalex");
797 willChange = willChange || history_change(history, frame, "scaley");
798 willChange = willChange || history_change(history, frame, "cxform.r0");
799 willChange = willChange || history_change(history, frame, "cxform.g0");
800 willChange = willChange || history_change(history, frame, "cxform.b0");
801 willChange = willChange || history_change(history, frame, "cxform.a0");
802 willChange = willChange || history_change(history, frame, "cxform.r1");
803 willChange = willChange || history_change(history, frame, "cxform.g1");
804 willChange = willChange || history_change(history, frame, "cxform.b1");
805 willChange = willChange || history_change(history, frame, "cxform.a1");
806 willChange = willChange || history_change(history, frame, "rotate");
807 willChange = willChange || history_change(history, frame, "shear");
808 willChange = willChange || history_change(history, frame, "pivot.x");
809 willChange = willChange || history_change(history, frame, "pivot.y");
810 willChange = willChange || history_change(history, frame, "pin.x");
811 willChange = willChange || history_change(history, frame, "pin.y");
812 willChange = willChange || history_change(history, frame, "blendmode");
813 willChange = willChange || history_changeFilter(history, frame);
818 static void free_filterlist(FILTERLIST* f_list)
821 for (i = 0; i < f_list->num; i++)
823 if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
824 gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
825 free(f_list->filter[i]);
830 static void readParameters(history_t* history, parameters_t* p, int frame)
832 p->x = history_value(history, frame, "x");
833 p->y = history_value(history, frame, "y");
834 p->scalex = history_value(history, frame, "scalex");
835 p->scaley = history_value(history, frame, "scaley");
836 p->cxform.r0 = history_value(history, frame, "cxform.r0");
837 p->cxform.g0 = history_value(history, frame, "cxform.g0");
838 p->cxform.b0 = history_value(history, frame, "cxform.b0");
839 p->cxform.a0 = history_value(history, frame, "cxform.a0");
840 p->cxform.r1 = history_value(history, frame, "cxform.r1");
841 p->cxform.g1 = history_value(history, frame, "cxform.g1");
842 p->cxform.b1 = history_value(history, frame, "cxform.b1");
843 p->cxform.a1 = history_value(history, frame, "cxform.a1");
844 p->rotate = history_value(history, frame, "rotate");
845 p->shear = history_value(history, frame, "shear");
846 p->pivot.x = history_value(history, frame, "pivot.x");
847 p->pivot.y = history_value(history, frame, "pivot.y");
848 p->pin.x = history_value(history, frame, "pin.x");
849 p->pin.y = history_value(history, frame, "pin.y");
850 p->blendmode = history_value(history, frame, "blendmode");
851 p->filters = history_valueFilter(history, frame);
854 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
858 swf_GetPlaceObject(NULL, &po);
862 po.cxform = p->cxform;
868 po.blendmode = p->blendmode;
871 po.filters = p->filters;
872 swf_SetPlaceObject(tag, &po);
875 static void writeInstance(instance_t* i)
879 int frame = i->history->firstFrame;
880 TAG* tag = i->history->firstTag;
881 while (frame < currentframe)
884 while (tag->id != ST_SHOWFRAME)
886 if (i->deathFrame == frame)
888 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
889 swf_SetU16(tag, i->depth);
892 if (parametersChange(i->history, frame))
894 readParameters(i->history, &p, frame);
895 m = s_instancepos(i->character->size, &p);
897 if(p.blendmode || p.filters)
898 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
900 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
901 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
903 free_filterlist(p.filters);
910 void dumpSWF(SWF*swf)
912 TAG* tag = swf->firstTag;
913 printf("vvvvvvvvvvvvvvvvvvvvv\n");
915 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
918 printf("^^^^^^^^^^^^^^^^^^^^^\n");
921 static void s_endSprite()
923 SRECT r = currentrect;
925 if(stack[stackpos].cut)
926 tag = removeFromTo(stack[stackpos].cut, tag);
930 stringarray_t* index =dictionary_index(&instances);
932 char* name = stringarray_at(index, num);
935 i = dictionary_lookup(&instances, name);
938 name = stringarray_at(index, num);
943 tag = swf_InsertTag(tag, ST_SHOWFRAME);
944 tag = swf_InsertTag(tag, ST_END);
946 tag = stack[stackpos].tag;
949 syntaxerror("internal error(7)");
950 /* TODO: before clearing, prepend "<spritename>." to names and
951 copy into old instances dict */
952 dictionary_free_all(&instances, free_instance);
954 currentframe = stack[stackpos].oldframe;
955 currentrect = stack[stackpos].oldrect;
956 currentdepth = stack[stackpos].olddepth;
957 instances = stack[stackpos].oldinstances;
959 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
960 free(stack[stackpos].name);
963 static void s_endSWF()
970 stringarray_t* index = dictionary_index(&instances);
972 char* name = stringarray_at(index, num);
975 i = dictionary_lookup(&instances, name);
978 name = stringarray_at(index, num);
981 if(stack[stackpos].cut)
982 tag = removeFromTo(stack[stackpos].cut, tag);
986 swf = stack[stackpos].swf;
987 filename = stack[stackpos].filename;
989 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
990 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
991 tag = swf_InsertTag(tag, ST_SHOWFRAME);
993 tag = swf_InsertTag(tag, ST_END);
995 swf_OptimizeTagOrder(swf);
1001 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1002 swf->movieSize = currentrect; /* "autocrop" */
1005 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1006 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1007 swf->movieSize.ymax += 20;
1008 warning("Empty bounding box for movie");
1011 if(do_cgi || !strcmp(filename, "-"))
1012 fi = fileno(stdout);
1014 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1016 syntaxerror("couldn't create output file %s", filename);
1019 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1020 else if(swf->compressed)
1021 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
1023 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1037 if(stack[stackpos-1].type == 0)
1038 syntaxerror("End of file encountered in .flash block");
1039 if(stack[stackpos-1].type == 1)
1040 syntaxerror("End of file encountered in .sprite block");
1041 if(stack[stackpos-1].type == 2)
1042 syntaxerror("End of file encountered in .clip block");
1048 return currentframe+1;
1051 void s_frame(int nr, int cut, char*name, char anchor)
1057 syntaxerror("Illegal frame number");
1058 nr--; // internally, frame 1 is frame 0
1060 for(t=currentframe;t<nr;t++) {
1061 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1062 if(t==nr-1 && name && *name) {
1063 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1064 swf_SetString(tag, name);
1066 swf_SetU8(tag, 1); //make this an anchor
1069 if(nr == 0 && currentframe == 0 && name && *name) {
1070 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1071 swf_SetString(tag, name);
1073 swf_SetU8(tag, 1); //make this an anchor
1078 syntaxerror("Can't cut, frame empty");
1080 stack[stackpos].cut = tag;
1086 int parseColor2(char*str, RGBA*color);
1088 int addFillStyle(SHAPE*s, SRECT*r, char*name)
1092 gradient_t*gradient;
1094 if(name[0] == '#') {
1095 parseColor2(name, &color);
1096 return swf_ShapeAddSolidFillStyle(s, &color);
1097 } else if ((texture = dictionary_lookup(&textures, name))) {
1098 return swf_ShapeAddFillStyle2(s, &texture->fs);
1099 } else if((image = dictionary_lookup(&images, name))) {
1101 swf_GetMatrix(0, &m);
1102 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1103 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1106 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1107 } else if ((gradient = dictionary_lookup(&gradients, name))) {
1111 swf_GetMatrix(0, &rot);
1112 ccos = cos(-gradient->rotate*2*M_PI/360);
1113 csin = sin(-gradient->rotate*2*M_PI/360);
1114 rot.sx = ccos*65536;
1115 rot.r1 = -csin*65536;
1116 rot.r0 = csin*65536;
1117 rot.sy = ccos*65536;
1118 r2 = swf_TurnRect(*r, &rot);
1119 swf_GetMatrix(0, &m);
1120 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1121 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1122 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1123 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1124 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1125 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1126 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1127 } else if (parseColor2(name, &color)) {
1128 return swf_ShapeAddSolidFillStyle(s, &color);
1130 syntaxerror("not a color/fillstyle: %s", name);
1135 RGBA black={r:0,g:0,b:0,a:0};
1136 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
1145 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1148 linewidth = linewidth>=20?linewidth-20:0;
1149 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1152 fs1 = addFillStyle(s, &r2, texture);
1155 r.xmin = r2.xmin-linewidth/2;
1156 r.ymin = r2.ymin-linewidth/2;
1157 r.xmax = r2.xmax+linewidth/2;
1158 r.ymax = r2.ymax+linewidth/2;
1159 swf_SetRect(tag,&r);
1160 swf_SetShapeHeader(tag,s);
1161 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1162 swf_ShapeSetLine(tag,s,width,0);
1163 swf_ShapeSetLine(tag,s,0,height);
1164 swf_ShapeSetLine(tag,s,-width,0);
1165 swf_ShapeSetLine(tag,s,0,-height);
1166 swf_ShapeSetEnd(tag);
1169 s_addcharacter(name, id, tag, r);
1173 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
1179 outline = dictionary_lookup(&outlines, outlinename);
1181 syntaxerror("outline %s not defined", outlinename);
1185 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1188 linewidth = linewidth>=20?linewidth-20:0;
1189 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1192 fs1 = addFillStyle(s, &r2, texture);
1195 rect.xmin = r2.xmin-linewidth/2;
1196 rect.ymin = r2.ymin-linewidth/2;
1197 rect.xmax = r2.xmax+linewidth/2;
1198 rect.ymax = r2.ymax+linewidth/2;
1200 swf_SetRect(tag,&rect);
1201 swf_SetShapeStyles(tag, s);
1202 swf_ShapeCountBits(s,0,0);
1203 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1204 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1205 swf_SetShapeBits(tag, s);
1206 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1209 s_addcharacter(name, id, tag, rect);
1213 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
1218 r2.xmin = r2.ymin = 0;
1222 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1225 linewidth = linewidth>=20?linewidth-20:0;
1226 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1229 fs1 = addFillStyle(s, &r2, texture);
1231 rect.xmin = r2.xmin-linewidth/2;
1232 rect.ymin = r2.ymin-linewidth/2;
1233 rect.xmax = r2.xmax+linewidth/2;
1234 rect.ymax = r2.ymax+linewidth/2;
1236 swf_SetRect(tag,&rect);
1237 swf_SetShapeHeader(tag,s);
1238 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1239 swf_ShapeSetCircle(tag, s, r,r,r,r);
1240 swf_ShapeSetEnd(tag);
1243 s_addcharacter(name, id, tag, rect);
1247 void s_textshape(char*name, char*fontname, float size, char*_text)
1250 U8*text = (U8*)_text;
1254 font = dictionary_lookup(&fonts, fontname);
1256 syntaxerror("font \"%s\" not known!", fontname);
1258 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1259 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1260 s_box(name, 0, 0, black, 20, 0);
1263 g = font->ascii2glyph[text[0]];
1265 outline = malloc(sizeof(outline_t));
1266 memset(outline, 0, sizeof(outline_t));
1267 outline->shape = font->glyph[g].shape;
1268 outline->bbox = font->layout->bounds[g];
1272 swf_Shape11DrawerInit(&draw, 0);
1273 swf_DrawText(&draw, font, (int)(size*100), _text);
1275 outline->shape = swf_ShapeDrawerToShape(&draw);
1276 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1277 draw.dealloc(&draw);
1280 if(dictionary_lookup(&outlines, name))
1281 syntaxerror("outline %s defined twice", name);
1282 dictionary_put2(&outlines, name, outline);
1285 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
1290 font = dictionary_lookup(&fonts, fontname);
1292 syntaxerror("font \"%s\" not known!", fontname);
1294 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1295 swf_SetU16(tag, id);
1296 if(!font->numchars) {
1297 s_box(name, 0, 0, black, 20, 0);
1300 r = swf_SetDefineText(tag, font, &color, text, size);
1302 if(stack[0].swf->fileVersion >= 8) {
1303 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1304 swf_SetU16(tag, id);
1305 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1306 swf_SetU32(tag, 0);//thickness
1307 swf_SetU32(tag, 0);//sharpness
1308 swf_SetU8(tag, 0);//reserved
1311 s_addcharacter(name, id, tag, r);
1315 void s_quicktime(char*name, char*url)
1320 memset(&r, 0, sizeof(r));
1322 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1323 swf_SetU16(tag, id);
1324 swf_SetString(tag, url);
1326 s_addcharacter(name, id, tag, r);
1330 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags, int align)
1333 EditTextLayout layout;
1336 if(fontname && *fontname) {
1337 flags |= ET_USEOUTLINES;
1338 font = dictionary_lookup(&fonts, fontname);
1340 syntaxerror("font \"%s\" not known!", fontname);
1342 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1343 swf_SetU16(tag, id);
1344 layout.align = align;
1345 layout.leftmargin = 0;
1346 layout.rightmargin = 0;
1354 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1356 s_addcharacter(name, id, tag, r);
1360 /* type: either "jpeg" or "png"
1362 void s_image(char*name, char*type, char*filename, int quality)
1364 /* an image is actually two folded: 1st bitmap, 2nd character.
1365 Both of them can be used separately */
1367 /* step 1: the bitmap */
1371 if(!strcmp(type,"jpeg")) {
1372 #ifndef HAVE_JPEGLIB
1373 warning("no jpeg support compiled in");
1374 s_box(name, 0, 0, black, 20, 0);
1377 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1378 swf_SetU16(tag, imageID);
1380 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1381 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1384 swf_GetJPEGSize(filename, &width, &height);
1391 s_addimage(name, id, tag, r);
1394 } else if(!strcmp(type,"png")) {
1396 swf_SetU16(tag, imageID);
1398 getPNG(filename, &width, &height, (unsigned char**)&data);
1401 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1404 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1405 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1406 swf_SetU16(tag, imageID);
1407 swf_SetLosslessImage(tag, data, width, height);
1414 s_addimage(name, id, tag, r);
1417 warning("image type \"%s\" not supported yet!", type);
1418 s_box(name, 0, 0, black, 20, 0);
1422 /* step 2: the character */
1423 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1424 swf_SetU16(tag, id);
1425 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1427 s_addcharacter(name, id, tag, r);
1431 void s_getBitmapSize(char*name, int*width, int*height)
1433 character_t* image = dictionary_lookup(&images, name);
1434 gradient_t* gradient = dictionary_lookup(&gradients,name);
1436 *width = image->size.xmax;
1437 *height = image->size.ymax;
1441 /* internal SWF gradient size */
1442 if(gradient->radial) {
1451 syntaxerror("No such bitmap/gradient: %s", name);
1454 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1456 if(dictionary_lookup(&textures, name))
1457 syntaxerror("texture %s defined twice", name);
1458 gradient_t* gradient = dictionary_lookup(&gradients, object);
1459 character_t* bitmap = dictionary_lookup(&images, object);
1460 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1462 FILLSTYLE*fs = &texture->fs;
1464 memset(&p, 0, sizeof(parameters_t));
1467 fs->type = FILL_TILED;
1468 fs->id_bitmap = bitmap->id;
1469 } else if(gradient) {
1470 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1471 fs->gradient = gradient->gradient;
1473 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1474 makeMatrix(&fs->m, &p);
1475 if(gradient && !gradient->radial) {
1482 p2 = swf_TurnPoint(p1, &m);
1491 dictionary_put2(&textures, name, texture);
1494 void s_font(char*name, char*filename)
1497 font = dictionary_lookup(&fonts, name);
1500 /* fix the layout. Only needed for old fonts */
1502 for(t=0;t<font->numchars;t++) {
1503 font->glyph[t].advance = 0;
1506 swf_FontCreateLayout(font);
1509 swf_FontReduce_swfc(font);
1510 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1511 swf_FontSetDefine2(tag, font);
1512 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1514 swf_SetU16(tag, id);
1515 swf_SetString(tag, name);
1522 typedef struct _sound_t
1528 void s_sound(char*name, char*filename)
1530 struct WAV wav, wav2;
1534 unsigned numsamples = 1;
1535 unsigned blocksize = 1152;
1538 if(dictionary_lookup(&sounds, name))
1539 syntaxerror("sound %s defined twice", name);
1541 if(wav_read(&wav, filename))
1544 wav_convert2mono(&wav, &wav2, 44100);
1545 samples = (U16*)wav2.data;
1546 numsamples = wav2.size/2;
1548 #ifdef WORDS_BIGENDIAN
1550 for(t=0;t<numsamples;t++)
1551 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1555 if(mp3_read(&mp3, filename))
1557 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1563 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1568 if(numsamples%blocksize != 0)
1570 // apply padding, so that block is a multiple of blocksize
1571 int numblocks = (numsamples+blocksize-1)/blocksize;
1574 numsamples2 = numblocks * blocksize;
1575 samples2 = malloc(sizeof(U16)*numsamples2);
1576 memcpy(samples2, samples, numsamples*sizeof(U16));
1577 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1578 numsamples = numsamples2;
1583 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1584 swf_SetU16(tag, id); //id
1587 swf_SetSoundDefineMP3(
1588 tag, mp3.data, mp3.size,
1595 swf_SetSoundDefine(tag, samples, numsamples);
1597 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1598 swf_SetU16(tag, id);
1599 swf_SetString(tag, name);
1600 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1602 swf_SetU16(tag, id);
1603 swf_SetString(tag, name);
1605 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1609 dictionary_put2(&sounds, name, sound);
1617 static char* gradient_getToken(const char**p)
1621 while(**p && strchr(" \t\n\r", **p)) {
1625 while(**p && !strchr(" \t\n\r", **p)) {
1628 result = malloc((*p)-start+1);
1629 memcpy(result,start,(*p)-start+1);
1630 result[(*p)-start] = 0;
1634 float parsePercent(char*str);
1635 RGBA parseColor(char*str);
1637 GRADIENT parseGradient(const char*str)
1641 const char* p = str;
1642 memset(&gradient, 0, sizeof(GRADIENT));
1643 gradient.ratios = rfx_calloc(16*sizeof(U8));
1644 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1648 char*posstr,*colorstr;
1651 posstr = gradient_getToken(&p);
1657 pos = (int)(parsePercent(posstr)*255.0);
1662 rfx_free(gradient.ratios);
1663 rfx_free(gradient.rgba);
1665 syntaxerror("Error in shape data: Color expected after %s", posstr);
1667 colorstr = gradient_getToken(&p);
1668 color = parseColor(colorstr);
1669 if(gradient.num == 16)
1671 warning("gradient record too big- max size is 16, rest ignored");
1674 gradient.ratios[gradient.num] = pos;
1675 gradient.rgba[gradient.num] = color;
1684 FILTERLIST* parseFilters(char* list)
1686 if (!strcmp(list, "no_filters"))
1689 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1691 char* f_start = list;
1695 f_end = strchr(f_start, ',');
1698 f = dictionary_lookup(&filters, f_start);
1702 syntaxerror("unknown filter %s", f_start);
1704 if (f_list->num == 8)
1706 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1709 f_list->filter[f_list->num] = f;
1714 f_start = f_end + 1;
1722 void s_gradient(char*name, const char*text, int radial, int rotate)
1724 gradient_t* gradient;
1725 gradient = malloc(sizeof(gradient_t));
1726 memset(gradient, 0, sizeof(gradient_t));
1727 gradient->gradient = parseGradient(text);
1728 gradient->radial = radial;
1729 gradient->rotate = rotate;
1731 dictionary_put2(&gradients, name, gradient);
1734 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1735 float angle, float distance, float strength, char innershadow,
1736 char knockout, char composite, char ontop, int passes)
1738 if(dictionary_lookup(&filters, name))
1739 syntaxerror("filter %s defined twice", name);
1741 gradient_t* g = dictionary_lookup(&gradients, gradient);
1743 syntaxerror("unknown gradient %s", gradient);
1747 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1748 filter->type = FILTERTYPE_GRADIENTGLOW;
1749 filter->gradient = &g->gradient;
1750 filter->blurx = blurx;
1751 filter->blury = blury;
1752 filter->strength = strength;
1753 filter->angle = angle;
1754 filter->distance = distance;
1755 filter->innershadow = innershadow;
1756 filter->knockout = knockout;
1757 filter->composite = composite;
1758 filter->ontop = ontop;
1759 filter->passes = passes;
1761 dictionary_put2(&filters, name, filter);
1764 void s_dropshadow(char*name, RGBA color, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, int passes)
1766 if(dictionary_lookup(&filters, name))
1767 syntaxerror("filter %s defined twice", name);
1770 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1771 filter->type = FILTERTYPE_DROPSHADOW;
1772 filter->color= color;
1773 filter->blurx = blurx;
1774 filter->blury = blury;
1775 filter->strength = strength;
1776 filter->angle = angle;
1777 filter->distance = distance;
1778 filter->innershadow = innershadow;
1779 filter->knockout = knockout;
1780 filter->composite = composite;
1781 filter->passes = passes;
1783 dictionary_put2(&filters, name, filter);
1786 void s_bevel(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)
1788 if(dictionary_lookup(&filters, name))
1789 syntaxerror("filter %s defined twice", name);
1792 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1793 filter->type = FILTERTYPE_BEVEL;
1794 filter->shadow = shadow;
1795 filter->highlight = highlight;
1796 filter->blurx = blurx;
1797 filter->blury = blury;
1798 filter->strength = strength;
1799 filter->angle = angle;
1800 filter->distance = distance;
1801 filter->innershadow = innershadow;
1802 filter->knockout = knockout;
1803 filter->composite = composite;
1804 filter->ontop = ontop;
1805 filter->passes = passes;
1807 dictionary_put2(&filters, name, filter);
1810 void s_blur(char*name, double blurx, double blury, int passes)
1812 if(dictionary_lookup(&filters, name))
1813 syntaxerror("filter %s defined twice", name);
1815 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1816 filter->type = FILTERTYPE_BLUR;
1817 filter->blurx = blurx;
1818 filter->blury = blury;
1819 filter->passes = passes;
1821 dictionary_put2(&filters, name, filter);
1824 void s_action(const char*text)
1827 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1831 syntaxerror("Couldn't compile ActionScript");
1834 tag = swf_InsertTag(tag, ST_DOACTION);
1836 swf_ActionSet(tag, a);
1841 void s_initaction(const char*character, const char*text)
1845 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1849 syntaxerror("Couldn't compile ActionScript");
1852 c = (character_t*)dictionary_lookup(&characters, character);
1854 tag = swf_InsertTag(tag, ST_DOINITACTION);
1855 swf_SetU16(tag, c->id);
1856 swf_ActionSet(tag, a);
1861 int s_swf3action(char*name, char*action)
1864 instance_t* object = 0;
1866 object = (instance_t*)dictionary_lookup(&instances, name);
1867 if(!object && name && *name) {
1868 /* we have a name, but couldn't find it. Abort. */
1871 a = action_SetTarget(0, name);
1872 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1873 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1874 else if(!strcmp(action, "stop")) a = action_Stop(a);
1875 else if(!strcmp(action, "play")) a = action_Play(a);
1876 a = action_SetTarget(a, "");
1879 tag = swf_InsertTag(tag, ST_DOACTION);
1880 swf_ActionSet(tag, a);
1885 void s_outline(char*name, char*format, char*source)
1887 if(dictionary_lookup(&outlines, name))
1888 syntaxerror("outline %s defined twice", name);
1897 //swf_Shape10DrawerInit(&draw, 0);
1898 swf_Shape11DrawerInit(&draw, 0);
1900 draw_string(&draw, source);
1902 shape = swf_ShapeDrawerToShape(&draw);
1903 bounds = swf_ShapeDrawerGetBBox(&draw);
1904 draw.dealloc(&draw);
1906 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1907 outline->shape = shape;
1908 outline->bbox = bounds;
1910 dictionary_put2(&outlines, name, outline);
1913 int s_playsound(char*name, int loops, int nomultiple, int stop)
1919 sound = dictionary_lookup(&sounds, name);
1923 tag = swf_InsertTag(tag, ST_STARTSOUND);
1924 swf_SetU16(tag, sound->id); //id
1925 memset(&info, 0, sizeof(info));
1928 info.nomultiple = nomultiple;
1929 swf_SetSoundInfo(tag, &info);
1933 void s_includeswf(char*name, char*filename)
1941 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1942 f = open(filename,O_RDONLY|O_BINARY);
1944 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1945 s_box(name, 0, 0, black, 20, 0);
1948 if (swf_ReadSWF(f,&swf)<0) {
1949 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1950 s_box(name, 0, 0, black, 20, 0);
1955 /* FIXME: The following sets the bounding Box for the character.
1956 It is wrong for two reasons:
1957 a) It may be too small (in case objects in the movie clip at the borders)
1958 b) it may be too big (because the poor movie never got autocropped)
1962 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1963 swf_SetU16(tag, id);
1964 swf_SetU16(tag, swf.frameCount);
1966 swf_Relocate(&swf, idmap);
1968 ftag = swf.firstTag;
1972 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1973 if(cutout[t] == ftag->id) {
1977 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1979 if(ftag->id == ST_END)
1984 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
1985 /* We simply dump all tags right after the sprite
1986 header, relying on the fact that swf_OptimizeTagOrder() will
1987 sort things out for us later.
1988 We also rely on the fact that the imported SWF is well-formed.
1990 tag = swf_InsertTag(tag, ftag->id);
1991 swf_SetBlock(tag, ftag->data, ftag->len);
1997 syntaxerror("Included file %s contains errors", filename);
1998 tag = swf_InsertTag(tag, ST_END);
2002 s_addcharacter(name, id, tag, r);
2005 SRECT s_getCharBBox(char*name)
2007 character_t* c = dictionary_lookup(&characters, name);
2008 if(!c) syntaxerror("character '%s' unknown(2)", name);
2011 SRECT s_getInstanceBBox(char*name)
2013 instance_t * i = dictionary_lookup(&instances, name);
2015 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2017 if(!c) syntaxerror("internal error(5)");
2020 void s_getParameters(char*name, parameters_t* p)
2022 instance_t * i = dictionary_lookup(&instances, name);
2024 syntaxerror("instance '%s' unknown(10)", name);
2025 if (change_sets_all)
2026 readParameters(i->history, p, currentframe);
2030 void s_startclip(char*instance, char*character, parameters_t p)
2032 character_t* c = dictionary_lookup(&characters, character);
2036 syntaxerror("character %s not known", character);
2038 i = s_addinstance(instance, c, currentdepth);
2040 m = s_instancepos(i->character->size, &p);
2042 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2043 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2044 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2046 stack[stackpos].tag = tag;
2047 stack[stackpos].type = 2;
2056 swf_SetTagPos(stack[stackpos].tag, 0);
2057 swf_GetPlaceObject(stack[stackpos].tag, &p);
2058 p.clipdepth = currentdepth;
2060 swf_ClearTag(stack[stackpos].tag);
2061 swf_SetPlaceObject(stack[stackpos].tag, &p);
2065 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2067 history_begin(i->history, "x", currentframe, tag, p->x);
2068 history_begin(i->history, "y", currentframe, tag, p->y);
2069 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2070 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2071 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2072 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2073 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2074 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2075 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2076 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2077 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2078 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2079 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2080 history_begin(i->history, "shear", currentframe, tag, p->shear);
2081 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2082 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2083 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2084 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2085 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2086 history_beginFilter(i->history, currentframe, tag, p->filters);
2089 void s_put(char*instance, char*character, parameters_t p)
2091 character_t* c = dictionary_lookup(&characters, character);
2095 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2097 i = s_addinstance(instance, c, currentdepth);
2099 m = s_instancepos(i->character->size, &p);
2101 if(p.blendmode || p.filters)
2103 if(stack[0].swf->fileVersion < 8)
2106 warning("blendmodes only supported for flash version>=8");
2108 warning("filters only supported for flash version>=8");
2110 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2113 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2114 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2115 setStartparameters(i, &p, tag);
2119 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2122 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2124 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2125 if (p.set & SF_SCALEX)
2126 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2127 if (p.set & SF_SCALEY)
2128 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2129 if (p.set & SF_CX_R)
2131 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2132 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2134 if (p.set & SF_CX_G)
2136 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2137 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2139 if (p.set & SF_CX_B)
2141 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2142 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2144 if (p.set & SF_CX_A)
2146 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2147 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2149 if (p.set & SF_ROTATE)
2150 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2151 if (p.set & SF_SHEAR)
2152 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2153 if (p.set & SF_PIVOT)
2155 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2156 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2160 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2161 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2163 if (p.set & SF_BLEND)
2164 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2165 if (p.set & SF_FILTER)
2166 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2169 void s_jump(char* instance, parameters_t p)
2171 instance_t* i = dictionary_lookup(&instances, instance);
2173 syntaxerror("instance %s not known", instance);
2174 recordChanges(i->history, p, CF_JUMP, 0);
2177 void s_change(char*instance, parameters_t p2, interpolation_t* inter)
2179 instance_t* i = dictionary_lookup(&instances, instance);
2181 syntaxerror("instance %s not known", instance);
2183 recordChanges(i->history, p2, CF_CHANGE, inter);
2186 void s_delinstance(char*instance)
2188 instance_t* i = dictionary_lookup(&instances, instance);
2190 syntaxerror("instance %s not known", instance);
2191 i->deathFrame = currentframe;
2194 void s_qchange(char*instance, parameters_t p)
2196 instance_t* i = dictionary_lookup(&instances, instance);
2198 syntaxerror("instance %s not known", instance);
2199 recordChanges(i->history, p, CF_QCHANGE, 0);
2205 syntaxerror(".end unexpected");
2206 switch (stack[stackpos-1].type)
2221 syntaxerror("internal error 1");
2225 // ------------------------------------------------------------------------
2227 typedef int command_func_t(map_t*args);
2229 SRECT parseBox(char*str)
2231 SRECT r = {0,0,0,0};
2232 float xmin, xmax, ymin, ymax;
2233 char*x = strchr(str, 'x');
2235 if(!strcmp(str, "autocrop")) {
2236 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2240 d1 = strchr(x+1, ':');
2242 d2 = strchr(d1+1, ':');
2244 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2248 else if(d1 && !d2) {
2249 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2255 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2260 r.xmin = (SCOORD)(xmin*20);
2261 r.ymin = (SCOORD)(ymin*20);
2262 r.xmax = (SCOORD)(xmax*20);
2263 r.ymax = (SCOORD)(ymax*20);
2266 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2269 float parseFloat(char*str)
2273 int parseInt(char*str)
2278 if(str[0]=='+' || str[0]=='-')
2282 if(str[t]<'0' || str[t]>'9')
2283 syntaxerror("Not an Integer: \"%s\"", str);
2286 int parseTwip(char*str)
2290 if(str[0]=='+' || str[0]=='-') {
2295 dot = strchr(str, '.');
2299 return sign*parseInt(str)*20;
2301 char* old = strdup(str);
2302 int l=strlen(dot+1);
2305 for(s=str;s<dot-1;s++)
2306 if(*s<'0' || *s>'9')
2309 syntaxerror("Not a coordinate: \"%s\"", str);
2312 if(*s<'0' || *s>'9')
2315 syntaxerror("Not a coordinate: \"%s\"", str);
2317 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2318 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2321 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2325 return sign*atoi(str)*20;
2327 return sign*atoi(str)*20+atoi(dot)*2;
2329 return sign*atoi(str)*20+atoi(dot)/5;
2334 int isPoint(char*str)
2336 if(strchr(str, '('))
2342 SPOINT parsePoint(char*str)
2346 int l = strlen(str);
2347 char*comma = strchr(str, ',');
2348 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2349 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2350 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2351 p.x = parseTwip(tmp);
2352 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2353 p.y = parseTwip(tmp);
2357 int parseColor2(char*str, RGBA*color)
2359 int l = strlen(str);
2363 struct {unsigned char r,g,b;char*name;} colors[] =
2364 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2365 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2366 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2367 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2368 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2369 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2370 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2371 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2372 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2373 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2374 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2375 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2379 if(str[0]=='#' && (l==7 || l==9)) {
2380 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2382 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2384 color->r = r; color->g = g; color->b = b; color->a = a;
2387 int len=strlen(str);
2389 if(strchr(str, '/')) {
2390 len = strchr(str, '/')-str;
2391 sscanf(str+len+1,"%02x", &alpha);
2393 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2394 if(!strncmp(str, colors[t].name, len)) {
2399 color->r = r; color->g = g; color->b = b; color->a = a;
2405 RGBA parseColor(char*str)
2408 if(!parseColor2(str, &c))
2409 syntaxerror("Expression '%s' is not a color", str);
2413 typedef struct _muladd {
2418 MULADD parseMulAdd(char*str)
2421 char* str2 = (char*)malloc(strlen(str)+5);
2428 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2429 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2430 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2431 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2432 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2433 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2434 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2435 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2436 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2437 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2439 syntaxerror("'%s' is not a valid color transform expression", str);
2441 m.add = (int)(add*256);
2442 m.mul = (int)(mul*256);
2447 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2449 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2450 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2452 if(a<-32768) a=-32768;
2453 if(a>32767) a=32767;
2454 if(m<-32768) m=-32768;
2455 if(m>32767) m=32767;
2461 float parsePxOrPercent(char*fontname, char*str)
2463 int l = strlen(str);
2464 if(strchr(str, '%'))
2465 return parsePercent(str);
2466 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2467 float p = atof(str);
2468 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2470 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2474 float parsePercent(char*str)
2476 int l = strlen(str);
2480 return atoi(str)/100.0;
2482 syntaxerror("Expression '%s' is not a percentage", str);
2485 int isPercent(char*str)
2487 return str[strlen(str)-1]=='%';
2489 int parseNewSize(char*str, int size)
2492 return parsePercent(str)*size;
2494 return (int)(atof(str)*20);
2497 int isColor(char*str)
2500 return parseColor2(str, &c);
2503 static char* lu(map_t* args, char*name)
2505 char* value = map_lookup(args, name);
2507 map_dump(args, stdout, "");
2508 syntaxerror("internal error 2: value %s should be set", name);
2513 static int c_flash(map_t*args)
2515 char* filename = map_lookup(args, "filename");
2516 char* compressstr = lu(args, "compress");
2517 char* change_modestr = lu(args, "change-sets-all");
2518 SRECT bbox = parseBox(lu(args, "bbox"));
2519 int version = parseInt(lu(args, "version"));
2520 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2521 RGBA color = parseColor(lu(args, "background"));
2524 if(!filename || !*filename) {
2525 /* for compatibility */
2526 filename = map_lookup(args, "name");
2527 if(!filename || !*filename) {
2530 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2531 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2535 if(!filename || override_outputname)
2536 filename = outputname;
2538 if(!strcmp(compressstr, "default"))
2539 compress = version>=6;
2540 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2542 else if(!strcmp(compressstr, "no"))
2544 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2546 if(!strcmp(change_modestr, "yes"))
2547 change_sets_all = 1;
2549 if(strcmp(change_modestr, "no"))
2550 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2552 s_swf(filename, bbox, version, fps, compress, color);
2555 int isRelative(char*str)
2557 return !strncmp(str, "<plus>", 6) ||
2558 !strncmp(str, "<minus>", 7);
2560 char* getOffset(char*str)
2562 if(!strncmp(str, "<plus>", 6))
2564 if(!strncmp(str, "<minus>", 7))
2566 syntaxerror("internal error (347)");
2569 int getSign(char*str)
2571 if(!strncmp(str, "<plus>", 6))
2573 if(!strncmp(str, "<minus>", 7))
2575 syntaxerror("internal error (348)");
2578 static dictionary_t points;
2579 static mem_t mpoints;
2580 int points_initialized = 0;
2582 static int c_interpolation(map_t *args)
2585 char* name = lu(args, "name");
2586 if (dictionary_lookup(&interpolations, name))
2587 syntaxerror("interpolation %s defined twice", name);
2589 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2590 char* functionstr = lu(args, "function");
2591 inter->function = 0;
2592 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2593 if (!strcmp(functionstr,interpolationFunctions[i]))
2595 inter->function = i + 1;
2598 if (!inter->function)
2599 syntaxerror("unkown interpolation function %s", functionstr);
2600 inter->speed = parseFloat(lu(args, "speed"));
2601 inter->amplitude = parseFloat(lu(args, "amplitude"));
2602 inter->growth = parseFloat(lu(args, "growth"));
2603 inter->bounces = parseInt(lu(args, "bounces"));
2604 inter->damping = parseInt(lu(args, "damping"));
2606 dictionary_put2(&interpolations, name, inter);
2610 SPOINT getPoint(SRECT r, char*name)
2613 if(!strcmp(name, "center")) {
2615 p.x = (r.xmin + r.xmax)/2;
2616 p.y = (r.ymin + r.ymax)/2;
2620 if(points_initialized)
2621 l = (int)dictionary_lookup(&points, name);
2623 syntaxerror("Invalid point: \"%s\".", name);
2626 return *(SPOINT*)&mpoints.buffer[l];
2629 static int texture2(char*name, char*object, map_t*args, int errors)
2632 char*xstr = map_lookup(args, "x");
2633 char*ystr = map_lookup(args, "y");
2634 char*widthstr = map_lookup(args, "width");
2635 char*heightstr = map_lookup(args, "height");
2636 char*scalestr = map_lookup(args, "scale");
2637 char*scalexstr = map_lookup(args, "scalex");
2638 char*scaleystr = map_lookup(args, "scaley");
2639 char*rotatestr = map_lookup(args, "rotate");
2640 char* shearstr = map_lookup(args, "shear");
2641 char* radiusstr = map_lookup(args, "r");
2643 float scalex = 1.0, scaley = 1.0;
2644 float rotate=0, shear=0;
2646 if(!*xstr && !*ystr) {
2648 syntaxerror("x and y must be set");
2651 if(*scalestr && (*scalexstr || *scaleystr)) {
2652 syntaxerror("scale and scalex/scaley can't both be set");
2655 if((*widthstr || *heightstr) && *radiusstr) {
2656 syntaxerror("width/height and radius can't both be set");
2659 widthstr = radiusstr;
2660 heightstr = radiusstr;
2662 if(!*xstr) xstr="0";
2663 if(!*ystr) ystr="0";
2664 if(!*rotatestr) rotatestr="0";
2665 if(!*shearstr) shearstr="0";
2668 scalex = scaley = parsePercent(scalestr);
2669 } else if(*scalexstr || *scaleystr) {
2670 if(scalexstr) scalex = parsePercent(scalexstr);
2671 if(scaleystr) scaley = parsePercent(scaleystr);
2672 } else if(*widthstr || *heightstr) {
2675 s_getBitmapSize(object, &width, &height);
2677 scalex = (float)parseTwip(widthstr)/(float)width;
2679 scaley = (float)parseTwip(heightstr)/(float)height;
2681 x = parseTwip(xstr);
2682 y = parseTwip(ystr);
2683 rotate = parseFloat(rotatestr);
2684 shear = parseFloat(shearstr);
2686 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2691 static int c_texture(map_t*args)
2693 char*name = lu(args, "instance");
2694 char*object = lu(args, "character");
2695 return texture2(name, object, args, 1);
2698 static int c_gradient(map_t*args)
2700 char*name = lu(args, "name");
2701 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2702 int rotate = parseInt(lu(args, "rotate"));
2706 syntaxerror("colon (:) expected");
2708 if(dictionary_lookup(&gradients, name))
2709 syntaxerror("gradient %s defined twice", name);
2711 s_gradient(name, text, radial, rotate);
2713 /* check whether we also have placement information,
2714 which would make this a positioned gradient.
2715 If there is placement information, texture2() will
2716 add a texture, which has priority over the gradient.
2718 texture2(name, name, args, 0);
2722 static char* checkFiltername(map_t* args)
2724 char*name = lu(args, "name");
2725 if (strchr(name, ','))
2726 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
2730 static int c_blur(map_t*args)
2732 char*name = checkFiltername(args);
2733 char*blurstr = lu(args, "blur");
2734 char*blurxstr = lu(args, "blurx");
2735 char*blurystr = lu(args, "blury");
2736 float blurx=1.0, blury=1.0;
2738 blurx = parseFloat(blurstr);
2739 blury = parseFloat(blurstr);
2742 blurx = parseFloat(blurxstr);
2744 blury = parseFloat(blurystr);
2745 int passes = parseInt(lu(args, "passes"));
2746 s_blur(name, blurx, blury, passes);
2750 static int c_gradientglow(map_t*args)
2752 char*name = checkFiltername(args);
2753 char*gradient = lu(args, "gradient");
2754 char*blurstr = lu(args, "blur");
2755 char*blurxstr = lu(args, "blurx");
2756 char*blurystr = lu(args, "blury");
2757 float blurx=1.0, blury=1.0;
2759 blurx = parseFloat(blurstr);
2760 blury = parseFloat(blurstr);
2763 blurx = parseFloat(blurxstr);
2765 blury = parseFloat(blurystr);
2767 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2768 float distance = parseFloat(lu(args, "distance"));
2769 float strength = parseFloat(lu(args, "strength"));
2770 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2771 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2772 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2773 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2774 int passes = parseInt(lu(args, "passes"));
2776 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2780 static int c_dropshadow(map_t*args)
2782 char*name = checkFiltername(args);
2783 RGBA color = parseColor(lu(args, "color"));
2784 char*blurstr = lu(args, "blur");
2785 char*blurxstr = lu(args, "blurx");
2786 char*blurystr = lu(args, "blury");
2787 float blurx=1.0, blury=1.0;
2789 blurx = parseFloat(blurstr);
2790 blury = parseFloat(blurstr);
2793 blurx = parseFloat(blurxstr);
2795 blury = parseFloat(blurystr);
2797 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2798 float distance = parseFloat(lu(args, "distance"));
2799 float strength = parseFloat(lu(args, "strength"));
2800 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2801 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2802 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2803 int passes = parseInt(lu(args, "passes"));
2805 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
2809 static int c_bevel(map_t*args)
2811 char*name = checkFiltername(args);
2812 RGBA shadow = parseColor(lu(args, "shadow"));
2813 RGBA highlight = parseColor(lu(args, "highlight"));
2814 char*blurstr = lu(args, "blur");
2815 char*blurxstr = lu(args, "blurx");
2816 char*blurystr = lu(args, "blury");
2817 float blurx=1.0, blury=1.0;
2819 blurx = parseFloat(blurstr);
2820 blury = parseFloat(blurstr);
2823 blurx = parseFloat(blurxstr);
2825 blury = parseFloat(blurystr);
2827 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2828 float distance = parseFloat(lu(args, "distance"));
2829 float strength = parseFloat(lu(args, "strength"));
2830 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2831 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2832 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2833 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2834 int passes = parseInt(lu(args, "passes"));
2836 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2840 static int c_point(map_t*args)
2842 char*name = lu(args, "name");
2846 if(!points_initialized) {
2847 dictionary_init(&points);
2849 points_initialized = 1;
2851 p.x = parseTwip(lu(args, "x"));
2852 p.y = parseTwip(lu(args, "y"));
2853 pos = mem_put(&mpoints, &p, sizeof(p));
2854 string_set(&s1, name);
2856 dictionary_put(&points, s1, (void*)pos);
2859 static int c_play(map_t*args)
2861 char*name = lu(args, "name");
2862 char*loop = lu(args, "loop");
2863 char*nomultiple = lu(args, "nomultiple");
2865 if(!strcmp(nomultiple, "nomultiple"))
2868 nm = parseInt(nomultiple);
2870 if(s_playsound(name, parseInt(loop), nm, 0)) {
2872 } else if(s_swf3action(name, "play")) {
2878 static int c_stop(map_t*args)
2880 char*name = map_lookup(args, "name");
2882 if(s_playsound(name, 0,0,1))
2884 else if(s_swf3action(name, "stop"))
2886 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
2890 static int c_nextframe(map_t*args)
2892 char*name = lu(args, "name");
2894 if(s_swf3action(name, "nextframe")) {
2897 syntaxerror("I don't know anything about movie \"%s\"", name);
2901 static int c_previousframe(map_t*args)
2903 char*name = lu(args, "name");
2905 if(s_swf3action(name, "previousframe")) {
2908 syntaxerror("I don't know anything about movie \"%s\"", name);
2912 static int c_placement(map_t*args, int type)
2914 char*instance = lu(args, (type==0||type==4)?"instance":"name");
2917 char* luminancestr = lu(args, "luminance");
2918 char* scalestr = lu(args, "scale");
2919 char* scalexstr = lu(args, "scalex");
2920 char* scaleystr = lu(args, "scaley");
2921 char* rotatestr = lu(args, "rotate");
2922 char* shearstr = lu(args, "shear");
2923 char* xstr="", *pivotstr="";
2924 char* ystr="", *anglestr="";
2925 char*above = lu(args, "above"); /*FIXME*/
2926 char*below = lu(args, "below");
2927 char* rstr = lu(args, "red");
2928 char* gstr = lu(args, "green");
2929 char* bstr = lu(args, "blue");
2930 char* astr = lu(args, "alpha");
2931 char* pinstr = lu(args, "pin");
2932 char* as = map_lookup(args, "as");
2933 char* blendmode = lu(args, "blend");
2934 char* filterstr = lu(args, "filter");
2945 { // (?) .rotate or .arcchange
2946 pivotstr = lu(args, "pivot");
2947 anglestr = lu(args, "angle");
2951 xstr = lu(args, "x");
2952 ystr = lu(args, "y");
2956 luminance = parseMulAdd(luminancestr);
2960 luminance.mul = 256;
2965 if(scalexstr[0]||scaleystr[0])
2966 syntaxerror("scalex/scaley and scale cannot both be set");
2967 scalexstr = scaleystr = scalestr;
2970 if(type == 0 || type == 4) {
2972 character = lu(args, "character");
2973 parameters_clear(&p);
2974 } else if (type == 5) {
2975 character = lu(args, "name");
2976 parameters_clear(&p);
2979 s_getParameters(instance, &p);
2985 if(isRelative(xstr))
2987 if(type == 0 || type == 4)
2988 syntaxerror("relative x values not allowed for initial put or startclip");
2989 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2993 p.x = parseTwip(xstr);
2999 if(isRelative(ystr))
3001 if(type == 0 || type == 4)
3002 syntaxerror("relative y values not allowed for initial put or startclip");
3003 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3007 p.y = parseTwip(ystr);
3012 /* scale, scalex, scaley */
3014 oldbbox = s_getCharBBox(character);
3016 oldbbox = s_getInstanceBBox(instance);
3017 oldwidth = oldbbox.xmax - oldbbox.xmin;
3018 oldheight = oldbbox.ymax - oldbbox.ymin;
3025 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3026 set = set | SF_SCALEX;
3034 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3035 set = set | SF_SCALEY;
3041 if(isRelative(rotatestr))
3042 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3044 p.rotate = parseFloat(rotatestr);
3045 set = set | SF_ROTATE;
3051 if(isRelative(shearstr))
3052 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3054 p.shear = parseFloat(shearstr);
3055 set = set | SF_SHEAR;
3060 if(isPoint(pivotstr))
3061 p.pivot = parsePoint(pivotstr);
3063 p.pivot = getPoint(oldbbox, pivotstr);
3064 set = set | SF_PIVOT;
3070 p.pin = parsePoint(pinstr);
3072 p.pin = getPoint(oldbbox, pinstr);
3076 /* color transform */
3078 if(rstr[0] || luminancestr[0])
3082 r = parseMulAdd(rstr);
3085 r.add = p.cxform.r0;
3086 r.mul = p.cxform.r1;
3088 r = mergeMulAdd(r, luminance);
3089 p.cxform.r0 = r.mul;
3090 p.cxform.r1 = r.add;
3091 set = set | SF_CX_R;
3093 if(gstr[0] || luminancestr[0])
3097 g = parseMulAdd(gstr);
3100 g.add = p.cxform.g0;
3101 g.mul = p.cxform.g1;
3103 g = mergeMulAdd(g, luminance);
3104 p.cxform.g0 = g.mul;
3105 p.cxform.g1 = g.add;
3106 set = set | SF_CX_G;
3108 if(bstr[0] || luminancestr[0])
3112 b = parseMulAdd(bstr);
3115 b.add = p.cxform.b0;
3116 b.mul = p.cxform.b1;
3118 b = mergeMulAdd(b, luminance);
3119 p.cxform.b0 = b.mul;
3120 p.cxform.b1 = b.add;
3121 set = set | SF_CX_B;
3125 MULADD a = parseMulAdd(astr);
3126 p.cxform.a0 = a.mul;
3127 p.cxform.a1 = a.add;
3128 set = set | SF_CX_A;
3135 for(t = 0; blendModeNames[t]; t++)
3137 if(!strcmp(blendModeNames[t], blendmode))
3145 syntaxerror("unknown blend mode: '%s'", blendmode);
3147 p.blendmode = blend;
3148 set = set | SF_BLEND;
3153 p.filters = parseFilters(filterstr);
3154 set = set | SF_FILTER;
3157 if (change_sets_all)
3164 s_put(instance, character, p);
3168 char* interstr = lu(args, "interpolation");
3169 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3171 syntaxerror("unkown interpolation %s", interstr);
3172 s_change(instance, p, inter);
3176 s_qchange(instance, p);
3179 s_jump(instance, p);
3182 s_startclip(instance, character, p);
3186 s_buttonput(character, as, p);
3188 s_buttonput(character, "shape", p);
3194 static int c_put(map_t*args)
3196 c_placement(args, 0);
3199 static int c_change(map_t*args)
3201 if (currentframe == 0)
3202 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3203 c_placement(args, 1);
3206 static int c_qchange(map_t*args)
3208 c_placement(args, 2);
3211 static int c_arcchange(map_t*args)
3213 c_placement(args, 2);
3216 static int c_jump(map_t*args)
3218 c_placement(args, 3);
3221 static int c_startclip(map_t*args)
3223 c_placement(args, 4);
3226 static int c_show(map_t*args)
3228 c_placement(args, 5);
3231 static int c_del(map_t*args)
3233 char*instance = lu(args, "name");
3234 s_delinstance(instance);
3237 static int c_end(map_t*args)
3242 static int c_sprite(map_t*args)
3244 char* name = lu(args, "name");
3248 static int c_frame(map_t*args)
3250 char*framestr = lu(args, "n");
3251 char*cutstr = lu(args, "cut");
3253 char*name = lu(args, "name");
3254 char*anchor = lu(args, "anchor");
3257 if(!strcmp(anchor, "anchor") && !*name)
3262 if(strcmp(cutstr, "no"))
3264 if(isRelative(framestr)) {
3265 frame = s_getframe();
3266 if(getSign(framestr)<0)
3267 syntaxerror("relative frame expressions must be positive");
3268 frame += parseInt(getOffset(framestr));
3271 frame = parseInt(framestr);
3272 if(s_getframe() >= frame
3273 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3274 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3276 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3279 static int c_primitive(map_t*args)
3281 char*name = lu(args, "name");
3282 char*command = lu(args, "commandname");
3283 int width=0, height=0, r=0;
3284 int linewidth = parseTwip(lu(args, "line"));
3285 char*colorstr = lu(args, "color");
3286 RGBA color = parseColor(colorstr);
3287 char*fillstr = lu(args, "fill");
3294 if(!strcmp(command, "circle"))
3296 else if(!strcmp(command, "filled"))
3300 width = parseTwip(lu(args, "width"));
3301 height = parseTwip(lu(args, "height"));
3302 } else if (type==1) {
3303 r = parseTwip(lu(args, "r"));
3304 } else if (type==2) {
3305 outline = lu(args, "outline");
3308 if(!strcmp(fillstr, "fill"))
3310 if(!strcmp(fillstr, "none"))
3312 if(width<0 || height<0 || linewidth<0 || r<0)
3313 syntaxerror("values width, height, line, r must be positive");
3315 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3316 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3317 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3321 static int c_textshape(map_t*args)
3323 char*name = lu(args, "name");
3324 char*text = lu(args, "text");
3325 char*font = lu(args, "font");
3326 float size = parsePxOrPercent(font, lu(args, "size"));
3328 s_textshape(name, font, size, text);
3332 static int c_swf(map_t*args)
3334 char*name = lu(args, "name");
3335 char*filename = lu(args, "filename");
3336 char*command = lu(args, "commandname");
3337 if(!strcmp(command, "shape"))
3338 warning("Please use .swf instead of .shape");
3339 s_includeswf(name, filename);
3343 static int c_font(map_t*args)
3345 char*name = lu(args, "name");
3346 char*filename = lu(args, "filename");
3347 s_font(name, filename);
3351 static int c_sound(map_t*args)
3353 char*name = lu(args, "name");
3354 char*filename = lu(args, "filename");
3355 s_sound(name, filename);
3359 static int c_text(map_t*args)
3361 char*name = lu(args, "name");
3362 char*text = lu(args, "text");
3363 char*font = lu(args, "font");
3364 float size = parsePxOrPercent(font, lu(args, "size"));
3365 RGBA color = parseColor(lu(args, "color"));
3366 s_text(name, font, text, (int)(size*100), color);
3370 static int c_soundtrack(map_t*args)
3375 static int c_quicktime(map_t*args)
3377 char*name = lu(args, "name");
3378 char*url = lu(args, "url");
3379 s_quicktime(name, url);
3383 static int c_image(map_t*args)
3385 char*command = lu(args, "commandname");
3386 char*name = lu(args, "name");
3387 char*filename = lu(args, "filename");
3388 if(!strcmp(command,"jpeg")) {
3389 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3390 s_image(name, "jpeg", filename, quality);
3392 s_image(name, "png", filename, 0);
3397 static int c_outline(map_t*args)
3399 char*name = lu(args, "name");
3400 char*format = lu(args, "format");
3404 syntaxerror("colon (:) expected");
3406 s_outline(name, format, text);
3410 int fakechar(map_t*args)
3412 char*name = lu(args, "name");
3413 s_box(name, 0, 0, black, 20, 0);
3417 static int c_egon(map_t*args) {return fakechar(args);}
3418 static int c_button(map_t*args) {
3419 char*name = lu(args, "name");
3423 static int current_button_flags = 0;
3424 static int c_on_press(map_t*args)
3426 char*position = lu(args, "position");
3428 if(!strcmp(position, "inside")) {
3429 current_button_flags |= BC_OVERUP_OVERDOWN;
3430 } else if(!strcmp(position, "outside")) {
3431 //current_button_flags |= BC_IDLE_OUTDOWN;
3432 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3433 } else if(!strcmp(position, "anywhere")) {
3434 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3437 if(type == RAWDATA) {
3439 s_buttonaction(current_button_flags, action);
3440 current_button_flags = 0;
3446 static int c_on_release(map_t*args)
3448 char*position = lu(args, "position");
3450 if(!strcmp(position, "inside")) {
3451 current_button_flags |= BC_OVERDOWN_OVERUP;
3452 } else if(!strcmp(position, "outside")) {
3453 current_button_flags |= BC_OUTDOWN_IDLE;
3454 } else if(!strcmp(position, "anywhere")) {
3455 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3458 if(type == RAWDATA) {
3460 s_buttonaction(current_button_flags, action);
3461 current_button_flags = 0;
3467 static int c_on_move_in(map_t*args)
3469 char*position = lu(args, "state");
3471 if(!strcmp(position, "pressed")) {
3472 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3473 } else if(!strcmp(position, "not_pressed")) {
3474 current_button_flags |= BC_IDLE_OVERUP;
3475 } else if(!strcmp(position, "any")) {
3476 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3479 if(type == RAWDATA) {
3481 s_buttonaction(current_button_flags, action);
3482 current_button_flags = 0;
3488 static int c_on_move_out(map_t*args)
3490 char*position = lu(args, "state");
3492 if(!strcmp(position, "pressed")) {
3493 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3494 } else if(!strcmp(position, "not_pressed")) {
3495 current_button_flags |= BC_OVERUP_IDLE;
3496 } else if(!strcmp(position, "any")) {
3497 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3500 if(type == RAWDATA) {
3502 s_buttonaction(current_button_flags, action);
3503 current_button_flags = 0;
3509 static int c_on_key(map_t*args)
3511 char*key = lu(args, "key");
3513 if(strlen(key)==1) {
3516 current_button_flags |= 0x4000 + (key[0]*0x200);
3518 syntaxerror("invalid character: %c"+key[0]);
3523 <ctrl-x> = 0x200*(x-'a')
3527 syntaxerror("invalid key: %s",key);
3530 if(type == RAWDATA) {
3532 s_buttonaction(current_button_flags, action);
3533 current_button_flags = 0;
3540 static int c_edittext(map_t*args)
3542 //"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"},
3543 char*name = lu(args, "name");
3544 char*font = lu(args, "font");
3545 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3546 int width = parseTwip(lu(args, "width"));
3547 int height = parseTwip(lu(args, "height"));
3548 char*text = lu(args, "text");
3549 RGBA color = parseColor(lu(args, "color"));
3550 int maxlength = parseInt(lu(args, "maxlength"));
3551 char*variable = lu(args, "variable");
3552 char*passwordstr = lu(args, "password");
3553 char*wordwrapstr = lu(args, "wordwrap");
3554 char*multilinestr = lu(args, "multiline");
3555 char*htmlstr = lu(args, "html");
3556 char*noselectstr = lu(args, "noselect");
3557 char*readonlystr = lu(args, "readonly");
3558 char*borderstr = lu(args, "border");
3559 char*autosizestr = lu(args, "autosize");
3560 char*alignstr = lu(args, "align");
3564 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3565 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3566 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3567 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3568 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3569 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3570 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3571 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3572 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3573 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3574 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3575 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3576 else syntaxerror("Unknown alignment: %s", alignstr);
3578 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3582 static int c_morphshape(map_t*args) {return fakechar(args);}
3583 static int c_movie(map_t*args) {return fakechar(args);}
3585 static char* readfile(const char*filename)
3587 FILE*fi = fopen(filename, "rb");
3591 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3592 fseek(fi, 0, SEEK_END);
3594 fseek(fi, 0, SEEK_SET);
3595 text = rfx_alloc(l+1);
3596 fread(text, l, 1, fi);
3602 static int c_action(map_t*args)
3604 char* filename = map_lookup(args, "filename");
3605 if(!filename ||!*filename) {
3607 if(type != RAWDATA) {
3608 syntaxerror("colon (:) expected");
3612 s_action(readfile(filename));
3618 static int c_initaction(map_t*args)
3620 char* character = lu(args, "name");
3621 char* filename = map_lookup(args, "filename");
3622 if(!filename ||!*filename) {
3624 if(type != RAWDATA) {
3625 syntaxerror("colon (:) expected");
3627 s_initaction(character, text);
3629 s_initaction(character, readfile(filename));
3637 command_func_t* func;
3640 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no"},
3641 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3642 // "import" type stuff
3643 {"swf", c_swf, "name filename"},
3644 {"shape", c_swf, "name filename"},
3645 {"jpeg", c_image, "name filename quality=80%"},
3646 {"png", c_image, "name filename"},
3647 {"movie", c_movie, "name filename"},
3648 {"sound", c_sound, "name filename"},
3649 {"font", c_font, "name filename"},
3650 {"soundtrack", c_soundtrack, "filename"},
3651 {"quicktime", c_quicktime, "url"},
3653 // generators of primitives
3655 {"point", c_point, "name x=0 y=0"},
3656 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
3657 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5, damping=2"},
3658 {"outline", c_outline, "name format=simple"},
3659 {"textshape", c_textshape, "name font size=100% text"},
3662 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
3663 {"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"},
3664 {"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"},
3665 {"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"},
3667 // character generators
3668 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
3669 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
3670 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
3672 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
3673 {"text", c_text, "name text font size=100% color=white"},
3674 {"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="},
3675 {"morphshape", c_morphshape, "name start end"},
3676 {"button", c_button, "name"},
3677 {"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="},
3678 {"on_press", c_on_press, "position=inside"},
3679 {"on_release", c_on_release, "position=anywhere"},
3680 {"on_move_in", c_on_move_in, "state=not_pressed"},
3681 {"on_move_out", c_on_move_out, "state=not_pressed"},
3682 {"on_key", c_on_key, "key=any"},
3685 {"play", c_play, "name loop=0 @nomultiple=0"},
3686 {"stop", c_stop, "name= "},
3687 {"nextframe", c_nextframe, "name"},
3688 {"previousframe", c_previousframe, "name"},
3690 // object placement tags
3691 {"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="},
3692 {"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="},
3693 {"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"},
3694 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3695 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3696 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3697 {"del", c_del, "name"},
3698 // virtual object placement
3699 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
3701 // commands which start a block
3702 //startclip (see above)
3703 {"sprite", c_sprite, "name"},
3704 {"action", c_action, "filename="},
3705 {"initaction", c_initaction, "name filename="},
3711 static map_t parseArguments(char*command, char*pattern)
3727 string_set(&t1, "commandname");
3728 string_set(&t2, command);
3729 map_put(&result, t1, t2);
3731 if(!pattern || !*pattern)
3738 if(!strncmp("<i> ", x, 3)) {
3740 if(type == COMMAND || type == RAWDATA) {
3742 syntaxerror("character name expected");
3744 name[pos].str = "instance";
3746 value[pos].str = text;
3747 value[pos].len = strlen(text);
3751 if(type == ASSIGNMENT)
3754 name[pos].str = "character";
3756 value[pos].str = text;
3757 value[pos].len = strlen(text);
3765 isboolean[pos] = (x[0] =='@');
3778 name[pos].len = d-x;
3783 name[pos].len = e-x;
3784 value[pos].str = e+1;
3785 value[pos].len = d-e-1;
3793 /* for(t=0;t<len;t++) {
3794 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
3795 isboolean[t]?"(boolean)":"");
3800 if(type == RAWDATA || type == COMMAND) {
3805 // first, search for boolean arguments
3806 for(pos=0;pos<len;pos++)
3808 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
3810 if(type == ASSIGNMENT)
3812 value[pos].str = text;
3813 value[pos].len = strlen(text);
3814 /*printf("setting boolean parameter %s (to %s)\n",
3815 strdup_n(name[pos], namelen[pos]),
3816 strdup_n(value[pos], valuelen[pos]));*/
3821 // second, search for normal arguments
3823 for(pos=0;pos<len;pos++)
3825 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
3826 (type != ASSIGNMENT && !set[pos])) {
3828 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
3830 if(type == ASSIGNMENT)
3833 value[pos].str = text;
3834 value[pos].len = strlen(text);
3836 printf("setting parameter %s (to %s)\n",
3837 strdup_n(name[pos].str, name[pos].len),
3838 strdup_n(value[pos].str, value[pos].len));
3844 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
3848 for(t=0;t<len;t++) {
3849 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
3852 for(t=0;t<len;t++) {
3853 if(value[t].str && value[t].str[0] == '*') {
3854 //relative default- take value from some other parameter
3856 for(s=0;s<len;s++) {
3857 if(value[s].len == value[t].len-1 &&
3858 !strncmp(&value[t].str[1], value[s].str, value[s].len))
3859 value[t].str = value[s].str;
3862 if(value[t].str == 0) {
3864 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
3868 /* ok, now construct the dictionary from the parameters */
3872 map_put(&result, name[t], value[t]);
3876 static void parseArgumentsForCommand(char*command)
3881 msg("<verbose> parse Command: %s (line %d)", command, line);
3883 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
3884 if(!strcmp(arguments[t].command, command)) {
3886 /* ugly hack- will be removed soon (once documentation and .sc generating
3887 utilities have been changed) */
3888 if(!strcmp(command, "swf") && !stackpos) {
3889 warning("Please use .flash instead of .swf- this will be mandatory soon");
3894 args = parseArguments(command, arguments[t].arguments);
3900 syntaxerror("command %s not known", command);
3902 // catch missing .flash directives at the beginning of a file
3903 if(strcmp(command, "flash") && !stackpos)
3905 syntaxerror("No movie defined- use .flash first");
3909 printf(".%s\n", command);fflush(stdout);
3910 map_dump(&args, stdout, "\t");fflush(stdout);
3913 (*arguments[nr].func)(&args);
3915 /*if(!strcmp(command, "button") ||
3916 !strcmp(command, "action")) {
3919 if(type == COMMAND) {
3920 if(!strcmp(text, "end"))
3935 /* for now only intended to find what glyphs of each font are to be included in the swf file.
3936 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
3937 * No syntax checking is done */
3938 static void analyseArgumentsForCommand(char*command)
3944 msg("<verbose> analyse Command: %s (line %d)", command, line);
3946 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
3948 if(!strcmp(arguments[t].command, command))
3950 args = parseArguments(command, arguments[t].arguments);
3956 printf(".%s\n", command);fflush(stdout);
3957 map_dump(&args, stdout, "\t");fflush(stdout);
3959 char* name = lu(&args, "name");
3960 if (!strcmp(command, "font"))
3962 if(dictionary_lookup(&fonts, name))
3963 syntaxerror("font %s defined twice", name);
3966 fontfile = lu(&args, "filename");
3967 font = swf_LoadFont(fontfile);
3969 warning("Couldn't open font file \"%s\"", fontfile);
3970 font = (SWFFONT*)malloc(sizeof(SWFFONT));
3971 memset(font, 0, sizeof(SWFFONT));
3973 swf_FontPrepareForEditText(font);
3974 dictionary_put2(&fonts, name, font);
3978 SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "font"));
3980 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
3982 if (!strcmp(command, "edittext"))
3983 swf_FontUseAll(font);
3985 swf_FontUseUTF8(font, lu(&args, "text"));
3991 void skipParameters()
3995 while (type != COMMAND);
3999 void findFontUsage()
4001 char* fontRelated = "font;text;textshape;edittext;";
4002 while(!noMoreTokens())
4006 syntaxerror("command expected");
4007 if (strstr(fontRelated, text))
4008 analyseArgumentsForCommand(text);
4010 if(strcmp(text, "end"))
4019 dictionary_init(&fonts);
4020 cleanUp = &freeFontDictionary;
4024 int main (int argc,char ** argv)
4027 processargs(argc, argv);
4028 initLog(0,-1,0,0,-1,verbose);
4031 args_callback_usage(argv[0]);
4035 file = generateTokens(filename);
4037 fprintf(stderr, "parser returned error.\n");
4044 while(!noMoreTokens()) {
4047 syntaxerror("command expected");
4048 parseArgumentsForCommand(text);