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;
50 static int do_exports = 0;
51 static char * mainclass = "";
53 static struct options_t options[] = {
62 int args_callback_option(char*name,char*val)
64 if(!strcmp(name, "V")) {
65 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
68 else if(!strcmp(name, "o")) {
70 override_outputname = 1;
73 else if(!strcmp(name, "O")) {
77 else if(!strcmp(name, "C")) {
81 else if(!strcmp(name, "v")) {
86 printf("Unknown option: -%s\n", name);
91 int args_callback_longoption(char*name,char*val)
93 return args_long2shortoption(options, name, val);
95 void args_callback_usage(char *name)
98 printf("Usage: %s [-o file.swf] file.sc\n", name);
100 printf("-h , --help Print short help message and exit\n");
101 printf("-V , --version Print version info and exit\n");
102 printf("-C , --cgi Output to stdout (for use in CGI environments)\n");
103 printf("-v , --verbose Increase verbosity. \n");
104 printf("-o , --output <filename> Set output file to <filename>.\n");
107 int args_callback_command(char*name,char*val)
110 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
117 static struct token_t* file;
124 static void readToken()
126 type = file[pos].type;
128 syntaxerror("unexpected end of file");
130 text = file[pos].text;
131 textlen = strlen(text);
132 line = file[pos].line;
133 column = file[pos].column;
135 //printf("---> %d(%s) %s\n", type, type_names[type], text);
138 static void pushBack()
141 if(!pos) syntaxerror("internal error 3");
146 textlen = strlen(text);
149 column = file[p].column;
152 static int noMoreTokens()
154 if(file[pos].type == END)
172 // ------------------------------ swf routines ----------------------------
176 int type; //0=swf, 1=sprite, 2=clip, 3=button
183 /* for sprites (1): */
197 static int stackpos = 0;
199 static dict_t characters;
200 static dict_t images;
201 static dict_t textures;
202 static dict_t outlines;
203 static dict_t gradients;
204 static dict_t filters;
205 static dict_t interpolations;
206 static char idmap[65536];
207 static TAG*tag = 0; //current tag
209 static int id; //current character id
210 static int currentframe; //current frame in current level
211 static SRECT currentrect; //current bounding box in current level
212 static U16 currentdepth;
213 static dict_t instances;
215 static dict_t sounds;
216 static dict_t fontUsage;
218 typedef struct _parameters {
220 float scalex, scaley;
226 U8 blendmode; //not interpolated
228 U16 set; // bits indicating wether a parameter was set in the c_placement function
229 U16 flags; // bits to toggle anything you may care to implement as a toggle
232 typedef struct _character {
238 typedef struct _instance {
239 character_t*character;
241 parameters_t parameters;
245 typedef struct _outline {
250 typedef struct _gradient {
256 typedef struct _filter {
260 typedef struct _texture {
264 char* interpolationFunctions[] = {"linear", \
265 "quadIn", "quadOut", "quadInOut", \
266 "cubicIn", "cubicOut", "cubicInOut", \
267 "quartIn", "quartOut", "quartInOut", \
268 "quintIn", "quintOut", "quintInOut", \
269 "circleIn", "circleOut", "circleInOut", \
270 "exponentialIn", "exponentialOut", "exponentialInOut", \
271 "sineIn", "sineOut", "sineInOut", \
272 "elasticIn", "elasticOut", "elasticInOut", \
273 "backIn", "backOut", "backInOut", \
274 "bounceIn", "bounceOut", "bounceInOut", \
275 "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
277 static void character_init(character_t*c)
279 memset(c, 0, sizeof(character_t));
282 static character_t* character_new()
285 c = (character_t*)malloc(sizeof(character_t));
290 static void instance_init(instance_t*i)
292 memset(i, 0, sizeof(instance_t));
293 i->history = history_new();
296 static void instance_free(instance_t* i)
298 history_free(i->history);
302 static instance_t* instance_new()
305 c = (instance_t*)malloc(sizeof(instance_t));
310 static void free_instance(void* i)
312 instance_free((instance_t*)i);
315 static void free_font(void* f)
317 swf_FontFree((SWFFONT*)f);
320 static void gradient_free(GRADIENT* grad)
327 static void free_gradient(void* grad)
329 gradient_free((GRADIENT*) grad);
332 static void outline_free(outline_t* o)
334 free(o->shape->data);
339 static void free_outline(void* o)
341 outline_free((outline_t*)o);
344 static void freeDictionaries()
346 dict_free_all(&instances, 1, free_instance);
347 dict_free_all(&characters, 1, free);
348 dict_free_all(&images, 1, free);
349 dict_free_all(&textures, 1, free);
350 dict_free_all(&outlines, 1, free_outline);
351 dict_free_all(&gradients, 1, free_gradient);
352 dict_free_all(&filters, 1, free);
353 dict_free_all(&fonts, 1, free_font);
354 dict_free_all(&sounds, 1, free);
355 dict_free_all(&interpolations, 1, free);
359 static void freeFontDictionary()
361 dict_free_all(&fonts, 1, free_font);
364 static void incrementid()
366 while(id<65536 && idmap[id]) {
370 syntaxerror("Out of character ids.");
374 static void s_addcharacter(const char*name, U16 id, TAG*ctag, SRECT r)
376 if(dict_lookup(&characters, name))
377 syntaxerror("character %s defined twice", name);
378 character_t* c = character_new();
380 c->definingTag = ctag;
383 dict_put(&characters, name, c);
386 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
388 swf_SetString(tag, name);
389 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
392 swf_SetString(tag, name);
395 static void s_addimage(const char*name, U16 id, TAG*ctag, SRECT r)
397 if(dict_lookup(&images, name))
398 syntaxerror("image %s defined twice", name);
400 character_t* c = character_new();
401 c->definingTag = ctag;
404 dict_put(&images, name, c);
406 static instance_t* s_addinstance(const char*name, character_t*c, U16 depth)
408 if(dict_lookup(&instances, name))
409 syntaxerror("object %s defined twice", name);
410 instance_t* i = instance_new();
413 //swf_GetMatrix(0, &i->matrix);
414 dict_put(&instances, name, i);
418 static void parameters_clear(parameters_t*p)
421 p->scalex = 1.0; p->scaley = 1.0;
424 p->pivot.x = 0; p->pivot.y = 0;
429 swf_GetCXForm(0, &p->cxform, 1);
432 static void makeMatrix(MATRIX*m, parameters_t*p)
441 sx = p->scalex*cos(p->rotate/360*2*M_PI);
442 r1 = -p->scalex*sin(p->rotate/360*2*M_PI)+sx*p->shear;
443 r0 = p->scaley*sin(p->rotate/360*2*M_PI);
444 sy = p->scaley*cos(p->rotate/360*2*M_PI)+r0*p->shear;
446 m->sx = (int)(sx*65536+0.5);
447 m->r1 = (int)(r1*65536+0.5);
448 m->r0 = (int)(r0*65536+0.5);
449 m->sy = (int)(sy*65536+0.5);
453 h = swf_TurnPoint(p->pin, m);
458 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
463 r = swf_TurnRect(rect, &m);
464 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
465 currentrect.xmax == 0 && currentrect.ymax == 0)
468 swf_ExpandRect2(¤trect, &r);
474 interpolation_t* new;
475 new = (interpolation_t*)malloc(sizeof(interpolation_t));
476 new->function = IF_LINEAR;
477 dict_put(&interpolations, "linear", new);
479 new = (interpolation_t*)malloc(sizeof(interpolation_t));
480 new->function = IF_QUAD_IN;
482 dict_put(&interpolations, "quadIn", new);
483 new = (interpolation_t*)malloc(sizeof(interpolation_t));
484 new->function = IF_QUAD_OUT;
486 dict_put(&interpolations, "quadOut", new);
487 new = (interpolation_t*)malloc(sizeof(interpolation_t));
488 new->function = IF_QUAD_IN_OUT;
490 dict_put(&interpolations, "quadInOut", new);
492 new = (interpolation_t*)malloc(sizeof(interpolation_t));
493 new->function = IF_CUBIC_IN;
495 dict_put(&interpolations, "cubicIn", new);
496 new = (interpolation_t*)malloc(sizeof(interpolation_t));
497 new->function = IF_CUBIC_OUT;
499 dict_put(&interpolations, "cubicOut", new);
500 new = (interpolation_t*)malloc(sizeof(interpolation_t));
501 new->function = IF_CUBIC_IN_OUT;
503 dict_put(&interpolations, "cubicInOut", new);
505 new = (interpolation_t*)malloc(sizeof(interpolation_t));
506 new->function = IF_QUART_IN;
508 dict_put(&interpolations, "quartIn", new);
509 new = (interpolation_t*)malloc(sizeof(interpolation_t));
510 new->function = IF_QUART_OUT;
512 dict_put(&interpolations, "quartOut", new);
513 new = (interpolation_t*)malloc(sizeof(interpolation_t));
514 new->function = IF_QUART_IN_OUT;
516 dict_put(&interpolations, "quartInOut", new);
518 new = (interpolation_t*)malloc(sizeof(interpolation_t));
519 new->function = IF_QUINT_IN;
521 dict_put(&interpolations, "quintIn", new);
522 new = (interpolation_t*)malloc(sizeof(interpolation_t));
523 new->function = IF_QUINT_OUT;
525 dict_put(&interpolations, "quintOut", new);
526 new = (interpolation_t*)malloc(sizeof(interpolation_t));
527 new->function = IF_QUINT_IN_OUT;
529 dict_put(&interpolations, "quintInOut", new);
531 new = (interpolation_t*)malloc(sizeof(interpolation_t));
532 new->function = IF_CIRCLE_IN;
533 dict_put(&interpolations, "circleIn", new);
534 new = (interpolation_t*)malloc(sizeof(interpolation_t));
535 new->function = IF_CIRCLE_OUT;
536 dict_put(&interpolations, "circleOut", new);
537 new = (interpolation_t*)malloc(sizeof(interpolation_t));
538 new->function = IF_CIRCLE_IN_OUT;
539 dict_put(&interpolations, "circleInOut", new);
541 new = (interpolation_t*)malloc(sizeof(interpolation_t));
542 new->function = IF_EXPONENTIAL_IN;
543 dict_put(&interpolations, "exponentialIn", new);
544 new = (interpolation_t*)malloc(sizeof(interpolation_t));
545 new->function = IF_EXPONENTIAL_OUT;
546 dict_put(&interpolations, "exponentialOut", new);
547 new = (interpolation_t*)malloc(sizeof(interpolation_t));
548 new->function = IF_EXPONENTIAL_IN_OUT;
549 dict_put(&interpolations, "exponentialInOut", new);
551 new = (interpolation_t*)malloc(sizeof(interpolation_t));
552 new->function = IF_SINE_IN;
553 dict_put(&interpolations, "sineIn", new);
554 new = (interpolation_t*)malloc(sizeof(interpolation_t));
555 new->function = IF_SINE_OUT;
556 dict_put(&interpolations, "sineOut", new);
557 new = (interpolation_t*)malloc(sizeof(interpolation_t));
558 new->function = IF_SINE_IN_OUT;
559 dict_put(&interpolations, "sineInOut", new);
562 memset(&c, 0, sizeof(RGBA));
563 gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
564 noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
565 noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
566 noGradient->gradient.num = 2;
567 noGradient->gradient.rgba[0] = c;
568 noGradient->gradient.ratios[0] = 0;
569 noGradient->gradient.rgba[1] = c;
570 noGradient->gradient.ratios[1] = 255;
571 noGradient->radial = 0;
572 noGradient->rotate = 0;
573 dict_put(&gradients, "no_gradient", noGradient);
576 // put a no_filters entry in the filters dictionary to provoce a message when a user tries
577 // to define a no_filters filter. The real filter=no_filters case is handled in parseFilters.
578 FILTER* dummy = (FILTER*)malloc(sizeof(FILTER));
579 dict_put(&filters, "no_filters", dummy);
580 noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
582 dict_put(&filters, "no_blur", noBlur);
583 noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
585 noBevel->composite = 1;
586 dict_put(&filters, "no_bevel", noBevel);
587 noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
588 noDropshadow->passes = 1;
589 noDropshadow->composite = 1;
590 dict_put(&filters, "no_dropshadow", noDropshadow);
591 noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
592 noGradientGlow->passes = 1;
593 noGradientGlow->composite = 1;
594 noGradientGlow->gradient = &noGradient->gradient;
595 dict_put(&filters, "no_gradientglow", noGradientGlow);
598 void s_swf(const char*name, SRECT r, int version, int fps, int compress, RGBA background)
601 syntaxerror(".swf blocks can't be nested");
602 if(stackpos==sizeof(stack)/sizeof(stack[0]))
603 syntaxerror("too many levels of recursion");
605 SWF*swf = (SWF*)malloc(sizeof(SWF));
607 memset(swf, 0, sizeof(swf));
608 swf->fileVersion = version;
610 swf->frameRate = fps;
611 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
612 swf->compressed = compress;
613 swf_SetRGB(tag,&background);
615 dict_init(&characters, 16);
616 dict_init(&images, 16);
617 dict_init(&textures, 16);
618 dict_init(&outlines, 16);
619 dict_init(&gradients, 16);
620 dict_init(&filters, 16);
621 dict_init(&instances, 16);
622 dict_init(&sounds, 16);
623 dict_init(&interpolations, 16);
625 cleanUp = &freeDictionaries;
627 memset(&stack[stackpos], 0, sizeof(stack[0]));
628 stack[stackpos].type = 0;
629 stack[stackpos].filename = strdup(name);
630 stack[stackpos].swf = swf;
631 stack[stackpos].oldframe = -1;
635 memset(¤trect, 0, sizeof(currentrect));
638 memset(idmap, 0, sizeof(idmap));
639 idmap[0]=1; //main movie has ID 0
644 void s_sprite(const char*name, SRECT*scalegrid, const char*as3name)
646 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
647 swf_SetU16(tag, id); //id
648 swf_SetU16(tag, 0); //frames
650 memset(&stack[stackpos], 0, sizeof(stack[0]));
651 stack[stackpos].type = 1;
652 stack[stackpos].oldframe = currentframe;
653 stack[stackpos].olddepth = currentdepth;
654 stack[stackpos].oldrect = currentrect;
655 stack[stackpos].oldinstances = instances;
656 stack[stackpos].tag = tag;
657 stack[stackpos].id = id;
658 stack[stackpos].name = strdup(name);
659 stack[stackpos].as3name = strdup(as3name);
661 stack[stackpos].scalegrid = *scalegrid;
663 memset(&stack[stackpos].scalegrid, 0, sizeof(SRECT));
666 /* FIXME: those four fields should be bundled together */
667 dict_init(&instances, 16);
670 memset(¤trect, 0, sizeof(currentrect));
676 typedef struct _buttonrecord
684 typedef struct _button
688 buttonrecord_t records[4];
691 static button_t mybutton;
693 void s_button(const char*name, const char*as3name)
695 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
696 swf_SetU16(tag, id); //id
697 swf_ButtonSetFlags(tag, 0); //menu=no
699 memset(&mybutton, 0, sizeof(mybutton));
701 memset(&stack[stackpos], 0, sizeof(stack[0]));
702 stack[stackpos].type = 3;
703 stack[stackpos].tag = tag;
704 stack[stackpos].id = id;
705 stack[stackpos].name = strdup(name);
706 stack[stackpos].as3name = strdup(as3name);
707 stack[stackpos].oldrect = currentrect;
708 memset(¤trect, 0, sizeof(currentrect));
713 void s_buttonput(const char*character, const char*as, parameters_t p)
715 character_t* c = dict_lookup(&characters, character);
718 const char*o = as,*s = as;
720 if(!stackpos || (stack[stackpos-1].type != 3)) {
721 syntaxerror(".show may only appear in .button");
724 syntaxerror("character %s not known (in .shape %s)", character, character);
726 if(mybutton.endofshapes) {
727 syntaxerror("a .do may not precede a .show", character, character);
730 m = s_instancepos(c->size, &p);
738 if(*s==',' || *s==0) {
739 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
740 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
741 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
742 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
743 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
744 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
751 static void setbuttonrecords(TAG*tag)
753 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
754 if(!mybutton.endofshapes) {
757 if(!mybutton.records[3].set) {
758 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
762 if(mybutton.records[t].set) {
763 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
766 swf_SetU8(tag,0); // end of button records
767 mybutton.endofshapes = 1;
771 void s_buttonaction(int flags, const char*action)
777 if(!stackpos || !stack[stackpos-1].tag ||
778 stack[stackpos-1].tag->id != ST_DEFINEBUTTON2) {
779 syntaxerror("Need to be inside a button for .on_* commands");
781 setbuttonrecords(stack[stackpos-1].tag);
783 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
785 syntaxerror("Couldn't compile ActionScript");
788 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
789 swf_ActionSet(stack[stackpos-1].tag, a);
790 mybutton.nr_actions++;
795 static void setactionend(TAG*tag)
797 if(!mybutton.nr_actions) {
798 /* no actions means we didn't have an actionoffset,
799 which means we can't signal the end of the
800 buttonaction records, so, *sigh*, we have
801 to insert a dummy record */
802 swf_SetU16(tag, 0); //offset
803 swf_SetU16(tag, 0); //condition
804 swf_SetU8(tag, 0); //action
808 static void s_endButton()
811 setbuttonrecords(stack[stackpos-1].tag);
812 setactionend(stack[stackpos-1].tag);
815 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
819 tag = stack[stackpos].tag;
820 currentrect = stack[stackpos].oldrect;
822 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
824 if(*stack[stackpos].as3name) {
825 tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
827 swf_SetU16(tag, stack[stackpos].id);
828 swf_SetString(tag, stack[stackpos].as3name);
831 free(stack[stackpos].name);
834 TAG* removeFromTo(TAG*from, TAG*to)
836 TAG*save = from->prev;
838 TAG*next = from->next;
839 if(swf_isAllowedSpriteTag(from))
840 swf_DeleteTag(0, from);
847 static int parametersChange(history_t* history, int frame)
851 willChange = willChange || history_change(history, frame, "x");
852 willChange = willChange || history_change(history, frame, "y");
853 willChange = willChange || history_change(history, frame, "scalex");
854 willChange = willChange || history_change(history, frame, "scaley");
855 willChange = willChange || history_change(history, frame, "cxform.r0");
856 willChange = willChange || history_change(history, frame, "cxform.g0");
857 willChange = willChange || history_change(history, frame, "cxform.b0");
858 willChange = willChange || history_change(history, frame, "cxform.a0");
859 willChange = willChange || history_change(history, frame, "cxform.r1");
860 willChange = willChange || history_change(history, frame, "cxform.g1");
861 willChange = willChange || history_change(history, frame, "cxform.b1");
862 willChange = willChange || history_change(history, frame, "cxform.a1");
863 willChange = willChange || history_change(history, frame, "rotate");
864 willChange = willChange || history_change(history, frame, "shear");
865 willChange = willChange || history_change(history, frame, "pivot.x");
866 willChange = willChange || history_change(history, frame, "pivot.y");
867 willChange = willChange || history_change(history, frame, "pin.x");
868 willChange = willChange || history_change(history, frame, "pin.y");
869 willChange = willChange || history_change(history, frame, "blendmode");
870 willChange = willChange || history_changeFilter(history, frame);
875 static void free_filterlist(FILTERLIST* f_list)
878 for (i = 0; i < f_list->num; i++)
880 if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
881 gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
882 free(f_list->filter[i]);
887 static void readParameters(history_t* history, parameters_t* p, int frame)
889 p->x = history_value(history, frame, "x");
890 p->y = history_value(history, frame, "y");
891 p->scalex = history_value(history, frame, "scalex");
892 p->scaley = history_value(history, frame, "scaley");
893 p->cxform.r0 = history_value(history, frame, "cxform.r0");
894 p->cxform.g0 = history_value(history, frame, "cxform.g0");
895 p->cxform.b0 = history_value(history, frame, "cxform.b0");
896 p->cxform.a0 = history_value(history, frame, "cxform.a0");
897 p->cxform.r1 = history_value(history, frame, "cxform.r1");
898 p->cxform.g1 = history_value(history, frame, "cxform.g1");
899 p->cxform.b1 = history_value(history, frame, "cxform.b1");
900 p->cxform.a1 = history_value(history, frame, "cxform.a1");
901 p->rotate = history_rotateValue(history, frame);
902 p->shear = history_value(history, frame, "shear");
903 p->pivot.x = history_value(history, frame, "pivot.x");
904 p->pivot.y = history_value(history, frame, "pivot.y");
905 p->pin.x = history_value(history, frame, "pin.x");
906 p->pin.y = history_value(history, frame, "pin.y");
907 p->blendmode = history_value(history, frame, "blendmode");
908 p->filters = history_filterValue(history, frame);
911 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, const char*name, parameters_t*p, char move)
915 swf_GetPlaceObject(NULL, &po);
919 po.cxform = p->cxform;
920 po.name = (char*)name;
925 po.blendmode = p->blendmode;
928 po.filters = p->filters;
929 swf_SetPlaceObject(tag, &po);
932 static void writeInstance(void* _i)
934 instance_t*i = (instance_t*)_i;
937 int frame = i->history->firstFrame;
938 TAG* tag = i->history->firstTag;
939 history_processFlags(i->history);
940 while (tag && frame < currentframe)
943 while (tag && tag->id != ST_SHOWFRAME)
945 if (parametersChange(i->history, frame))
947 readParameters(i->history, &p, frame);
948 m = s_instancepos(i->character->size, &p);
950 if(p.blendmode || p.filters)
951 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
953 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
954 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
956 free_filterlist(p.filters);
963 void dumpSWF(SWF*swf)
965 TAG* tag = swf->firstTag;
966 printf("vvvvvvvvvvvvvvvvvvvvv\n");
968 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
971 printf("^^^^^^^^^^^^^^^^^^^^^\n");
974 static void s_endSprite()
976 SRECT r = currentrect;
981 dict_foreach_value(&instances, writeInstance);
983 if(stack[stackpos].cut)
984 tag = removeFromTo(stack[stackpos].cut, tag);
986 // the writeInstance loop above may have inserted tags after what used to be the current tag,
987 // so let's make sure 'tag' point to the current tag again.
991 tag = swf_InsertTag(tag, ST_SHOWFRAME);
992 tag = swf_InsertTag(tag, ST_END);
994 tag = stack[stackpos].tag;
997 if(stack[stackpos].scalegrid.xmin | stack[stackpos].scalegrid.ymin |
998 stack[stackpos].scalegrid.xmax | stack[stackpos].scalegrid.ymax)
1000 tag = swf_InsertTag(tag, ST_DEFINESCALINGGRID);
1001 swf_SetU16(tag, stack[stackpos].id);
1002 swf_SetRect(tag, &stack[stackpos].scalegrid);
1006 syntaxerror("internal error(7)");
1007 /* TODO: before clearing, prepend "<spritename>." to names and
1008 copy into old instances dict */
1009 dict_free_all(&instances, 1, free_instance);
1011 currentframe = stack[stackpos].oldframe;
1012 currentrect = stack[stackpos].oldrect;
1013 currentdepth = stack[stackpos].olddepth;
1014 instances = stack[stackpos].oldinstances;
1016 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
1018 if(*stack[stackpos].as3name) {
1019 tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
1021 swf_SetU16(tag, stack[stackpos].id);
1022 swf_SetString(tag, stack[stackpos].as3name);
1026 free(stack[stackpos].name);
1029 static void s_endSWF()
1036 dict_foreach_value(&instances, writeInstance);
1038 if(stack[stackpos].cut)
1039 tag = removeFromTo(stack[stackpos].cut, tag);
1043 swf = stack[stackpos].swf;
1044 filename = stack[stackpos].filename;
1046 // the writeInstance loop above may have inserted tags after what used yo be the current tag,
1047 // so let's make sure 'tag' point to the current tag again.
1051 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1052 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
1053 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1056 TAG*tag = swf->firstTag;
1057 tag = swf_InsertTag(tag, ST_DOABC);
1058 void*code = as3_getcode();
1059 swf_WriteABC(tag, code);
1062 else if (as3_getglobalclass())
1063 mc = as3_getglobalclass();
1065 tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
1068 swf_SetString(tag, mc);
1070 warning("no global public MovieClip subclass");
1075 tag = swf_InsertTag(tag, ST_END);
1077 swf_OptimizeTagOrder(swf);
1083 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1084 swf->movieSize = currentrect; /* "autocrop" */
1087 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1088 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1089 swf->movieSize.ymax += 20;
1090 warning("Empty bounding box for movie");
1093 if(do_cgi || !strcmp(filename, "-"))
1094 fi = fileno(stdout);
1096 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1098 syntaxerror("couldn't create output file %s", filename);
1101 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1103 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1117 if(stack[stackpos-1].type == 0)
1118 syntaxerror("End of file encountered in .flash block");
1119 if(stack[stackpos-1].type == 1)
1120 syntaxerror("End of file encountered in .sprite block");
1121 if(stack[stackpos-1].type == 2)
1122 syntaxerror("End of file encountered in .clip block");
1128 return currentframe+1;
1131 void s_frame(int nr, int cut, const char*name, char anchor)
1137 syntaxerror("Illegal frame number");
1138 nr--; // internally, frame 1 is frame 0
1140 for(t=currentframe;t<nr;t++) {
1141 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1142 if(t==nr-1 && name && *name) {
1143 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1144 swf_SetString(tag, name);
1146 swf_SetU8(tag, 1); //make this an anchor
1149 if(nr == 0 && currentframe == 0 && name && *name) {
1150 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1151 swf_SetString(tag, name);
1153 swf_SetU8(tag, 1); //make this an anchor
1158 syntaxerror("Can't cut, frame empty");
1160 stack[stackpos].cut = tag;
1166 int parseColor2(const char*str, RGBA*color);
1168 int addFillStyle(SHAPE*s, SRECT*r, const char*name)
1172 gradient_t*gradient;
1174 if(name[0] == '#') {
1175 parseColor2(name, &color);
1176 return swf_ShapeAddSolidFillStyle(s, &color);
1177 } else if ((texture = dict_lookup(&textures, name))) {
1178 return swf_ShapeAddFillStyle2(s, &texture->fs);
1179 } else if((image = dict_lookup(&images, name))) {
1181 swf_GetMatrix(0, &m);
1182 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1183 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1186 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1187 } else if ((gradient = dict_lookup(&gradients, name))) {
1191 swf_GetMatrix(0, &rot);
1192 ccos = cos(-gradient->rotate*2*M_PI/360);
1193 csin = sin(-gradient->rotate*2*M_PI/360);
1194 rot.sx = ccos*65536;
1195 rot.r1 = -csin*65536;
1196 rot.r0 = csin*65536;
1197 rot.sy = ccos*65536;
1198 r2 = swf_TurnRect(*r, &rot);
1199 swf_GetMatrix(0, &m);
1200 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1201 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1202 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1203 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1204 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1205 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1206 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1207 } else if (parseColor2(name, &color)) {
1208 return swf_ShapeAddSolidFillStyle(s, &color);
1210 syntaxerror("not a color/fillstyle: %s", name);
1215 RGBA black={r:0,g:0,b:0,a:0};
1216 void s_box(const char*name, int width, int height, RGBA color, int linewidth, const char*texture)
1225 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1228 linewidth = linewidth>=20?linewidth-20:0;
1229 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1232 fs1 = addFillStyle(s, &r2, texture);
1235 r.xmin = r2.xmin-linewidth/2;
1236 r.ymin = r2.ymin-linewidth/2;
1237 r.xmax = r2.xmax+linewidth/2;
1238 r.ymax = r2.ymax+linewidth/2;
1239 swf_SetRect(tag,&r);
1240 swf_SetShapeHeader(tag,s);
1241 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1242 swf_ShapeSetLine(tag,s,width,0);
1243 swf_ShapeSetLine(tag,s,0,height);
1244 swf_ShapeSetLine(tag,s,-width,0);
1245 swf_ShapeSetLine(tag,s,0,-height);
1246 swf_ShapeSetEnd(tag);
1249 s_addcharacter(name, id, tag, r);
1253 void s_filled(const char*name, const char*outlinename, RGBA color, int linewidth, const char*texture)
1259 outline = dict_lookup(&outlines, outlinename);
1261 syntaxerror("outline %s not defined", outlinename);
1265 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1268 linewidth = linewidth>=20?linewidth-20:0;
1269 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1272 fs1 = addFillStyle(s, &r2, texture);
1275 rect.xmin = r2.xmin-linewidth/2;
1276 rect.ymin = r2.ymin-linewidth/2;
1277 rect.xmax = r2.xmax+linewidth/2;
1278 rect.ymax = r2.ymax+linewidth/2;
1280 swf_SetRect(tag,&rect);
1281 swf_SetShapeStyles(tag, s);
1282 swf_ShapeCountBits(s,0,0);
1283 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1284 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1285 swf_SetShapeBits(tag, s);
1286 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1289 s_addcharacter(name, id, tag, rect);
1293 void s_circle(const char*name, int r, RGBA color, int linewidth, const char*texture)
1298 r2.xmin = r2.ymin = 0;
1302 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1305 linewidth = linewidth>=20?linewidth-20:0;
1306 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1309 fs1 = addFillStyle(s, &r2, texture);
1311 rect.xmin = r2.xmin-linewidth/2;
1312 rect.ymin = r2.ymin-linewidth/2;
1313 rect.xmax = r2.xmax+linewidth/2;
1314 rect.ymax = r2.ymax+linewidth/2;
1316 swf_SetRect(tag,&rect);
1317 swf_SetShapeHeader(tag,s);
1318 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1319 swf_ShapeSetCircle(tag, s, r,r,r,r);
1320 swf_ShapeSetEnd(tag);
1323 s_addcharacter(name, id, tag, rect);
1327 void s_textshape(const char*name, const char*fontname, float size, const char*_text)
1330 U8*text = (U8*)_text;
1334 font = dict_lookup(&fonts, fontname);
1336 syntaxerror("font \"%s\" not known!", fontname);
1338 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1339 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1340 s_box(name, 0, 0, black, 20, 0);
1343 g = font->ascii2glyph[text[0]];
1345 outline = malloc(sizeof(outline_t));
1346 memset(outline, 0, sizeof(outline_t));
1347 outline->shape = font->glyph[g].shape;
1348 outline->bbox = font->layout->bounds[g];
1352 swf_Shape11DrawerInit(&draw, 0);
1353 swf_DrawText(&draw, font, (int)(size*100), (char*)_text);
1355 outline->shape = swf_ShapeDrawerToShape(&draw);
1356 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1357 draw.dealloc(&draw);
1360 if(dict_lookup(&outlines, name))
1361 syntaxerror("outline %s defined twice", name);
1362 dict_put(&outlines, name, outline);
1365 void s_text(const char*name, const char*fontname, const char*text, int size, RGBA color)
1370 font = dict_lookup(&fonts, fontname);
1372 syntaxerror("font \"%s\" not known!", fontname);
1374 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1375 swf_SetU16(tag, id);
1376 if(!font->numchars) {
1377 s_box(name, 0, 0, black, 20, 0);
1380 r = swf_SetDefineText(tag, font, &color, (char*)text, size);
1382 if(stack[0].swf->fileVersion >= 8) {
1383 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1384 swf_SetU16(tag, id);
1385 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1386 swf_SetU32(tag, 0);//thickness
1387 swf_SetU32(tag, 0);//sharpness
1388 swf_SetU8(tag, 0);//reserved
1391 s_addcharacter(name, id, tag, r);
1395 void s_quicktime(const char*name, const char*url)
1400 memset(&r, 0, sizeof(r));
1402 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1403 swf_SetU16(tag, id);
1404 swf_SetString(tag, url);
1406 s_addcharacter(name, id, tag, r);
1410 void s_video(const char *name, int width, int height)
1414 memset(&r, 0, sizeof(r));
1416 tag = swf_InsertTag(tag, ST_DEFINEVIDEOSTREAM);
1417 swf_SetU16(tag, id);
1418 swf_SetU16(tag, 0); // numframes
1419 swf_SetU16(tag, width);
1420 swf_SetU16(tag, height);
1421 swf_SetU8(tag, 0); // videoflags
1422 swf_SetU8(tag, 0); // codecid
1424 s_addcharacter(name, id, tag, r);
1428 void s_edittext(const char*name, const char*fontname, int size, int width, int height, const char*text, RGBA*color, int maxlength, const char*variable, int flags, int align)
1431 EditTextLayout layout;
1434 if(fontname && *fontname) {
1435 flags |= ET_USEOUTLINES;
1436 font = dict_lookup(&fonts, fontname);
1438 syntaxerror("font \"%s\" not known!", fontname);
1440 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1441 swf_SetU16(tag, id);
1442 layout.align = align;
1443 layout.leftmargin = 0;
1444 layout.rightmargin = 0;
1452 swf_SetEditText(tag, flags, r, (char*)text, color, maxlength, font?font->id:0, size, &layout, (char*)variable);
1454 s_addcharacter(name, id, tag, r);
1458 /* type: either "jpeg" or "png"
1460 void s_image(const char*name, const char*type, const char*filename, int quality)
1462 /* an image is actually two folded: 1st bitmap, 2nd character.
1463 Both of them can be used separately */
1465 /* step 1: the bitmap */
1469 if(!strcmp(type,"jpeg")) {
1470 #ifndef HAVE_JPEGLIB
1471 warning("no jpeg support compiled in");
1472 s_box(name, 0, 0, black, 20, 0);
1475 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1476 swf_SetU16(tag, imageID);
1478 if(swf_SetJPEGBits(tag, (char*)filename, quality) < 0) {
1479 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1482 swf_GetJPEGSize(filename, &width, &height);
1489 s_addimage(name, id, tag, r);
1492 } else if(!strcmp(type,"png")) {
1494 swf_SetU16(tag, imageID);
1496 getPNG(filename, &width, &height, (unsigned char**)&data);
1499 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1502 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1503 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1504 swf_SetU16(tag, imageID);
1505 swf_SetLosslessImage(tag, data, width, height);
1512 s_addimage(name, id, tag, r);
1515 warning("image type \"%s\" not supported yet!", type);
1516 s_box(name, 0, 0, black, 20, 0);
1520 /* step 2: the character */
1521 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1522 swf_SetU16(tag, id);
1523 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1525 s_addcharacter(name, id, tag, r);
1529 void s_getBitmapSize(const char*name, int*width, int*height)
1531 character_t* image = dict_lookup(&images, name);
1532 gradient_t* gradient = dict_lookup(&gradients,name);
1534 *width = image->size.xmax;
1535 *height = image->size.ymax;
1539 /* internal SWF gradient size */
1540 if(gradient->radial) {
1549 syntaxerror("No such bitmap/gradient: %s", name);
1552 void s_texture(const char*name, const char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1554 if(dict_lookup(&textures, name))
1555 syntaxerror("texture %s defined twice", name);
1556 gradient_t* gradient = dict_lookup(&gradients, object);
1557 character_t* bitmap = dict_lookup(&images, object);
1558 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1560 FILLSTYLE*fs = &texture->fs;
1562 memset(&p, 0, sizeof(parameters_t));
1565 fs->type = FILL_TILED;
1566 fs->id_bitmap = bitmap->id;
1567 } else if(gradient) {
1568 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1569 fs->gradient = gradient->gradient;
1571 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1572 makeMatrix(&fs->m, &p);
1573 if(gradient && !gradient->radial) {
1580 p2 = swf_TurnPoint(p1, &m);
1589 dict_put(&textures, name, texture);
1592 void s_font(const char*name, const char*filename)
1595 font = dict_lookup(&fonts, name);
1598 /* fix the layout. Only needed for old fonts */
1600 for(t=0;t<font->numchars;t++) {
1601 font->glyph[t].advance = 0;
1604 swf_FontCreateLayout(font);
1607 swf_FontReduce_swfc(font);
1608 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1609 swf_FontSetDefine2(tag, font);
1611 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1613 swf_SetU16(tag, id);
1614 swf_SetString(tag, name);
1622 typedef struct _sound_t
1628 void s_sound(const char*name, const char*filename)
1630 struct WAV wav, wav2;
1634 unsigned numsamples = 1;
1635 unsigned blocksize = 1152;
1638 if(dict_lookup(&sounds, name))
1639 syntaxerror("sound %s defined twice", name);
1641 if(wav_read(&wav, filename))
1644 wav_convert2mono(&wav, &wav2, 44100);
1645 samples = (U16*)wav2.data;
1646 numsamples = wav2.size/2;
1648 #ifdef WORDS_BIGENDIAN
1650 for(t=0;t<numsamples;t++)
1651 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1655 if(mp3_read(&mp3, filename))
1657 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1663 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1668 if(numsamples%blocksize != 0)
1670 // apply padding, so that block is a multiple of blocksize
1671 int numblocks = (numsamples+blocksize-1)/blocksize;
1674 numsamples2 = numblocks * blocksize;
1675 samples2 = malloc(sizeof(U16)*numsamples2);
1676 memcpy(samples2, samples, numsamples*sizeof(U16));
1677 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1678 numsamples = numsamples2;
1683 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1684 swf_SetU16(tag, id); //id
1687 swf_SetSoundDefineMP3(
1688 tag, mp3.data, mp3.size,
1695 swf_SetSoundDefine(tag, samples, numsamples);
1698 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1699 swf_SetU16(tag, id);
1700 swf_SetString(tag, name);
1701 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1703 swf_SetU16(tag, id);
1704 swf_SetString(tag, name);
1707 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1711 dict_put(&sounds, name, sound);
1719 static char* gradient_getToken(const char**p)
1723 while(**p && strchr(" \t\n\r", **p)) {
1727 while(**p && !strchr(" \t\n\r", **p)) {
1730 result = malloc((*p)-start+1);
1731 memcpy(result,start,(*p)-start+1);
1732 result[(*p)-start] = 0;
1736 float parsePercent(const char*str);
1737 RGBA parseColor(const char*str);
1739 GRADIENT parseGradient(const char*str)
1743 const char* p = str;
1744 memset(&gradient, 0, sizeof(GRADIENT));
1745 gradient.ratios = rfx_calloc(16*sizeof(U8));
1746 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1750 char*posstr,*colorstr;
1753 posstr = gradient_getToken(&p);
1759 pos = (int)(parsePercent(posstr)*255.0);
1764 rfx_free(gradient.ratios);
1765 rfx_free(gradient.rgba);
1767 syntaxerror("Error in shape data: Color expected after %s", posstr);
1769 colorstr = gradient_getToken(&p);
1770 color = parseColor(colorstr);
1771 if(gradient.num == 16)
1773 warning("gradient record too big- max size is 16, rest ignored");
1776 gradient.ratios[gradient.num] = pos;
1777 gradient.rgba[gradient.num] = color;
1786 FILTERLIST* parseFilters(char* list)
1788 if (!strcmp(list, "no_filters"))
1791 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1793 char* f_start = list;
1797 f_end = strchr(f_start, ',');
1800 f = dict_lookup(&filters, f_start);
1804 syntaxerror("unknown filter %s", f_start);
1806 if (f_list->num == 8)
1808 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1811 f_list->filter[f_list->num] = f;
1816 f_start = f_end + 1;
1824 void s_gradient(const char*name, const char*text, int radial, int rotate)
1826 gradient_t* gradient;
1827 gradient = malloc(sizeof(gradient_t));
1828 memset(gradient, 0, sizeof(gradient_t));
1829 gradient->gradient = parseGradient(text);
1830 gradient->radial = radial;
1831 gradient->rotate = rotate;
1833 dict_put(&gradients, name, gradient);
1836 void s_gradientglow(const char*name, const char*gradient, float blurx, float blury,
1837 float angle, float distance, float strength, char innershadow,
1838 char knockout, char composite, char ontop, int passes)
1840 if(dict_lookup(&filters, name))
1841 syntaxerror("filter %s defined twice", name);
1843 gradient_t* g = dict_lookup(&gradients, gradient);
1845 syntaxerror("unknown gradient %s", gradient);
1849 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1850 filter->type = FILTERTYPE_GRADIENTGLOW;
1851 filter->gradient = &g->gradient;
1852 filter->blurx = blurx;
1853 filter->blury = blury;
1854 filter->strength = strength;
1855 filter->angle = angle;
1856 filter->distance = distance;
1857 filter->innershadow = innershadow;
1858 filter->knockout = knockout;
1859 filter->composite = composite;
1860 filter->ontop = ontop;
1861 filter->passes = passes;
1863 dict_put(&filters, name, filter);
1866 void s_dropshadow(const char*name, RGBA color, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, int passes)
1868 if(dict_lookup(&filters, name))
1869 syntaxerror("filter %s defined twice", name);
1872 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1873 filter->type = FILTERTYPE_DROPSHADOW;
1874 filter->color= color;
1875 filter->blurx = blurx;
1876 filter->blury = blury;
1877 filter->strength = strength;
1878 filter->angle = angle;
1879 filter->distance = distance;
1880 filter->innershadow = innershadow;
1881 filter->knockout = knockout;
1882 filter->composite = composite;
1883 filter->passes = passes;
1885 dict_put(&filters, name, filter);
1888 void s_bevel(const char*name, RGBA shadow, RGBA highlight, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, char ontop, int passes)
1890 if(dict_lookup(&filters, name))
1891 syntaxerror("filter %s defined twice", name);
1894 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1895 filter->type = FILTERTYPE_BEVEL;
1896 filter->shadow = shadow;
1897 filter->highlight = highlight;
1898 filter->blurx = blurx;
1899 filter->blury = blury;
1900 filter->strength = strength;
1901 filter->angle = angle;
1902 filter->distance = distance;
1903 filter->innershadow = innershadow;
1904 filter->knockout = knockout;
1905 filter->composite = composite;
1906 filter->ontop = ontop;
1907 filter->passes = passes;
1909 dict_put(&filters, name, filter);
1912 void s_blur(const char*name, double blurx, double blury, int passes)
1914 if(dict_lookup(&filters, name))
1915 syntaxerror("filter %s defined twice", name);
1917 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1918 filter->type = FILTERTYPE_BLUR;
1919 filter->blurx = blurx;
1920 filter->blury = blury;
1921 filter->passes = passes;
1923 dict_put(&filters, name, filter);
1926 void s_action(const char*text)
1928 if(stack[0].swf->fileVersion < 9) {
1930 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1933 syntaxerror("Couldn't compile ActionScript");
1935 tag = swf_InsertTag(tag, ST_DOACTION);
1936 swf_ActionSet(tag, a);
1939 as3_parse_bytearray(stack[0].filename, text, strlen(text));
1944 void s_initaction(const char*character, const char*text)
1948 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1952 syntaxerror("Couldn't compile ActionScript");
1955 c = (character_t*)dict_lookup(&characters, character);
1957 tag = swf_InsertTag(tag, ST_DOINITACTION);
1958 swf_SetU16(tag, c->id);
1959 swf_ActionSet(tag, a);
1964 int s_swf3action(const char*name, const char*action)
1967 instance_t* object = 0;
1969 object = (instance_t*)dict_lookup(&instances, name);
1970 if(!object && name && *name) {
1971 /* we have a name, but couldn't find it. Abort. */
1974 a = action_SetTarget(0, name);
1975 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1976 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1977 else if(!strcmp(action, "stop")) a = action_Stop(a);
1978 else if(!strcmp(action, "play")) a = action_Play(a);
1979 a = action_SetTarget(a, "");
1982 tag = swf_InsertTag(tag, ST_DOACTION);
1983 swf_ActionSet(tag, a);
1988 void s_outline(const char*name, const char*format, const char*source)
1990 if(dict_lookup(&outlines, name))
1991 syntaxerror("outline %s defined twice", name);
2000 //swf_Shape10DrawerInit(&draw, 0);
2001 swf_Shape11DrawerInit(&draw, 0);
2003 draw_string(&draw, source);
2005 shape = swf_ShapeDrawerToShape(&draw);
2006 bounds = swf_ShapeDrawerGetBBox(&draw);
2007 draw.dealloc(&draw);
2009 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
2010 outline->shape = shape;
2011 outline->bbox = bounds;
2013 dict_put(&outlines, name, outline);
2016 int s_playsound(const char*name, int loops, int nomultiple, int stop)
2022 sound = dict_lookup(&sounds, name);
2026 tag = swf_InsertTag(tag, ST_STARTSOUND);
2027 swf_SetU16(tag, sound->id); //id
2028 memset(&info, 0, sizeof(info));
2031 info.nomultiple = nomultiple;
2032 swf_SetSoundInfo(tag, &info);
2036 void s_includeswf(const char*name, const char*filename)
2044 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
2045 f = open(filename,O_RDONLY|O_BINARY);
2047 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
2048 s_box(name, 0, 0, black, 20, 0);
2051 if (swf_ReadSWF(f,&swf)<0) {
2052 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
2053 s_box(name, 0, 0, black, 20, 0);
2058 /* FIXME: The following sets the bounding Box for the character.
2059 It is wrong for two reasons:
2060 a) It may be too small (in case objects in the movie clip at the borders)
2061 b) it may be too big (because the poor movie never got autocropped)
2065 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2066 swf_SetU16(tag, id);
2067 swf_SetU16(tag, swf.frameCount);
2069 swf_Relocate(&swf, idmap);
2071 ftag = swf.firstTag;
2075 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2076 if(cutout[t] == ftag->id) {
2080 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2082 if(ftag->id == ST_END)
2087 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2088 /* We simply dump all tags right after the sprite
2089 header, relying on the fact that swf_OptimizeTagOrder() will
2090 sort things out for us later.
2091 We also rely on the fact that the imported SWF is well-formed.
2093 tag = swf_InsertTag(tag, ftag->id);
2094 swf_SetBlock(tag, ftag->data, ftag->len);
2100 syntaxerror("Included file %s contains errors", filename);
2101 tag = swf_InsertTag(tag, ST_END);
2105 s_addcharacter(name, id, tag, r);
2108 SRECT s_getCharBBox(const char*name)
2110 character_t* c = dict_lookup(&characters, name);
2111 if(!c) syntaxerror("character '%s' unknown(2)", name);
2114 SRECT s_getInstanceBBox(const char*name)
2116 instance_t * i = dict_lookup(&instances, name);
2118 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2120 if(!c) syntaxerror("internal error(5)");
2123 void s_getParameters(const char*name, parameters_t* p)
2125 instance_t * i = dict_lookup(&instances, name);
2127 syntaxerror("instance '%s' unknown(10)", name);
2128 if (change_sets_all)
2129 readParameters(i->history, p, currentframe);
2134 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2136 history_begin(i->history, "x", currentframe, tag, p->x);
2137 history_begin(i->history, "y", currentframe, tag, p->y);
2138 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2139 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2140 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2141 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2142 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2143 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2144 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2145 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2146 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2147 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2148 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2149 history_begin(i->history, "shear", currentframe, tag, p->shear);
2150 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2151 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2152 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2153 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2154 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2155 history_beginFilter(i->history, currentframe, tag, p->filters);
2156 history_begin(i->history, "flags", currentframe, tag, 0);
2159 void s_startclip(const char*instance, const char*character, parameters_t p)
2161 character_t* c = dict_lookup(&characters, character);
2165 syntaxerror("character %s not known", character);
2167 i = s_addinstance(instance, c, currentdepth);
2169 m = s_instancepos(i->character->size, &p);
2171 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2172 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2173 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2175 stack[stackpos].tag = tag;
2176 stack[stackpos].type = 2;
2179 setStartparameters(i, &p, tag);
2186 swf_SetTagPos(stack[stackpos].tag, 0);
2187 swf_GetPlaceObject(stack[stackpos].tag, &p);
2188 p.clipdepth = currentdepth;
2190 swf_ClearTag(stack[stackpos].tag);
2191 swf_SetPlaceObject(stack[stackpos].tag, &p);
2195 void s_put(const char*instance, const char*character, parameters_t p)
2197 character_t* c = dict_lookup(&characters, character);
2201 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2203 i = s_addinstance(instance, c, currentdepth);
2205 m = s_instancepos(i->character->size, &p);
2207 if(p.blendmode || p.filters)
2209 if(stack[0].swf->fileVersion < 8)
2212 warning("blendmodes only supported for flash version>=8");
2214 warning("filters only supported for flash version>=8");
2216 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2219 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2220 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2221 setStartparameters(i, &p, tag);
2225 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2228 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2230 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2231 if (p.set & SF_SCALEX)
2232 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2233 if (p.set & SF_SCALEY)
2234 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2235 if (p.set & SF_CX_R)
2237 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2238 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2240 if (p.set & SF_CX_G)
2242 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2243 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2245 if (p.set & SF_CX_B)
2247 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2248 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2250 if (p.set & SF_CX_A)
2252 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2253 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2255 if (p.set & SF_ROTATE)
2256 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2257 if (p.set & SF_SHEAR)
2258 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2259 if (p.set & SF_PIVOT)
2261 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2262 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2266 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2267 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2269 if (p.set & SF_BLEND)
2270 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2271 if (p.set & SF_FILTER)
2272 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2275 void s_jump(const char* instance, parameters_t p)
2277 instance_t* i = dict_lookup(&instances, instance);
2279 syntaxerror("instance %s not known", instance);
2280 recordChanges(i->history, p, CF_JUMP, 0);
2283 void s_change(const char*instance, parameters_t p, interpolation_t* inter)
2285 instance_t* i = dict_lookup(&instances, instance);
2287 syntaxerror("instance %s not known", instance);
2288 recordChanges(i->history, p, CF_CHANGE, inter);
2291 void s_sweep(const char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2293 instance_t* i = dict_lookup(&instances, instance);
2295 syntaxerror("instance %s not known", instance);
2296 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2299 void s_toggle(const char* instance, U16 flagsOn, U16 flagsOff)
2301 instance_t* i = dict_lookup(&instances, instance);
2303 syntaxerror("instance %s not known", instance);
2304 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2307 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2310 void s_delinstance(const char*instance)
2312 instance_t* i = dict_lookup(&instances, instance);
2314 syntaxerror("instance %s not known", instance);
2316 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2317 swf_SetU16(tag, i->depth);
2318 dict_del(&instances, instance);
2322 void s_schange(const char*instance, parameters_t p, interpolation_t* inter)
2324 instance_t* i = dict_lookup(&instances, instance);
2326 syntaxerror("instance %s not known", instance);
2327 recordChanges(i->history, p, CF_SCHANGE, inter);
2333 syntaxerror(".end unexpected");
2334 switch (stack[stackpos-1].type)
2349 syntaxerror("internal error 1");
2353 // ------------------------------------------------------------------------
2355 typedef int command_func_t(map_t*args);
2357 SRECT parseBox(const char*str)
2359 SRECT r = {0,0,0,0};
2360 float xmin, xmax, ymin, ymax;
2361 char*x = strchr(str, 'x');
2363 if(!strcmp(str, "autocrop")) {
2364 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2368 d1 = strchr(x+1, ':');
2370 d2 = strchr(d1+1, ':');
2372 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2376 else if(d1 && !d2) {
2377 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2383 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2388 r.xmin = (SCOORD)(xmin*20);
2389 r.ymin = (SCOORD)(ymin*20);
2390 r.xmax = (SCOORD)(xmax*20);
2391 r.ymax = (SCOORD)(ymax*20);
2394 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2397 float parseFloat(const char*str)
2401 int parseInt(const char*str)
2406 if(str[0]=='+' || str[0]=='-')
2410 if(str[t]<'0' || str[t]>'9')
2411 syntaxerror("Not an Integer: \"%s\"", str);
2414 static double parseRawTwip(const char*str)
2418 if(str[0]=='+' || str[0]=='-') {
2423 dot = strchr(str, '.');
2427 return sign*parseInt(str);
2429 char* old = strdup(str);
2430 int l=strlen(dot+1);
2433 for(s=str;s<dot-1;s++) {
2434 if(*s<'0' || *s>'9')
2437 syntaxerror("Not a coordinate: \"%s\"", str);
2441 if(*s<'0' || *s>'9')
2444 syntaxerror("Not a coordinate: \"%s\"", str);
2447 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2448 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2451 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2455 return sign*(atoi(str));
2457 return sign*(atoi(str)+0.1*atoi(dot));
2459 return sign*(atoi(str)+0.01*atoi(dot));
2464 static dict_t defines;
2465 static int defines_initialized = 0;
2466 static mem_t define_values;
2468 static double parseNameOrTwip(const char*s)
2472 if(defines_initialized) {
2473 l = (int)dict_lookup(&defines, s);
2476 return *(int*)&define_values.buffer[l-1];
2478 return parseRawTwip(s);
2482 /* automatically generated by yiyiyacc, http://www.quiss.org/yiyiyacc/ */
2483 static double parseExpression(char*s)
2486 memset(chr2index, -1, sizeof(chr2index));
2493 chr2index['\0'] = 7;
2501 int left[10]={11,8,8,8,8,9,9,9,10,10}; //production left side
2502 int plen[10]={1,3,2,3,1,3,3,1,1,3}; //production size
2503 int table[18][12] = {
2504 {0, 4, 0, 0, 5, 6, 0, 0, 1, 2, 3, 0},
2505 {7, 8, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0},
2506 {-4, -4, 9, 10, 0, 0, -4, -4, 0, 0, 0, 0},
2507 {-7, -7, -7, -7, 0, 0, -7, -7, 0, 0, 0, 0},
2508 {0, 0, 0, 0, 5, 6, 0, 0, 0, 11, 3, 0},
2509 {-8, -8, -8, -8, 0, 0, -8, -8, 0, 0, 0, 0},
2510 {0, 4, 0, 0, 5, 6, 0, 0, 12, 2, 3, 0},
2511 {0, 0, 0, 0, 5, 6, 0, 0, 0, 13, 3, 0},
2512 {0, 0, 0, 0, 5, 6, 0, 0, 0, 14, 3, 0},
2513 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 15, 0},
2514 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 16, 0},
2515 {-2, -2, 9, 10, 0, 0, -2, -2, 0, 0, 0, 0},
2516 {7, 8, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0},
2517 {-1, -1, 9, 10, 0, 0, -1, -1, 0, 0, 0, 0},
2518 {-3, -3, 9, 10, 0, 0, -3, -3, 0, 0, 0, 0},
2519 {-5, -5, -5, -5, 0, 0, -5, -5, 0, 0, 0, 0},
2520 {-6, -6, -6, -6, 0, 0, -6, -6, 0, 0, 0, 0},
2521 {-9, -9, -9, -9, 0, 0, -9, -9, 0, 0, 0, 0}};
2529 fprintf(stderr, "Error in expression\n");
2533 if(chr2index[*p]<0) {
2534 action = table[stack[stackpos-1]][4];
2536 while(chr2index[*pnext]<0)
2540 value = parseNameOrTwip(p);
2544 action = table[stack[stackpos-1]][chr2index[*p]];
2547 if(action == accept) {
2548 return values[stack[stackpos-1]];
2549 } else if(action>0) { // shift
2551 fprintf(stderr, "Stack overflow while parsing expression\n");
2554 values[stackpos]=value;
2555 stack[stackpos++]=action;
2557 } else if(action<0) { // reduce
2558 stackpos-=plen[-action];
2559 stack[stackpos] = table[stack[stackpos-1]][left[-action]];
2562 values[stackpos] = values[stackpos+0] + values[stackpos+2];
2565 values[stackpos] = 0 - values[stackpos+1];
2568 values[stackpos] = values[stackpos+0] - values[stackpos+2];
2571 values[stackpos] = values[stackpos+0] * values[stackpos+2];
2574 values[stackpos] = values[stackpos+0] / values[stackpos+2];
2577 values[stackpos] = values[stackpos+1];
2582 fprintf(stderr, "Syntax error in expression\n");
2588 int parseTwip(const char*str)
2590 char*str2 = (char*)str;
2591 int v = (int)(parseExpression(str2)*20);
2595 int parseArc(const char* str)
2597 if (!strcmp(str, "short"))
2599 if (!strcmp(str, "long"))
2601 syntaxerror("invalid value for the arc parameter: %s", str);
2605 int parseDir(const char* str)
2607 if (!strcmp(str, "clockwise"))
2609 if (!strcmp(str, "counterclockwise"))
2611 syntaxerror("invalid value for the dir parameter: %s", str);
2615 int isPoint(const char*str)
2617 if(strchr(str, '('))
2623 SPOINT parsePoint(const char*str)
2627 int l = strlen(str);
2628 char*comma = strchr(str, ',');
2629 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2630 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2631 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2632 p.x = parseTwip(tmp);
2633 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2634 p.y = parseTwip(tmp);
2638 int parseColor2(const char*str, RGBA*color)
2640 int l = strlen(str);
2644 struct {unsigned char r,g,b;char*name;} colors[] =
2645 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2646 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2647 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2648 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2649 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2650 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2651 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2652 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2653 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2654 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2655 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2656 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2660 if(str[0]=='#' && (l==7 || l==9)) {
2661 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2663 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2665 color->r = r; color->g = g; color->b = b; color->a = a;
2668 int len=strlen(str);
2670 if(strchr(str, '/')) {
2671 len = strchr(str, '/')-str;
2672 sscanf(str+len+1,"%02x", &alpha);
2674 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2675 if(!strncmp(str, colors[t].name, len)) {
2680 color->r = r; color->g = g; color->b = b; color->a = a;
2686 RGBA parseColor(const char*str)
2689 if(!parseColor2(str, &c))
2690 syntaxerror("Expression '%s' is not a color", str);
2694 typedef struct _muladd {
2699 MULADD parseMulAdd(const char*str)
2702 char* str2 = (char*)malloc(strlen(str)+5);
2709 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2710 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2711 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2712 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2713 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2714 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2715 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2716 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2717 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2718 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2720 syntaxerror("'%s' is not a valid color transform expression", str);
2722 m.add = (int)(add*256);
2723 m.mul = (int)(mul*256);
2728 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2730 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2731 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2733 if(a<-32768) a=-32768;
2734 if(a>32767) a=32767;
2735 if(m<-32768) m=-32768;
2736 if(m>32767) m=32767;
2742 float parsePxOrPercent(const char*fontname, const char*str)
2744 int l = strlen(str);
2745 if(strchr(str, '%'))
2746 return parsePercent(str);
2747 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2748 float p = atof(str);
2749 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2751 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2755 float parsePercent(const char*str)
2757 int l = strlen(str);
2761 return atof(str)/100.0;
2763 syntaxerror("Expression '%s' is not a percentage", str);
2766 int isPercent(const char*str)
2768 return str[strlen(str)-1]=='%';
2770 int parseNewSize(const char*str, int size)
2773 return parsePercent(str)*size;
2775 return (int)(atof(str)*20);
2778 int isColor(char*str)
2781 return parseColor2(str, &c);
2784 static const char* lu(map_t* args, char*name)
2786 const char* value = map_lookup(args, name);
2788 map_dump(args, stdout, "");
2789 syntaxerror("internal error 2: value %s should be set", name);
2794 static int c_flash(map_t*args)
2796 const char* filename = map_lookup(args, "filename");
2797 const char* compressstr = lu(args, "compress");
2798 const char* change_modestr = lu(args, "change-sets-all");
2799 const char* exportstr = lu(args, "export");
2800 SRECT bbox = parseBox(lu(args, "bbox"));
2801 int version = parseInt(lu(args, "version"));
2802 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2803 RGBA color = parseColor(lu(args, "background"));
2806 if(!filename || !*filename) {
2807 /* for compatibility */
2808 filename = map_lookup(args, "name");
2809 if(!filename || !*filename) {
2812 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2813 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2817 if(!filename || override_outputname)
2818 filename = outputname;
2820 if(!strcmp(compressstr, "default"))
2821 compress = version>=6;
2822 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2824 else if(!strcmp(compressstr, "no"))
2826 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2828 if(!strcmp(change_modestr, "yes"))
2829 change_sets_all = 1;
2831 if(strcmp(change_modestr, "no"))
2832 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2834 do_exports=atoi(exportstr);
2835 mainclass=strdup(lu(args, "mainclass"));
2837 s_swf(filename, bbox, version, fps, compress, color);
2840 int isRelative(const char*str)
2842 return !strncmp(str, "<plus>", 6) ||
2843 !strncmp(str, "<minus>", 7);
2845 const char* getOffset(const char*str)
2847 if(!strncmp(str, "<plus>", 6))
2849 if(!strncmp(str, "<minus>", 7))
2851 syntaxerror("internal error (347)");
2854 int getSign(const char*str)
2856 if(!strncmp(str, "<plus>", 6))
2858 if(!strncmp(str, "<minus>", 7))
2860 syntaxerror("internal error (348)");
2864 static dict_t points;
2865 static mem_t mpoints;
2866 static int points_initialized = 0;
2868 static int c_interpolation(map_t *args)
2871 const char* name = lu(args, "name");
2872 if (dict_lookup(&interpolations, name))
2873 syntaxerror("interpolation %s defined twice", name);
2875 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2876 const char* functionstr = lu(args, "function");
2877 inter->function = 0;
2878 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2879 if (!strcmp(functionstr,interpolationFunctions[i]))
2881 inter->function = i + 1;
2884 if (!inter->function)
2885 syntaxerror("unkown interpolation function %s", functionstr);
2886 inter->speed = parseFloat(lu(args, "speed"));
2887 inter->amplitude = parseTwip(lu(args, "amplitude"));
2888 inter->growth = parseFloat(lu(args, "growth"));
2889 inter->bounces = parseInt(lu(args, "bounces"));
2890 inter->damping = parseFloat(lu(args, "damping"));
2891 inter->slope = parseFloat(lu(args, "slope"));
2893 dict_put(&interpolations, name, inter);
2897 SPOINT getPoint(SRECT r, const char*name)
2900 if(!strcmp(name, "center")) {
2902 p.x = (r.xmin + r.xmax)/2;
2903 p.y = (r.ymin + r.ymax)/2;
2906 if (!strcmp(name, "bottom-center")) {
2908 p.x = (r.xmin + r.xmax)/2;
2912 if (!strcmp(name, "top-center")) {
2914 p.x = (r.xmin + r.xmax)/2;
2918 if (!strcmp(name, "top-left")) {
2924 if (!strcmp(name, "top-right")) {
2930 if (!strcmp(name, "bottom-right")) {
2936 if (!strcmp(name, "bottom-left")) {
2942 if (!strcmp(name, "left-center")) {
2945 p.y = (r.ymin + r.ymax)/2;
2948 if (!strcmp(name, "right-center")) {
2951 p.y = (r.ymin + r.ymax)/2;
2956 if(points_initialized)
2957 l = (int)dict_lookup(&points, name);
2959 syntaxerror("Invalid point: \"%s\".", name);
2961 return *(SPOINT*)&mpoints.buffer[l-1];
2965 static int texture2(const char*name, const char*object, map_t*args, int errors)
2968 const char*xstr = map_lookup(args, "x");
2969 const char*ystr = map_lookup(args, "y");
2970 const char*widthstr = map_lookup(args, "width");
2971 const char*heightstr = map_lookup(args, "height");
2972 const char*scalestr = map_lookup(args, "scale");
2973 const char*scalexstr = map_lookup(args, "scalex");
2974 const char*scaleystr = map_lookup(args, "scaley");
2975 const char*rotatestr = map_lookup(args, "rotate");
2976 const char* shearstr = map_lookup(args, "shear");
2977 const char* radiusstr = map_lookup(args, "r");
2979 float scalex = 1.0, scaley = 1.0;
2980 float rotate=0, shear=0;
2982 if(!*xstr && !*ystr) {
2984 syntaxerror("x and y must be set");
2987 if(*scalestr && (*scalexstr || *scaleystr)) {
2988 syntaxerror("scale and scalex/scaley can't both be set");
2991 if((*widthstr || *heightstr) && *radiusstr) {
2992 syntaxerror("width/height and radius can't both be set");
2995 widthstr = radiusstr;
2996 heightstr = radiusstr;
2998 if(!*xstr) xstr="0";
2999 if(!*ystr) ystr="0";
3000 if(!*rotatestr) rotatestr="0";
3001 if(!*shearstr) shearstr="0";
3004 scalex = scaley = parsePercent(scalestr);
3005 } else if(*scalexstr || *scaleystr) {
3006 if(scalexstr) scalex = parsePercent(scalexstr);
3007 if(scaleystr) scaley = parsePercent(scaleystr);
3008 } else if(*widthstr || *heightstr) {
3011 s_getBitmapSize(object, &width, &height);
3013 scalex = (float)parseTwip(widthstr)/(float)width;
3015 scaley = (float)parseTwip(heightstr)/(float)height;
3017 x = parseTwip(xstr);
3018 y = parseTwip(ystr);
3019 rotate = parseFloat(rotatestr);
3020 shear = parseFloat(shearstr);
3022 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
3027 static int c_texture(map_t*args)
3029 const char*name = lu(args, "instance");
3030 const char*object = lu(args, "character");
3031 return texture2(name, object, args, 1);
3034 static int c_gradient(map_t*args)
3036 const char*name = lu(args, "name");
3037 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
3038 int rotate = parseInt(lu(args, "rotate"));
3042 syntaxerror("colon (:) expected");
3044 if(dict_lookup(&gradients, name))
3045 syntaxerror("gradient %s defined twice", name);
3047 s_gradient(name, text, radial, rotate);
3049 /* check whether we also have placement information,
3050 which would make this a positioned gradient.
3051 If there is placement information, texture2() will
3052 add a texture, which has priority over the gradient.
3054 texture2(name, name, args, 0);
3058 static const char* checkFiltername(map_t* args)
3060 const char* name = lu(args, "name");
3061 if (strchr(name, ','))
3062 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
3066 static int c_blur(map_t*args)
3068 const char*name = checkFiltername(args);
3069 const char*blurstr = lu(args, "blur");
3070 const char*blurxstr = lu(args, "blurx");
3071 const char*blurystr = lu(args, "blury");
3072 float blurx=1.0, blury=1.0;
3074 blurx = parseFloat(blurstr);
3075 blury = parseFloat(blurstr);
3078 blurx = parseFloat(blurxstr);
3080 blury = parseFloat(blurystr);
3081 int passes = parseInt(lu(args, "passes"));
3082 s_blur(name, blurx, blury, passes);
3086 static int c_gradientglow(map_t*args)
3088 const char*name = checkFiltername(args);
3089 const char*gradient = lu(args, "gradient");
3090 const char*blurstr = lu(args, "blur");
3091 const char*blurxstr = lu(args, "blurx");
3092 const char*blurystr = lu(args, "blury");
3093 float blurx=1.0, blury=1.0;
3095 blurx = parseFloat(blurstr);
3096 blury = parseFloat(blurstr);
3099 blurx = parseFloat(blurxstr);
3101 blury = parseFloat(blurystr);
3103 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3104 float distance = parseFloat(lu(args, "distance"));
3105 float strength = parseFloat(lu(args, "strength"));
3106 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3107 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3108 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3109 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3110 int passes = parseInt(lu(args, "passes"));
3112 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3116 static int c_dropshadow(map_t*args)
3118 const char*name = checkFiltername(args);
3119 RGBA color = parseColor(lu(args, "color"));
3120 const char*blurstr = lu(args, "blur");
3121 const char*blurxstr = lu(args, "blurx");
3122 const char*blurystr = lu(args, "blury");
3123 float blurx=1.0, blury=1.0;
3125 blurx = parseFloat(blurstr);
3126 blury = parseFloat(blurstr);
3129 blurx = parseFloat(blurxstr);
3131 blury = parseFloat(blurystr);
3133 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3134 float distance = parseFloat(lu(args, "distance"));
3135 float strength = parseFloat(lu(args, "strength"));
3136 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3137 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3138 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3139 int passes = parseInt(lu(args, "passes"));
3141 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3145 static int c_bevel(map_t*args)
3147 const char*name = checkFiltername(args);
3148 RGBA shadow = parseColor(lu(args, "shadow"));
3149 RGBA highlight = parseColor(lu(args, "highlight"));
3150 const char*blurstr = lu(args, "blur");
3151 const char*blurxstr = lu(args, "blurx");
3152 const char*blurystr = lu(args, "blury");
3153 float blurx=1.0, blury=1.0;
3155 blurx = parseFloat(blurstr);
3156 blury = parseFloat(blurstr);
3159 blurx = parseFloat(blurxstr);
3161 blury = parseFloat(blurystr);
3163 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3164 float distance = parseFloat(lu(args, "distance"));
3165 float strength = parseFloat(lu(args, "strength"));
3166 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3167 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3168 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3169 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3170 int passes = parseInt(lu(args, "passes"));
3172 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3176 static int c_define(map_t*args)
3178 const char*name = lu(args, "name");
3179 const char*value = lu(args, "value");
3181 if(!defines_initialized) {
3182 dict_init(&defines, 16);
3183 mem_init(&define_values);
3184 defines_initialized = 1;
3186 int val = parseTwip(value);
3187 int pos = mem_put(&define_values, &val, sizeof(val));
3188 dict_put(&defines, name, (void*)(pos+1));
3191 static int c_point(map_t*args)
3193 const char*name = lu(args, "name");
3196 if(!points_initialized) {
3197 dict_init(&points, 16);
3199 points_initialized = 1;
3201 p.x = parseTwip(lu(args, "x"));
3202 p.y = parseTwip(lu(args, "y"));
3203 pos = mem_put(&mpoints, &p, sizeof(p));
3204 dict_put(&points, name, (void*)(pos+1));
3207 static int c_play(map_t*args)
3209 const char*name = lu(args, "name");
3210 const char*loop = lu(args, "loop");
3211 const char*nomultiple = lu(args, "nomultiple");
3213 if(!strcmp(nomultiple, "nomultiple"))
3216 nm = parseInt(nomultiple);
3218 if(s_playsound(name, parseInt(loop), nm, 0)) {
3220 } else if(s_swf3action(name, "play")) {
3226 static int c_stop(map_t*args)
3228 const char*name = map_lookup(args, "name");
3230 if(s_playsound(name, 0,0,1))
3232 else if(s_swf3action(name, "stop"))
3234 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3238 static int c_nextframe(map_t*args)
3240 const char*name = lu(args, "name");
3242 if(s_swf3action(name, "nextframe")) {
3245 syntaxerror("I don't know anything about movie \"%s\"", name);
3249 static int c_previousframe(map_t*args)
3251 const char*name = lu(args, "name");
3253 if(s_swf3action(name, "previousframe")) {
3256 syntaxerror("I don't know anything about movie \"%s\"", name);
3260 static int c_movement(map_t*args, int type)
3262 const char*instance = lu(args, "name");
3264 const char* xstr="";
3265 const char* ystr="";
3270 xstr = lu(args, "x");
3271 ystr = lu(args, "y");
3273 s_getParameters(instance, &p);
3278 if(isRelative(xstr))
3280 if(type == PT_PUT || type == PT_STARTCLIP)
3281 syntaxerror("relative x values not allowed for initial put or startclip");
3282 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3286 p.x = parseTwip(xstr);
3292 if(isRelative(ystr))
3294 if(type == PT_PUT || type == PT_STARTCLIP)
3295 syntaxerror("relative y values not allowed for initial put or startclip");
3296 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3300 p.y = parseTwip(ystr);
3305 if (change_sets_all)
3313 const char* interstr = lu(args, "interpolation");
3314 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3316 syntaxerror("unkown interpolation %s", interstr);
3317 s_change(instance, p, inter);
3322 const char* interstr = lu(args, "interpolation");
3323 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3325 syntaxerror("unkown interpolation %s", interstr);
3326 s_schange(instance, p, inter);
3331 const char* rstr = lu(args, "r");
3332 int radius = parseTwip(rstr);
3334 syntaxerror("sweep not possible: radius must be greater than 0.");
3335 const char* dirstr = lu(args, "dir");
3336 int clockwise = parseDir(dirstr);
3337 const char* arcstr = lu(args, "arc");
3338 int short_arc = parseArc(arcstr);
3339 const char* interstr = lu(args, "interpolation");
3340 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3342 syntaxerror("unkown interpolation %s", interstr);
3343 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3350 static int c_placement(map_t*args, int type)
3352 const char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3353 const char*character = 0;
3355 const char* luminancestr = lu(args, "luminance");
3356 const char* scalestr = lu(args, "scale");
3357 const char* scalexstr = lu(args, "scalex");
3358 const char* scaleystr = lu(args, "scaley");
3359 const char* rotatestr = lu(args, "rotate");
3360 const char* shearstr = lu(args, "shear");
3361 const char* xstr="", *pivotstr="";
3362 const char* ystr="", *anglestr="";
3363 const char*above = lu(args, "above"); /*FIXME*/
3364 const char*below = lu(args, "below");
3365 const char* rstr = lu(args, "red");
3366 const char* gstr = lu(args, "green");
3367 const char* bstr = lu(args, "blue");
3368 const char* astr = lu(args, "alpha");
3369 const char* pinstr = lu(args, "pin");
3370 const char* as = map_lookup(args, "as");
3371 const char* blendmode = lu(args, "blend");
3372 const char* filterstr = lu(args, "filter");
3383 { // (?) .rotate or .arcchange
3384 pivotstr = lu(args, "pivot");
3385 anglestr = lu(args, "angle");
3389 xstr = lu(args, "x");
3390 ystr = lu(args, "y");
3394 luminance = parseMulAdd(luminancestr);
3398 luminance.mul = 256;
3403 if(scalexstr[0]||scaleystr[0])
3404 syntaxerror("scalex/scaley and scale cannot both be set");
3405 scalexstr = scaleystr = scalestr;
3408 if(type == PT_PUT || type == PT_STARTCLIP) {
3410 character = lu(args, "character");
3411 parameters_clear(&p);
3412 } else if (type == PT_BUTTON) {
3413 character = lu(args, "name");
3414 parameters_clear(&p);
3417 s_getParameters(instance, &p);
3423 if(isRelative(xstr))
3425 if(type == PT_PUT || type == PT_STARTCLIP)
3426 syntaxerror("relative x values not allowed for initial put or startclip");
3427 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3431 p.x = parseTwip(xstr);
3437 if(isRelative(ystr))
3439 if(type == PT_PUT || type == PT_STARTCLIP)
3440 syntaxerror("relative y values not allowed for initial put or startclip");
3441 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3445 p.y = parseTwip(ystr);
3450 /* scale, scalex, scaley */
3452 oldbbox = s_getCharBBox(character);
3454 oldbbox = s_getInstanceBBox(instance);
3455 oldwidth = oldbbox.xmax - oldbbox.xmin;
3456 oldheight = oldbbox.ymax - oldbbox.ymin;
3463 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3464 set = set | SF_SCALEX;
3472 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3473 set = set | SF_SCALEY;
3479 if(isRelative(rotatestr))
3480 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3482 p.rotate = parseFloat(rotatestr);
3483 set = set | SF_ROTATE;
3489 if(isRelative(shearstr))
3490 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3492 p.shear = parseFloat(shearstr);
3493 set = set | SF_SHEAR;
3498 if(isPoint(pivotstr))
3499 p.pivot = parsePoint(pivotstr);
3501 p.pivot = getPoint(oldbbox, pivotstr);
3502 set = set | SF_PIVOT;
3508 p.pin = parsePoint(pinstr);
3510 p.pin = getPoint(oldbbox, pinstr);
3514 /* color transform */
3516 if(rstr[0] || luminancestr[0])
3520 r = parseMulAdd(rstr);
3523 r.add = p.cxform.r0;
3524 r.mul = p.cxform.r1;
3526 r = mergeMulAdd(r, luminance);
3527 p.cxform.r0 = r.mul;
3528 p.cxform.r1 = r.add;
3529 set = set | SF_CX_R;
3531 if(gstr[0] || luminancestr[0])
3535 g = parseMulAdd(gstr);
3538 g.add = p.cxform.g0;
3539 g.mul = p.cxform.g1;
3541 g = mergeMulAdd(g, luminance);
3542 p.cxform.g0 = g.mul;
3543 p.cxform.g1 = g.add;
3544 set = set | SF_CX_G;
3546 if(bstr[0] || luminancestr[0])
3550 b = parseMulAdd(bstr);
3553 b.add = p.cxform.b0;
3554 b.mul = p.cxform.b1;
3556 b = mergeMulAdd(b, luminance);
3557 p.cxform.b0 = b.mul;
3558 p.cxform.b1 = b.add;
3559 set = set | SF_CX_B;
3563 MULADD a = parseMulAdd(astr);
3564 p.cxform.a0 = a.mul;
3565 p.cxform.a1 = a.add;
3566 set = set | SF_CX_A;
3573 for(t = 0; blendModeNames[t]; t++)
3575 if(!strcmp(blendModeNames[t], blendmode))
3583 syntaxerror("unknown blend mode: '%s'", blendmode);
3585 p.blendmode = blend;
3586 set = set | SF_BLEND;
3591 p.filters = parseFilters((char*)filterstr);
3592 set = set | SF_FILTER;
3595 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3596 warning("As of version 0.8.2 using the .change command to modify an \
3597 object's position on the stage is considered deprecated. Future \
3598 versions may consider x and y parameters for the .change command \
3599 to be illegal; please use the .move command.");
3601 if (change_sets_all)
3608 s_put(instance, character, p);
3612 const char* interstr = lu(args, "interpolation");
3613 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3615 syntaxerror("unkown interpolation %s", interstr);
3616 s_change(instance, p, inter);
3621 const char* interstr = lu(args, "interpolation");
3622 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3624 syntaxerror("unkown interpolation %s", interstr);
3625 s_schange(instance, p, inter);
3629 s_jump(instance, p);
3632 s_startclip(instance, character, p);
3636 s_buttonput(character, as, p);
3638 s_buttonput(character, "shape", p);
3644 static int c_put(map_t*args)
3646 c_placement(args, PT_PUT);
3649 static int c_change(map_t*args)
3651 if (currentframe == 0)
3652 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3653 c_placement(args, PT_CHANGE);
3656 static int c_schange(map_t*args)
3658 c_placement(args, PT_SCHANGE);
3661 static int c_move(map_t* args)
3663 c_movement(args, PT_MOVE);
3666 static int c_smove(map_t* args)
3668 c_movement(args, PT_SMOVE);
3671 static int c_sweep(map_t* args)
3673 c_movement(args, PT_SWEEP);
3676 static int c_arcchange(map_t*args)
3678 c_placement(args, 0);
3681 static int c_jump(map_t*args)
3683 c_placement(args, PT_JUMP);
3686 static int c_startclip(map_t*args)
3688 c_placement(args, PT_STARTCLIP);
3691 static int c_show(map_t*args)
3693 c_placement(args, PT_BUTTON);
3696 static int c_toggle(map_t* args)
3698 const char*instance = lu(args, "name");
3699 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3700 const char* alignstr = lu(args, "fixed_alignment");
3701 if (!strcmp(alignstr, "on"))
3702 flagsOn += IF_FIXED_ALIGNMENT;
3704 if (!strcmp(alignstr, "off"))
3705 flagsOff -= IF_FIXED_ALIGNMENT;
3707 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3708 s_toggle(instance, flagsOn, flagsOff);
3711 static int c_del(map_t*args)
3713 const char*instance = lu(args, "name");
3714 s_delinstance(instance);
3717 static int c_end(map_t*args)
3722 static int c_sprite(map_t*args)
3724 const char* name = lu(args, "name");
3725 const char* scalinggrid = lu(args, "scalinggrid");
3726 const char* as3name = lu(args, "as3name");
3728 if(scalinggrid && *scalinggrid) {
3729 SRECT r = parseBox(scalinggrid);
3730 s_sprite(name, &r, as3name);
3732 s_sprite(name, 0, as3name);
3736 static int c_frame(map_t*args)
3738 const char*framestr = lu(args, "n");
3739 const char*cutstr = lu(args, "cut");
3741 const char*name = lu(args, "name");
3742 const char*anchor = lu(args, "anchor");
3745 if(!strcmp(anchor, "anchor") && !*name)
3750 if(strcmp(cutstr, "no"))
3752 if(isRelative(framestr)) {
3753 frame = s_getframe();
3754 if(getSign(framestr)<0)
3755 syntaxerror("relative frame expressions must be positive");
3756 frame += parseInt(getOffset(framestr));
3759 frame = parseInt(framestr);
3760 if(s_getframe() >= frame
3761 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3762 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3764 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3767 static int c_primitive(map_t*args)
3769 const char*name = lu(args, "name");
3770 const char*command = lu(args, "commandname");
3771 int width=0, height=0, r=0;
3772 int linewidth = parseTwip(lu(args, "line"));
3773 const char*colorstr = lu(args, "color");
3774 RGBA color = parseColor(colorstr);
3775 const char*fillstr = lu(args, "fill");
3780 const char* outline=0;
3782 if(!strcmp(command, "circle"))
3784 else if(!strcmp(command, "filled"))
3788 width = parseTwip(lu(args, "width"));
3789 height = parseTwip(lu(args, "height"));
3790 } else if (type==1) {
3791 r = parseTwip(lu(args, "r"));
3792 } else if (type==2) {
3793 outline = lu(args, "outline");
3796 if(!strcmp(fillstr, "fill"))
3798 if(!strcmp(fillstr, "none"))
3800 if(width<0 || height<0 || linewidth<0 || r<0)
3801 syntaxerror("values width, height, line, r must be positive");
3803 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3804 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3805 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3809 static int c_textshape(map_t*args)
3811 const char*name = lu(args, "name");
3812 const char*text = lu(args, "text");
3813 const char*font = lu(args, "font");
3814 float size = parsePxOrPercent(font, lu(args, "size"));
3816 s_textshape(name, font, size, text);
3820 static int c_swf(map_t*args)
3822 const char*name = lu(args, "name");
3823 const char*filename = lu(args, "filename");
3824 const char*command = lu(args, "commandname");
3825 if(!strcmp(command, "shape"))
3826 warning("Please use .swf instead of .shape");
3827 s_includeswf(name, filename);
3831 static int c_font(map_t*args)
3833 const char*name = lu(args, "name");
3834 const char*filename = lu(args, "filename");
3835 s_font(name, filename);
3839 static int c_sound(map_t*args)
3841 const char*name = lu(args, "name");
3842 const char*filename = lu(args, "filename");
3843 s_sound(name, filename);
3847 static int c_text(map_t*args)
3849 const char*name = lu(args, "name");
3850 const char*text = lu(args, "text");
3851 const char*font = lu(args, "font");
3852 float size = parsePxOrPercent(font, lu(args, "size"));
3853 RGBA color = parseColor(lu(args, "color"));
3854 s_text(name, font, text, (int)(size*100), color);
3858 static int c_soundtrack(map_t*args)
3863 static int c_quicktime(map_t*args)
3865 const char*name = lu(args, "name");
3866 const char*url = lu(args, "url");
3867 s_quicktime(name, url);
3871 static int c_video(map_t*args)
3873 const char*name = lu(args, "name");
3874 int width = parseInt(lu(args, "width"));
3875 int height = parseInt(lu(args, "height"));
3876 s_video(name, width, height);
3880 static int c_image(map_t*args)
3882 const char*command = lu(args, "commandname");
3883 const char*name = lu(args, "name");
3884 const char*filename = lu(args, "filename");
3885 if(!strcmp(command,"jpeg")) {
3886 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3887 s_image(name, "jpeg", filename, quality);
3889 s_image(name, "png", filename, 0);
3894 static int c_outline(map_t*args)
3896 const char*name = lu(args, "name");
3897 const char*format = lu(args, "format");
3901 syntaxerror("colon (:) expected");
3903 s_outline(name, format, text);
3907 int fakechar(map_t*args)
3909 const char*name = lu(args, "name");
3910 s_box(name, 0, 0, black, 20, 0);
3914 static int c_egon(map_t*args) {return fakechar(args);}
3915 static int c_button(map_t*args) {
3916 const char*name = lu(args, "name");
3917 const char*as3name = lu(args, "as3name");
3918 s_button(name, as3name);
3921 static int current_button_flags = 0;
3922 static int c_on_press(map_t*args)
3924 const char*position = lu(args, "position");
3925 const char*action = "";
3926 if(!strcmp(position, "inside")) {
3927 current_button_flags |= BC_OVERUP_OVERDOWN;
3928 } else if(!strcmp(position, "outside")) {
3929 //current_button_flags |= BC_IDLE_OUTDOWN;
3930 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3931 } else if(!strcmp(position, "anywhere")) {
3932 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3935 if(type == RAWDATA) {
3937 s_buttonaction(current_button_flags, action);
3938 current_button_flags = 0;
3944 static int c_on_release(map_t*args)
3946 const char*position = lu(args, "position");
3947 const char*action = "";
3948 if(!strcmp(position, "inside")) {
3949 current_button_flags |= BC_OVERDOWN_OVERUP;
3950 } else if(!strcmp(position, "outside")) {
3951 current_button_flags |= BC_OUTDOWN_IDLE;
3952 } else if(!strcmp(position, "anywhere")) {
3953 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3956 if(type == RAWDATA) {
3958 s_buttonaction(current_button_flags, action);
3959 current_button_flags = 0;
3965 static int c_on_move_in(map_t*args)
3967 const char*position = lu(args, "state");
3968 const char*action = "";
3969 if(!strcmp(position, "pressed")) {
3970 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3971 } else if(!strcmp(position, "not_pressed")) {
3972 current_button_flags |= BC_IDLE_OVERUP;
3973 } else if(!strcmp(position, "any")) {
3974 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3977 if(type == RAWDATA) {
3979 s_buttonaction(current_button_flags, action);
3980 current_button_flags = 0;
3986 static int c_on_move_out(map_t*args)
3988 const char*position = lu(args, "state");
3989 const char*action = "";
3990 if(!strcmp(position, "pressed")) {
3991 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3992 } else if(!strcmp(position, "not_pressed")) {
3993 current_button_flags |= BC_OVERUP_IDLE;
3994 } else if(!strcmp(position, "any")) {
3995 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3998 if(type == RAWDATA) {
4000 s_buttonaction(current_button_flags, action);
4001 current_button_flags = 0;
4007 static int c_on_key(map_t*args)
4009 const char*key = lu(args, "key");
4010 const char*action = "";
4011 if(strlen(key)==1) {
4014 current_button_flags |= 0x4000 + (key[0]*0x200);
4016 syntaxerror("invalid character: %c"+key[0]);
4021 <ctrl-x> = 0x200*(x-'a')
4025 syntaxerror("invalid key: %s",key);
4028 if(type == RAWDATA) {
4030 s_buttonaction(current_button_flags, action);
4031 current_button_flags = 0;
4038 static int c_edittext(map_t*args)
4040 //"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"},
4041 const char*name = lu(args, "name");
4042 const char*font = lu(args, "font");
4043 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
4044 int width = parseTwip(lu(args, "width"));
4045 int height = parseTwip(lu(args, "height"));
4046 const char*text = lu(args, "text");
4047 RGBA color = parseColor(lu(args, "color"));
4048 int maxlength = parseInt(lu(args, "maxlength"));
4049 const char*variable = lu(args, "variable");
4050 const char*passwordstr = lu(args, "password");
4051 const char*wordwrapstr = lu(args, "wordwrap");
4052 const char*multilinestr = lu(args, "multiline");
4053 const char*htmlstr = lu(args, "html");
4054 const char*noselectstr = lu(args, "noselect");
4055 const char*readonlystr = lu(args, "readonly");
4056 const char*borderstr = lu(args, "border");
4057 const char*autosizestr = lu(args, "autosize");
4058 const char*alignstr = lu(args, "align");
4062 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
4063 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
4064 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
4065 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
4066 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
4067 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
4068 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
4069 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
4070 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
4071 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
4072 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
4073 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
4074 else syntaxerror("Unknown alignment: %s", alignstr);
4076 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
4080 static int c_morphshape(map_t*args) {return fakechar(args);}
4081 static int c_movie(map_t*args) {return fakechar(args);}
4083 static char* readfile(char*filename)
4085 FILE*fi = fopen(filename, "rb");
4089 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
4090 fseek(fi, 0, SEEK_END);
4092 fseek(fi, 0, SEEK_SET);
4093 text = rfx_alloc(l+1);
4094 fread(text, l, 1, fi);
4100 static int c_action(map_t*args)
4102 const char* filename = map_lookup(args, "filename");
4103 if(!filename ||!*filename) {
4105 if(type != RAWDATA) {
4106 syntaxerror("colon (:) expected");
4110 s_action(readfile((char*)filename));
4116 static int c_initaction(map_t*args)
4118 const char* character = lu(args, "name");
4119 const char* filename = map_lookup(args, "filename");
4120 if(!filename ||!*filename) {
4122 if(type != RAWDATA) {
4123 syntaxerror("colon (:) expected");
4125 s_initaction(character, text);
4127 s_initaction(character, readfile((char*)filename));
4135 command_func_t* func;
4138 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1 @mainclass="},
4139 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
4140 // "import" type stuff
4141 {"swf", c_swf, "name filename"},
4142 {"shape", c_swf, "name filename"},
4143 {"jpeg", c_image, "name filename quality=80%"},
4144 {"png", c_image, "name filename"},
4145 {"movie", c_movie, "name filename"},
4146 {"sound", c_sound, "name filename"},
4147 {"font", c_font, "name filename glyphs="},
4148 {"soundtrack", c_soundtrack, "filename"},
4149 {"quicktime", c_quicktime, "url"},
4150 {"video", c_video, "name width= height="},
4152 // generators of primitives
4154 {"define", c_define, "name value=0"},
4155 {"point", c_point, "name x=0 y=0"},
4156 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4157 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4158 {"outline", c_outline, "name format=simple"},
4159 {"textshape", c_textshape, "name font size=100% text"},
4162 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4163 {"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"},
4164 {"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"},
4165 {"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"},
4167 // character generators
4168 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4169 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4170 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4172 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4173 {"text", c_text, "name text font size=100% color=white"},
4174 {"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="},
4175 {"morphshape", c_morphshape, "name start end"},
4176 {"button", c_button, "name as3name="},
4177 {"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="},
4178 {"on_press", c_on_press, "position=inside"},
4179 {"on_release", c_on_release, "position=anywhere"},
4180 {"on_move_in", c_on_move_in, "state=not_pressed"},
4181 {"on_move_out", c_on_move_out, "state=not_pressed"},
4182 {"on_key", c_on_key, "key=any"},
4185 {"play", c_play, "name loop=0 @nomultiple=0"},
4186 {"stop", c_stop, "name= "},
4187 {"nextframe", c_nextframe, "name"},
4188 {"previousframe", c_previousframe, "name"},
4190 // object placement tags
4191 {"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="},
4192 {"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="},
4193 {"move", c_move, "name x= y= interpolation=linear"},
4194 {"smove", c_smove, "name x= y= interpolation=linear"},
4195 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4196 {"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"},
4197 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4198 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4199 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4200 {"del", c_del, "name"},
4201 // virtual object placement
4202 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4204 {"toggle", c_toggle, "name fixed_alignment="},
4206 // commands which start a block
4207 //startclip (see above)
4208 {"sprite", c_sprite, "name scalinggrid= as3name="},
4209 {"action", c_action, "filename="},
4210 {"initaction", c_initaction, "name filename="},
4216 static map_t parseArguments(char*command, char*pattern)
4232 string_set(&t1, "commandname");
4233 string_set(&t2, command);
4234 map_put(&result, t1, t2);
4236 if(!pattern || !*pattern)
4243 if(!strncmp("<i> ", x, 3)) {
4245 if(type == COMMAND || type == RAWDATA) {
4247 syntaxerror("character name expected");
4249 name[pos].str = "instance";
4251 value[pos].str = text;
4252 value[pos].len = strlen(text);
4256 if(type == ASSIGNMENT)
4259 name[pos].str = "character";
4261 value[pos].str = text;
4262 value[pos].len = strlen(text);
4270 isboolean[pos] = (x[0] =='@');
4283 name[pos].len = d-x;
4288 name[pos].len = e-x;
4289 value[pos].str = e+1;
4290 value[pos].len = d-e-1;
4298 /* for(t=0;t<len;t++) {
4299 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4300 isboolean[t]?"(boolean)":"");
4305 if(type == RAWDATA || type == COMMAND) {
4310 // first, search for boolean arguments
4311 for(pos=0;pos<len;pos++)
4313 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4315 if(type == ASSIGNMENT)
4317 value[pos].str = text;
4318 value[pos].len = strlen(text);
4319 /*printf("setting boolean parameter %s (to %s)\n",
4320 strdup_n(name[pos], namelen[pos]),
4321 strdup_n(value[pos], valuelen[pos]));*/
4326 // second, search for normal arguments
4328 for(pos=0;pos<len;pos++)
4330 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4331 (type != ASSIGNMENT && !set[pos])) {
4333 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4335 if(type == ASSIGNMENT)
4338 value[pos].str = text;
4339 value[pos].len = strlen(text);
4341 printf("setting parameter %s (to %s)\n",
4342 strdup_n(name[pos].str, name[pos].len),
4343 strdup_n(value[pos].str, value[pos].len));
4349 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4353 for(t=0;t<len;t++) {
4354 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4357 for(t=0;t<len;t++) {
4358 if(value[t].str && value[t].str[0] == '*') {
4359 //relative default- take value from some other parameter
4361 for(s=0;s<len;s++) {
4362 if(value[s].len == value[t].len-1 &&
4363 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4364 value[t].str = value[s].str;
4367 if(value[t].str == 0) {
4369 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4373 /* ok, now construct the dictionary from the parameters */
4377 map_put(&result, name[t], value[t]);
4381 static void parseArgumentsForCommand(char*command)
4386 msg("<verbose> parse Command: %s (line %d)", command, line);
4388 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4389 if(!strcmp(arguments[t].command, command)) {
4391 /* ugly hack- will be removed soon (once documentation and .sc generating
4392 utilities have been changed) */
4393 if(!strcmp(command, "swf") && !stackpos) {
4394 warning("Please use .flash instead of .swf- this will be mandatory soon");
4399 args = parseArguments(command, arguments[t].arguments);
4405 syntaxerror("command %s not known", command);
4408 // catch missing .flash directives at the beginning of a file
4409 if(strcmp(command, "flash") && !stackpos)
4411 syntaxerror("No movie defined- use .flash first");
4416 printf(".%s\n", command);fflush(stdout);
4417 map_dump(&args, stdout, "\t");fflush(stdout);
4421 (*arguments[nr].func)(&args);
4423 if(!strcmp(command, "action") || !strcmp(command, "initaction") ||
4424 !strcmp(command, "outline") || !strcmp(command, "gradient")) {
4426 if(type != RAWDATA) {
4427 syntaxerror("colon (:) expected");
4436 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4437 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4438 * No syntax checking is done */
4439 static void analyseArgumentsForCommand(char*command)
4443 const char* fontfile;
4445 U8* glyphs_to_include;
4446 msg("<verbose> analyse Command: %s (line %d)", command, line);
4448 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4450 if(!strcmp(arguments[t].command, command))
4452 args = parseArguments(command, arguments[t].arguments);
4458 printf(".%s\n", command);fflush(stdout);
4459 map_dump(&args, stdout, "\t");fflush(stdout);
4461 const char* name = lu(&args, "name");
4462 if (!strcmp(command, "font"))
4464 if(dict_lookup(&fonts, name))
4465 syntaxerror("font %s defined twice", name);
4468 fontfile = lu(&args, "filename");
4469 font = swf_LoadFont(fontfile);
4471 warning("Couldn't open font file \"%s\"", fontfile);
4472 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4473 memset(font, 0, sizeof(SWFFONT));
4477 swf_FontPrepareForEditText(font);
4478 glyphs_to_include = (U8*)lu(&args, "glyphs");
4479 if (!strcmp(glyphs_to_include, "all"))
4481 swf_FontUseAll(font);
4482 font->use->glyphs_specified = 1;
4486 if (strcmp (glyphs_to_include, ""))
4488 swf_FontUseUTF8(font, glyphs_to_include, /*FIXME*/0xffff);
4489 font->use->glyphs_specified = 1;
4492 swf_FontInitUsage(font);
4495 dict_put(&fonts, name, font);
4499 SWFFONT* font = dict_lookup(&fonts, lu(&args, "font"));
4501 //that's ok... it might be an edittext with a system font
4502 //syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4504 if (font->use && !font->use->glyphs_specified)
4506 if (!strcmp(command, "edittext"))
4508 swf_FontUseAll(font);
4509 font->use->glyphs_specified = 1;
4512 swf_FontUseUTF8(font, (U8*)lu(&args, "text"), 0xffff);
4519 void skipParameters()
4523 while (type != COMMAND);
4527 void findFontUsage()
4529 char* fontRelated = "font;text;textshape;edittext;";
4530 while(!noMoreTokens())
4534 syntaxerror("command expected");
4535 if (strstr(fontRelated, text))
4536 analyseArgumentsForCommand(text);
4538 if(strcmp(text, "end"))
4547 dict_init(&fonts, 16);
4548 cleanUp = &freeFontDictionary;
4552 int main (int argc,char ** argv)
4555 processargs(argc, argv);
4556 initLog(0,-1,0,0,-1,verbose);
4559 args_callback_usage(argv[0]);
4563 file = generateTokens(filename);
4565 fprintf(stderr, "parser returned error.\n");
4572 while(!noMoreTokens()) {
4575 syntaxerror("command expected");
4576 parseArgumentsForCommand(text);