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 */
1468 unsigned width, height;
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_createfont(const char*name, const char*filename, const char*glyphs, char flashtype)
1594 if(dict_lookup(&fonts, name))
1595 syntaxerror("font %s defined twice", name);
1597 SWFFONT* font = swf_LoadFont(filename, flashtype);
1599 warning("Couldn't open font file \"%s\"", filename);
1600 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1601 memset(font, 0, sizeof(SWFFONT));
1602 dict_put(&fonts, name, font);
1605 swf_FontPrepareForEditText(font);
1607 if(!strcmp(glyphs, "all")) {
1608 swf_FontUseAll(font);
1609 font->use->glyphs_specified = 1;
1612 swf_FontInitUsage(font);
1614 swf_FontUseUTF8(font, (const U8*)glyphs, 0xffff);
1615 font->use->glyphs_specified = 1;
1618 dict_put(&fonts, name, font);
1621 void s_font(const char*name, const char*filename)
1624 font = dict_lookup(&fonts, name);
1626 swf_FontReduce_swfc(font);
1628 if(font->version>=3 && stack[0].swf->fileVersion < 8) {
1629 warning("flashtype not supported for flash versions 8 and below");
1632 tag = swf_InsertTag(tag, font->version==3?ST_DEFINEFONT3:ST_DEFINEFONT2);
1633 swf_FontSetDefine2(tag, font);
1636 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1638 swf_SetU16(tag, id);
1639 swf_SetString(tag, name);
1647 typedef struct _sound_t
1653 void s_sound(const char*name, const char*filename)
1655 struct WAV wav, wav2;
1659 unsigned numsamples = 1;
1660 unsigned blocksize = 1152;
1663 if(dict_lookup(&sounds, name))
1664 syntaxerror("sound %s defined twice", name);
1666 if(wav_read(&wav, filename))
1669 wav_convert2mono(&wav, &wav2, 44100);
1670 samples = (U16*)wav2.data;
1671 numsamples = wav2.size/2;
1673 #ifdef WORDS_BIGENDIAN
1675 for(t=0;t<numsamples;t++)
1676 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1680 if(mp3_read(&mp3, filename))
1682 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1688 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1693 if(numsamples%blocksize != 0)
1695 // apply padding, so that block is a multiple of blocksize
1696 int numblocks = (numsamples+blocksize-1)/blocksize;
1699 numsamples2 = numblocks * blocksize;
1700 samples2 = malloc(sizeof(U16)*numsamples2);
1701 memcpy(samples2, samples, numsamples*sizeof(U16));
1702 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1703 numsamples = numsamples2;
1708 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1709 swf_SetU16(tag, id); //id
1712 swf_SetSoundDefineMP3(
1713 tag, mp3.data, mp3.size,
1720 swf_SetSoundDefine(tag, samples, numsamples);
1723 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1724 swf_SetU16(tag, id);
1725 swf_SetString(tag, name);
1726 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1728 swf_SetU16(tag, id);
1729 swf_SetString(tag, name);
1732 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1736 dict_put(&sounds, name, sound);
1744 static char* gradient_getToken(const char**p)
1748 while(**p && strchr(" \t\n\r", **p)) {
1752 while(**p && !strchr(" \t\n\r", **p)) {
1755 result = malloc((*p)-start+1);
1756 memcpy(result,start,(*p)-start+1);
1757 result[(*p)-start] = 0;
1761 float parsePercent(const char*str);
1762 RGBA parseColor(const char*str);
1764 GRADIENT parseGradient(const char*str)
1768 const char* p = str;
1769 memset(&gradient, 0, sizeof(GRADIENT));
1770 gradient.ratios = rfx_calloc(16*sizeof(U8));
1771 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1775 char*posstr,*colorstr;
1778 posstr = gradient_getToken(&p);
1784 pos = (int)(parsePercent(posstr)*255.0);
1789 rfx_free(gradient.ratios);
1790 rfx_free(gradient.rgba);
1792 syntaxerror("Error in shape data: Color expected after %s", posstr);
1794 colorstr = gradient_getToken(&p);
1795 color = parseColor(colorstr);
1796 if(gradient.num == 16)
1798 warning("gradient record too big- max size is 16, rest ignored");
1801 gradient.ratios[gradient.num] = pos;
1802 gradient.rgba[gradient.num] = color;
1811 FILTERLIST* parseFilters(char* list)
1813 if(!strcmp(list, "no_filters"))
1816 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1818 char* f_start = list;
1822 f_end = strchr(f_start, ',');
1825 f = dict_lookup(&filters, f_start);
1829 syntaxerror("unknown filter %s", f_start);
1831 if(f_list->num == 8)
1833 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1836 f_list->filter[f_list->num] = f;
1841 f_start = f_end + 1;
1849 void s_gradient(const char*name, const char*text, int radial, int rotate)
1851 gradient_t* gradient;
1852 gradient = malloc(sizeof(gradient_t));
1853 memset(gradient, 0, sizeof(gradient_t));
1854 gradient->gradient = parseGradient(text);
1855 gradient->radial = radial;
1856 gradient->rotate = rotate;
1858 dict_put(&gradients, name, gradient);
1861 void s_gradientglow(const char*name, const char*gradient, float blurx, float blury,
1862 float angle, float distance, float strength, char innershadow,
1863 char knockout, char composite, char ontop, int passes)
1865 if(dict_lookup(&filters, name))
1866 syntaxerror("filter %s defined twice", name);
1868 gradient_t* g = dict_lookup(&gradients, gradient);
1870 syntaxerror("unknown gradient %s", gradient);
1874 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1875 filter->type = FILTERTYPE_GRADIENTGLOW;
1876 filter->gradient = &g->gradient;
1877 filter->blurx = blurx;
1878 filter->blury = blury;
1879 filter->strength = strength;
1880 filter->angle = angle;
1881 filter->distance = distance;
1882 filter->innershadow = innershadow;
1883 filter->knockout = knockout;
1884 filter->composite = composite;
1885 filter->ontop = ontop;
1886 filter->passes = passes;
1888 dict_put(&filters, name, filter);
1891 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)
1893 if(dict_lookup(&filters, name))
1894 syntaxerror("filter %s defined twice", name);
1897 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1898 filter->type = FILTERTYPE_DROPSHADOW;
1899 filter->color= color;
1900 filter->blurx = blurx;
1901 filter->blury = blury;
1902 filter->strength = strength;
1903 filter->angle = angle;
1904 filter->distance = distance;
1905 filter->innershadow = innershadow;
1906 filter->knockout = knockout;
1907 filter->composite = composite;
1908 filter->passes = passes;
1910 dict_put(&filters, name, filter);
1913 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)
1915 if(dict_lookup(&filters, name))
1916 syntaxerror("filter %s defined twice", name);
1919 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1920 filter->type = FILTERTYPE_BEVEL;
1921 filter->shadow = shadow;
1922 filter->highlight = highlight;
1923 filter->blurx = blurx;
1924 filter->blury = blury;
1925 filter->strength = strength;
1926 filter->angle = angle;
1927 filter->distance = distance;
1928 filter->innershadow = innershadow;
1929 filter->knockout = knockout;
1930 filter->composite = composite;
1931 filter->ontop = ontop;
1932 filter->passes = passes;
1934 dict_put(&filters, name, filter);
1937 void s_blur(const char*name, double blurx, double blury, int passes)
1939 if(dict_lookup(&filters, name))
1940 syntaxerror("filter %s defined twice", name);
1942 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1943 filter->type = FILTERTYPE_BLUR;
1944 filter->blurx = blurx;
1945 filter->blury = blury;
1946 filter->passes = passes;
1948 dict_put(&filters, name, filter);
1951 void s_action(const char*text)
1953 if(stack[0].swf->fileVersion < 9) {
1955 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1958 syntaxerror("Couldn't compile ActionScript");
1960 tag = swf_InsertTag(tag, ST_DOACTION);
1961 swf_ActionSet(tag, a);
1964 as3_parse_bytearray(stack[0].filename, text, strlen(text));
1969 void s_initaction(const char*character, const char*text)
1973 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1977 syntaxerror("Couldn't compile ActionScript");
1980 c = (character_t*)dict_lookup(&characters, character);
1982 tag = swf_InsertTag(tag, ST_DOINITACTION);
1983 swf_SetU16(tag, c->id);
1984 swf_ActionSet(tag, a);
1989 int s_swf3action(const char*name, const char*action)
1992 instance_t* object = 0;
1994 object = (instance_t*)dict_lookup(&instances, name);
1995 if(!object && name && *name) {
1996 /* we have a name, but couldn't find it. Abort. */
1999 a = action_SetTarget(0, name);
2000 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
2001 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
2002 else if(!strcmp(action, "stop")) a = action_Stop(a);
2003 else if(!strcmp(action, "play")) a = action_Play(a);
2004 a = action_SetTarget(a, "");
2007 tag = swf_InsertTag(tag, ST_DOACTION);
2008 swf_ActionSet(tag, a);
2013 void s_outline(const char*name, const char*format, const char*source)
2015 if(dict_lookup(&outlines, name))
2016 syntaxerror("outline %s defined twice", name);
2025 //swf_Shape10DrawerInit(&draw, 0);
2026 swf_Shape11DrawerInit(&draw, 0);
2028 draw_string(&draw, source);
2030 shape = swf_ShapeDrawerToShape(&draw);
2031 bounds = swf_ShapeDrawerGetBBox(&draw);
2032 draw.dealloc(&draw);
2034 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
2035 outline->shape = shape;
2036 outline->bbox = bounds;
2038 dict_put(&outlines, name, outline);
2041 int s_playsound(const char*name, int loops, int nomultiple, int stop)
2047 sound = dict_lookup(&sounds, name);
2051 tag = swf_InsertTag(tag, ST_STARTSOUND);
2052 swf_SetU16(tag, sound->id); //id
2053 memset(&info, 0, sizeof(info));
2056 info.nomultiple = nomultiple;
2057 swf_SetSoundInfo(tag, &info);
2061 void s_includeswf(const char*name, const char*filename)
2069 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
2070 f = open(filename,O_RDONLY|O_BINARY);
2072 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
2073 s_box(name, 0, 0, black, 20, 0);
2076 if(swf_ReadSWF(f,&swf)<0) {
2077 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
2078 s_box(name, 0, 0, black, 20, 0);
2083 /* FIXME: The following sets the bounding Box for the character.
2084 It is wrong for two reasons:
2085 a) It may be too small (in case objects in the movie clip at the borders)
2086 b) it may be too big (because the poor movie never got autocropped)
2090 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2091 swf_SetU16(tag, id);
2092 swf_SetU16(tag, swf.frameCount);
2094 swf_Relocate(&swf, idmap);
2096 ftag = swf.firstTag;
2100 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2101 if(cutout[t] == ftag->id) {
2105 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2107 if(ftag->id == ST_END)
2112 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2113 /* We simply dump all tags right after the sprite
2114 header, relying on the fact that swf_OptimizeTagOrder() will
2115 sort things out for us later.
2116 We also rely on the fact that the imported SWF is well-formed.
2118 tag = swf_InsertTag(tag, ftag->id);
2119 swf_SetBlock(tag, ftag->data, ftag->len);
2125 syntaxerror("Included file %s contains errors", filename);
2126 tag = swf_InsertTag(tag, ST_END);
2130 s_addcharacter(name, id, tag, r);
2133 SRECT s_getCharBBox(const char*name)
2135 character_t* c = dict_lookup(&characters, name);
2136 if(!c) syntaxerror("character '%s' unknown(2)", name);
2139 SRECT s_getInstanceBBox(const char*name)
2141 instance_t * i = dict_lookup(&instances, name);
2143 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2145 if(!c) syntaxerror("internal error(5)");
2148 void s_getParameters(const char*name, parameters_t* p)
2150 instance_t * i = dict_lookup(&instances, name);
2152 syntaxerror("instance '%s' unknown(10)", name);
2154 readParameters(i->history, p, currentframe);
2159 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2161 history_begin(i->history, "x", currentframe, tag, p->x);
2162 history_begin(i->history, "y", currentframe, tag, p->y);
2163 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2164 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2165 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2166 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2167 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2168 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2169 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2170 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2171 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2172 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2173 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2174 history_begin(i->history, "shear", currentframe, tag, p->shear);
2175 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2176 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2177 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2178 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2179 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2180 history_beginFilter(i->history, currentframe, tag, p->filters);
2181 history_begin(i->history, "flags", currentframe, tag, 0);
2184 void s_startclip(const char*instance, const char*character, parameters_t p)
2186 character_t* c = dict_lookup(&characters, character);
2190 syntaxerror("character %s not known", character);
2192 i = s_addinstance(instance, c, currentdepth);
2194 m = s_instancepos(i->character->size, &p);
2196 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2197 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2198 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2200 stack[stackpos].tag = tag;
2201 stack[stackpos].type = 2;
2204 setStartparameters(i, &p, tag);
2211 swf_SetTagPos(stack[stackpos].tag, 0);
2212 swf_GetPlaceObject(stack[stackpos].tag, &p);
2213 p.clipdepth = currentdepth;
2215 swf_ClearTag(stack[stackpos].tag);
2216 swf_SetPlaceObject(stack[stackpos].tag, &p);
2220 void s_put(const char*instance, const char*character, parameters_t p)
2222 character_t* c = dict_lookup(&characters, character);
2226 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2228 i = s_addinstance(instance, c, currentdepth);
2230 m = s_instancepos(i->character->size, &p);
2232 if(p.blendmode || p.filters)
2234 if(stack[0].swf->fileVersion < 8)
2237 warning("blendmodes only supported for flash version>=8");
2239 warning("filters only supported for flash version>=8");
2241 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2244 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2245 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2246 setStartparameters(i, &p, tag);
2250 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2253 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2255 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2256 if(p.set & SF_SCALEX)
2257 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2258 if(p.set & SF_SCALEY)
2259 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2262 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2263 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2267 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2268 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2272 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2273 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2277 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2278 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2280 if(p.set & SF_ROTATE)
2281 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2282 if(p.set & SF_SHEAR)
2283 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2284 if(p.set & SF_PIVOT)
2286 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2287 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2291 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2292 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2294 if(p.set & SF_BLEND)
2295 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2296 if(p.set & SF_FILTER)
2297 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2300 void s_jump(const char* instance, parameters_t p)
2302 instance_t* i = dict_lookup(&instances, instance);
2304 syntaxerror("instance %s not known", instance);
2305 recordChanges(i->history, p, CF_JUMP, 0);
2308 void s_change(const char*instance, parameters_t p, interpolation_t* inter)
2310 instance_t* i = dict_lookup(&instances, instance);
2312 syntaxerror("instance %s not known", instance);
2313 recordChanges(i->history, p, CF_CHANGE, inter);
2316 void s_sweep(const char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2318 instance_t* i = dict_lookup(&instances, instance);
2320 syntaxerror("instance %s not known", instance);
2321 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2324 void s_toggle(const char* instance, U16 flagsOn, U16 flagsOff)
2326 instance_t* i = dict_lookup(&instances, instance);
2328 syntaxerror("instance %s not known", instance);
2329 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2332 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2335 void s_delinstance(const char*instance)
2337 instance_t* i = dict_lookup(&instances, instance);
2339 syntaxerror("instance %s not known", instance);
2341 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2342 swf_SetU16(tag, i->depth);
2343 dict_del(&instances, instance);
2347 void s_schange(const char*instance, parameters_t p, interpolation_t* inter)
2349 instance_t* i = dict_lookup(&instances, instance);
2351 syntaxerror("instance %s not known", instance);
2352 recordChanges(i->history, p, CF_SCHANGE, inter);
2358 syntaxerror(".end unexpected");
2359 switch (stack[stackpos-1].type)
2374 syntaxerror("internal error 1");
2378 // ------------------------------------------------------------------------
2380 typedef int command_func_t(map_t*args);
2382 SRECT parseBox(const char*str)
2384 SRECT r = {0,0,0,0};
2385 float xmin, xmax, ymin, ymax;
2386 char*x = strchr(str, 'x');
2388 if(!strcmp(str, "autocrop")) {
2389 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2393 d1 = strchr(x+1, ':');
2395 d2 = strchr(d1+1, ':');
2397 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2401 else if(d1 && !d2) {
2402 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2408 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2413 r.xmin = (SCOORD)(xmin*20);
2414 r.ymin = (SCOORD)(ymin*20);
2415 r.xmax = (SCOORD)(xmax*20);
2416 r.ymax = (SCOORD)(ymax*20);
2419 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2422 float parseFloat(const char*str)
2426 int parseInt(const char*str)
2431 if(str[0]=='+' || str[0]=='-')
2435 if(str[t]<'0' || str[t]>'9')
2436 syntaxerror("Not an Integer: \"%s\"", str);
2439 static double parseRawTwip(const char*str)
2443 if(str[0]=='+' || str[0]=='-') {
2448 dot = strchr(str, '.');
2452 return sign*parseInt(str);
2454 char* old = strdup(str);
2455 int l=strlen(dot+1);
2458 for(s=str;s<dot-1;s++) {
2459 if(*s<'0' || *s>'9')
2462 syntaxerror("Not a coordinate: \"%s\"", str);
2466 if(*s<'0' || *s>'9')
2469 syntaxerror("Not a coordinate: \"%s\"", str);
2472 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2473 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2476 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2480 return sign*(atoi(str));
2482 return sign*(atoi(str)+0.1*atoi(dot));
2484 return sign*(atoi(str)+0.01*atoi(dot));
2489 static dict_t defines;
2490 static int defines_initialized = 0;
2491 static mem_t define_values;
2493 static double parseNameOrTwip(const char*s)
2497 if(defines_initialized) {
2498 l = (int)dict_lookup(&defines, s);
2501 return *(int*)&define_values.buffer[l-1];
2503 return parseRawTwip(s);
2507 /* automatically generated by yiyiyacc, http://www.quiss.org/yiyiyacc/ */
2508 static double parseExpression(char*s)
2511 memset(chr2index, -1, sizeof(chr2index));
2518 chr2index['\0'] = 7;
2526 int left[10]={11,8,8,8,8,9,9,9,10,10}; //production left side
2527 int plen[10]={1,3,2,3,1,3,3,1,1,3}; //production size
2528 int table[18][12] = {
2529 {0, 4, 0, 0, 5, 6, 0, 0, 1, 2, 3, 0},
2530 {7, 8, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0},
2531 {-4, -4, 9, 10, 0, 0, -4, -4, 0, 0, 0, 0},
2532 {-7, -7, -7, -7, 0, 0, -7, -7, 0, 0, 0, 0},
2533 {0, 0, 0, 0, 5, 6, 0, 0, 0, 11, 3, 0},
2534 {-8, -8, -8, -8, 0, 0, -8, -8, 0, 0, 0, 0},
2535 {0, 4, 0, 0, 5, 6, 0, 0, 12, 2, 3, 0},
2536 {0, 0, 0, 0, 5, 6, 0, 0, 0, 13, 3, 0},
2537 {0, 0, 0, 0, 5, 6, 0, 0, 0, 14, 3, 0},
2538 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 15, 0},
2539 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 16, 0},
2540 {-2, -2, 9, 10, 0, 0, -2, -2, 0, 0, 0, 0},
2541 {7, 8, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0},
2542 {-1, -1, 9, 10, 0, 0, -1, -1, 0, 0, 0, 0},
2543 {-3, -3, 9, 10, 0, 0, -3, -3, 0, 0, 0, 0},
2544 {-5, -5, -5, -5, 0, 0, -5, -5, 0, 0, 0, 0},
2545 {-6, -6, -6, -6, 0, 0, -6, -6, 0, 0, 0, 0},
2546 {-9, -9, -9, -9, 0, 0, -9, -9, 0, 0, 0, 0}};
2554 fprintf(stderr, "Error in expression\n");
2558 if(chr2index[*p]<0) {
2559 action = table[stack[stackpos-1]][4];
2561 while(chr2index[*pnext]<0)
2565 value = parseNameOrTwip(p);
2569 action = table[stack[stackpos-1]][chr2index[*p]];
2572 if(action == accept) {
2573 return values[stack[stackpos-1]];
2574 } else if(action>0) { // shift
2576 fprintf(stderr, "Stack overflow while parsing expression\n");
2579 values[stackpos]=value;
2580 stack[stackpos++]=action;
2582 } else if(action<0) { // reduce
2583 stackpos-=plen[-action];
2584 stack[stackpos] = table[stack[stackpos-1]][left[-action]];
2587 values[stackpos] = values[stackpos+0] + values[stackpos+2];
2590 values[stackpos] = 0 - values[stackpos+1];
2593 values[stackpos] = values[stackpos+0] - values[stackpos+2];
2596 values[stackpos] = values[stackpos+0] * values[stackpos+2];
2599 values[stackpos] = values[stackpos+0] / values[stackpos+2];
2602 values[stackpos] = values[stackpos+1];
2607 fprintf(stderr, "Syntax error in expression\n");
2613 int parseTwip(const char*str)
2615 char*str2 = (char*)str;
2616 int v = (int)(parseExpression(str2)*20);
2620 int parseArc(const char* str)
2622 if(!strcmp(str, "short"))
2624 if(!strcmp(str, "long"))
2626 syntaxerror("invalid value for the arc parameter: %s", str);
2630 int parseDir(const char* str)
2632 if(!strcmp(str, "clockwise"))
2634 if(!strcmp(str, "counterclockwise"))
2636 syntaxerror("invalid value for the dir parameter: %s", str);
2640 int isPoint(const char*str)
2642 if(strchr(str, '('))
2648 SPOINT parsePoint(const char*str)
2652 int l = strlen(str);
2653 char*comma = strchr(str, ',');
2654 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2655 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2656 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2657 p.x = parseTwip(tmp);
2658 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2659 p.y = parseTwip(tmp);
2663 int parseColor2(const char*str, RGBA*color)
2665 int l = strlen(str);
2669 struct {unsigned char r,g,b;char*name;} colors[] =
2670 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2671 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2672 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2673 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2674 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2675 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2676 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2677 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2678 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2679 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2680 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2681 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2685 if(str[0]=='#' && (l==7 || l==9)) {
2686 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2688 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2690 color->r = r; color->g = g; color->b = b; color->a = a;
2693 int len=strlen(str);
2695 if(strchr(str, '/')) {
2696 len = strchr(str, '/')-str;
2697 sscanf(str+len+1,"%02x", &alpha);
2699 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2700 if(!strncmp(str, colors[t].name, len)) {
2705 color->r = r; color->g = g; color->b = b; color->a = a;
2711 RGBA parseColor(const char*str)
2714 if(!parseColor2(str, &c))
2715 syntaxerror("Expression '%s' is not a color", str);
2719 typedef struct _muladd {
2724 MULADD parseMulAdd(const char*str)
2727 char* str2 = (char*)malloc(strlen(str)+5);
2734 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2735 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2736 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2737 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2738 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2739 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2740 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2741 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2742 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2743 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2745 syntaxerror("'%s' is not a valid color transform expression", str);
2747 m.add = (int)(add*256);
2748 m.mul = (int)(mul*256);
2753 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2755 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2756 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2758 if(a<-32768) a=-32768;
2759 if(a>32767) a=32767;
2760 if(m<-32768) m=-32768;
2761 if(m>32767) m=32767;
2767 float parsePxOrPercent(const char*fontname, const char*str)
2769 int l = strlen(str);
2770 if(strchr(str, '%'))
2771 return parsePercent(str);
2772 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2773 float p = atof(str);
2774 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2776 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2780 float parsePercent(const char*str)
2782 int l = strlen(str);
2786 return atof(str)/100.0;
2788 syntaxerror("Expression '%s' is not a percentage", str);
2791 int isPercent(const char*str)
2793 return str[strlen(str)-1]=='%';
2795 int parseNewSize(const char*str, int size)
2798 return parsePercent(str)*size;
2800 return (int)(atof(str)*20);
2803 int isColor(char*str)
2806 return parseColor2(str, &c);
2809 static const char* lu(map_t* args, char*name)
2811 const char* value = map_lookup(args, name);
2813 map_dump(args, stdout, "");
2814 syntaxerror("internal error 2: value %s should be set", name);
2819 static int c_flash(map_t*args)
2821 const char* filename = map_lookup(args, "filename");
2822 const char* compressstr = lu(args, "compress");
2823 const char* change_modestr = lu(args, "change-sets-all");
2824 const char* exportstr = lu(args, "export");
2825 SRECT bbox = parseBox(lu(args, "bbox"));
2826 int version = parseInt(lu(args, "version"));
2827 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2828 RGBA color = parseColor(lu(args, "background"));
2831 if(!filename || !*filename) {
2832 /* for compatibility */
2833 filename = map_lookup(args, "name");
2834 if(!filename || !*filename) {
2837 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2838 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2842 if(!filename || override_outputname)
2843 filename = outputname;
2845 if(!strcmp(compressstr, "default"))
2846 compress = version>=6;
2847 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2849 else if(!strcmp(compressstr, "no"))
2851 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2853 if(!strcmp(change_modestr, "yes"))
2854 change_sets_all = 1;
2856 if(strcmp(change_modestr, "no"))
2857 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2859 do_exports=atoi(exportstr);
2860 mainclass=strdup(lu(args, "mainclass"));
2862 s_swf(filename, bbox, version, fps, compress, color);
2865 int isRelative(const char*str)
2867 return !strncmp(str, "<plus>", 6) ||
2868 !strncmp(str, "<minus>", 7);
2870 const char* getOffset(const char*str)
2872 if(!strncmp(str, "<plus>", 6))
2874 if(!strncmp(str, "<minus>", 7))
2876 syntaxerror("internal error (347)");
2879 int getSign(const char*str)
2881 if(!strncmp(str, "<plus>", 6))
2883 if(!strncmp(str, "<minus>", 7))
2885 syntaxerror("internal error (348)");
2889 static dict_t points;
2890 static mem_t mpoints;
2891 static int points_initialized = 0;
2893 static int c_interpolation(map_t *args)
2896 const char* name = lu(args, "name");
2897 if(dict_lookup(&interpolations, name))
2898 syntaxerror("interpolation %s defined twice", name);
2900 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2901 const char* functionstr = lu(args, "function");
2902 inter->function = 0;
2903 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2904 if(!strcmp(functionstr,interpolationFunctions[i]))
2906 inter->function = i + 1;
2909 if(!inter->function)
2910 syntaxerror("unkown interpolation function %s", functionstr);
2911 inter->speed = parseFloat(lu(args, "speed"));
2912 inter->amplitude = parseTwip(lu(args, "amplitude"));
2913 inter->growth = parseFloat(lu(args, "growth"));
2914 inter->bounces = parseInt(lu(args, "bounces"));
2915 inter->damping = parseFloat(lu(args, "damping"));
2916 inter->slope = parseFloat(lu(args, "slope"));
2918 dict_put(&interpolations, name, inter);
2922 SPOINT getPoint(SRECT r, const char*name)
2925 if(!strcmp(name, "center")) {
2927 p.x = (r.xmin + r.xmax)/2;
2928 p.y = (r.ymin + r.ymax)/2;
2931 if(!strcmp(name, "bottom-center")) {
2933 p.x = (r.xmin + r.xmax)/2;
2937 if(!strcmp(name, "top-center")) {
2939 p.x = (r.xmin + r.xmax)/2;
2943 if(!strcmp(name, "top-left")) {
2949 if(!strcmp(name, "top-right")) {
2955 if(!strcmp(name, "bottom-right")) {
2961 if(!strcmp(name, "bottom-left")) {
2967 if(!strcmp(name, "left-center")) {
2970 p.y = (r.ymin + r.ymax)/2;
2973 if(!strcmp(name, "right-center")) {
2976 p.y = (r.ymin + r.ymax)/2;
2981 if(points_initialized)
2982 l = (int)dict_lookup(&points, name);
2984 syntaxerror("Invalid point: \"%s\".", name);
2986 return *(SPOINT*)&mpoints.buffer[l-1];
2990 static int texture2(const char*name, const char*object, map_t*args, int errors)
2993 const char*xstr = map_lookup(args, "x");
2994 const char*ystr = map_lookup(args, "y");
2995 const char*widthstr = map_lookup(args, "width");
2996 const char*heightstr = map_lookup(args, "height");
2997 const char*scalestr = map_lookup(args, "scale");
2998 const char*scalexstr = map_lookup(args, "scalex");
2999 const char*scaleystr = map_lookup(args, "scaley");
3000 const char*rotatestr = map_lookup(args, "rotate");
3001 const char* shearstr = map_lookup(args, "shear");
3002 const char* radiusstr = map_lookup(args, "r");
3004 float scalex = 1.0, scaley = 1.0;
3005 float rotate=0, shear=0;
3007 if(!*xstr && !*ystr) {
3009 syntaxerror("x and y must be set");
3012 if(*scalestr && (*scalexstr || *scaleystr)) {
3013 syntaxerror("scale and scalex/scaley can't both be set");
3016 if((*widthstr || *heightstr) && *radiusstr) {
3017 syntaxerror("width/height and radius can't both be set");
3020 widthstr = radiusstr;
3021 heightstr = radiusstr;
3023 if(!*xstr) xstr="0";
3024 if(!*ystr) ystr="0";
3025 if(!*rotatestr) rotatestr="0";
3026 if(!*shearstr) shearstr="0";
3029 scalex = scaley = parsePercent(scalestr);
3030 } else if(*scalexstr || *scaleystr) {
3031 if(scalexstr) scalex = parsePercent(scalexstr);
3032 if(scaleystr) scaley = parsePercent(scaleystr);
3033 } else if(*widthstr || *heightstr) {
3036 s_getBitmapSize(object, &width, &height);
3038 scalex = (float)parseTwip(widthstr)/(float)width;
3040 scaley = (float)parseTwip(heightstr)/(float)height;
3042 x = parseTwip(xstr);
3043 y = parseTwip(ystr);
3044 rotate = parseFloat(rotatestr);
3045 shear = parseFloat(shearstr);
3047 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
3052 static int c_texture(map_t*args)
3054 const char*name = lu(args, "instance");
3055 const char*object = lu(args, "character");
3056 return texture2(name, object, args, 1);
3059 static int c_gradient(map_t*args)
3061 const char*name = lu(args, "name");
3062 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
3063 int rotate = parseInt(lu(args, "rotate"));
3067 syntaxerror("colon (:) expected");
3069 if(dict_lookup(&gradients, name))
3070 syntaxerror("gradient %s defined twice", name);
3072 s_gradient(name, text, radial, rotate);
3074 /* check whether we also have placement information,
3075 which would make this a positioned gradient.
3076 If there is placement information, texture2() will
3077 add a texture, which has priority over the gradient.
3079 texture2(name, name, args, 0);
3083 static const char* checkFiltername(map_t* args)
3085 const char* name = lu(args, "name");
3086 if(strchr(name, ','))
3087 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
3091 static int c_blur(map_t*args)
3093 const char*name = checkFiltername(args);
3094 const char*blurstr = lu(args, "blur");
3095 const char*blurxstr = lu(args, "blurx");
3096 const char*blurystr = lu(args, "blury");
3097 float blurx=1.0, blury=1.0;
3099 blurx = parseFloat(blurstr);
3100 blury = parseFloat(blurstr);
3103 blurx = parseFloat(blurxstr);
3105 blury = parseFloat(blurystr);
3106 int passes = parseInt(lu(args, "passes"));
3107 s_blur(name, blurx, blury, passes);
3111 static int c_gradientglow(map_t*args)
3113 const char*name = checkFiltername(args);
3114 const char*gradient = lu(args, "gradient");
3115 const char*blurstr = lu(args, "blur");
3116 const char*blurxstr = lu(args, "blurx");
3117 const char*blurystr = lu(args, "blury");
3118 float blurx=1.0, blury=1.0;
3120 blurx = parseFloat(blurstr);
3121 blury = parseFloat(blurstr);
3124 blurx = parseFloat(blurxstr);
3126 blury = parseFloat(blurystr);
3128 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3129 float distance = parseFloat(lu(args, "distance"));
3130 float strength = parseFloat(lu(args, "strength"));
3131 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3132 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3133 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3134 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3135 int passes = parseInt(lu(args, "passes"));
3137 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3141 static int c_dropshadow(map_t*args)
3143 const char*name = checkFiltername(args);
3144 RGBA color = parseColor(lu(args, "color"));
3145 const char*blurstr = lu(args, "blur");
3146 const char*blurxstr = lu(args, "blurx");
3147 const char*blurystr = lu(args, "blury");
3148 float blurx=1.0, blury=1.0;
3150 blurx = parseFloat(blurstr);
3151 blury = parseFloat(blurstr);
3154 blurx = parseFloat(blurxstr);
3156 blury = parseFloat(blurystr);
3158 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3159 float distance = parseFloat(lu(args, "distance"));
3160 float strength = parseFloat(lu(args, "strength"));
3161 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3162 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3163 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3164 int passes = parseInt(lu(args, "passes"));
3166 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3170 static int c_bevel(map_t*args)
3172 const char*name = checkFiltername(args);
3173 RGBA shadow = parseColor(lu(args, "shadow"));
3174 RGBA highlight = parseColor(lu(args, "highlight"));
3175 const char*blurstr = lu(args, "blur");
3176 const char*blurxstr = lu(args, "blurx");
3177 const char*blurystr = lu(args, "blury");
3178 float blurx=1.0, blury=1.0;
3180 blurx = parseFloat(blurstr);
3181 blury = parseFloat(blurstr);
3184 blurx = parseFloat(blurxstr);
3186 blury = parseFloat(blurystr);
3188 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3189 float distance = parseFloat(lu(args, "distance"));
3190 float strength = parseFloat(lu(args, "strength"));
3191 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3192 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3193 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3194 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3195 int passes = parseInt(lu(args, "passes"));
3197 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3201 static int c_define(map_t*args)
3203 const char*name = lu(args, "name");
3204 const char*value = lu(args, "value");
3206 if(!defines_initialized) {
3207 dict_init(&defines, 16);
3208 mem_init(&define_values);
3209 defines_initialized = 1;
3211 int val = parseTwip(value);
3212 int pos = mem_put(&define_values, &val, sizeof(val));
3213 dict_put(&defines, name, (void*)(pos+1));
3216 static int c_point(map_t*args)
3218 const char*name = lu(args, "name");
3221 if(!points_initialized) {
3222 dict_init(&points, 16);
3224 points_initialized = 1;
3226 p.x = parseTwip(lu(args, "x"));
3227 p.y = parseTwip(lu(args, "y"));
3228 pos = mem_put(&mpoints, &p, sizeof(p));
3229 dict_put(&points, name, (void*)(pos+1));
3232 static int c_play(map_t*args)
3234 const char*name = lu(args, "name");
3235 const char*loop = lu(args, "loop");
3236 const char*nomultiple = lu(args, "nomultiple");
3238 if(!strcmp(nomultiple, "nomultiple"))
3241 nm = parseInt(nomultiple);
3243 if(s_playsound(name, parseInt(loop), nm, 0)) {
3245 } else if(s_swf3action(name, "play")) {
3251 static int c_stop(map_t*args)
3253 const char*name = map_lookup(args, "name");
3255 if(s_playsound(name, 0,0,1))
3257 else if(s_swf3action(name, "stop"))
3259 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3263 static int c_nextframe(map_t*args)
3265 const char*name = lu(args, "name");
3267 if(s_swf3action(name, "nextframe")) {
3270 syntaxerror("I don't know anything about movie \"%s\"", name);
3274 static int c_previousframe(map_t*args)
3276 const char*name = lu(args, "name");
3278 if(s_swf3action(name, "previousframe")) {
3281 syntaxerror("I don't know anything about movie \"%s\"", name);
3285 static int c_movement(map_t*args, int type)
3287 const char*instance = lu(args, "name");
3289 const char* xstr="";
3290 const char* ystr="";
3295 xstr = lu(args, "x");
3296 ystr = lu(args, "y");
3298 s_getParameters(instance, &p);
3303 if(isRelative(xstr))
3305 if(type == PT_PUT || type == PT_STARTCLIP)
3306 syntaxerror("relative x values not allowed for initial put or startclip");
3307 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3311 p.x = parseTwip(xstr);
3317 if(isRelative(ystr))
3319 if(type == PT_PUT || type == PT_STARTCLIP)
3320 syntaxerror("relative y values not allowed for initial put or startclip");
3321 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3325 p.y = parseTwip(ystr);
3338 const char* interstr = lu(args, "interpolation");
3339 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3341 syntaxerror("unkown interpolation %s", interstr);
3342 s_change(instance, p, inter);
3347 const char* interstr = lu(args, "interpolation");
3348 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3350 syntaxerror("unkown interpolation %s", interstr);
3351 s_schange(instance, p, inter);
3356 const char* rstr = lu(args, "r");
3357 int radius = parseTwip(rstr);
3359 syntaxerror("sweep not possible: radius must be greater than 0.");
3360 const char* dirstr = lu(args, "dir");
3361 int clockwise = parseDir(dirstr);
3362 const char* arcstr = lu(args, "arc");
3363 int short_arc = parseArc(arcstr);
3364 const char* interstr = lu(args, "interpolation");
3365 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3367 syntaxerror("unkown interpolation %s", interstr);
3368 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3375 static int c_placement(map_t*args, int type)
3377 const char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3378 const char*character = 0;
3380 const char* luminancestr = lu(args, "luminance");
3381 const char* scalestr = lu(args, "scale");
3382 const char* scalexstr = lu(args, "scalex");
3383 const char* scaleystr = lu(args, "scaley");
3384 const char* rotatestr = lu(args, "rotate");
3385 const char* shearstr = lu(args, "shear");
3386 const char* xstr="", *pivotstr="";
3387 const char* ystr="", *anglestr="";
3388 const char*above = lu(args, "above"); /*FIXME*/
3389 const char*below = lu(args, "below");
3390 const char* rstr = lu(args, "red");
3391 const char* gstr = lu(args, "green");
3392 const char* bstr = lu(args, "blue");
3393 const char* astr = lu(args, "alpha");
3394 const char* pinstr = lu(args, "pin");
3395 const char* as = map_lookup(args, "as");
3396 const char* blendmode = lu(args, "blend");
3397 const char* filterstr = lu(args, "filter");
3408 { // (?) .rotate or .arcchange
3409 pivotstr = lu(args, "pivot");
3410 anglestr = lu(args, "angle");
3414 xstr = lu(args, "x");
3415 ystr = lu(args, "y");
3419 luminance = parseMulAdd(luminancestr);
3423 luminance.mul = 256;
3428 if(scalexstr[0]||scaleystr[0])
3429 syntaxerror("scalex/scaley and scale cannot both be set");
3430 scalexstr = scaleystr = scalestr;
3433 if(type == PT_PUT || type == PT_STARTCLIP) {
3435 character = lu(args, "character");
3436 parameters_clear(&p);
3437 } else if(type == PT_BUTTON) {
3438 character = lu(args, "name");
3439 parameters_clear(&p);
3442 s_getParameters(instance, &p);
3448 if(isRelative(xstr))
3450 if(type == PT_PUT || type == PT_STARTCLIP)
3451 syntaxerror("relative x values not allowed for initial put or startclip");
3452 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3456 p.x = parseTwip(xstr);
3462 if(isRelative(ystr))
3464 if(type == PT_PUT || type == PT_STARTCLIP)
3465 syntaxerror("relative y values not allowed for initial put or startclip");
3466 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3470 p.y = parseTwip(ystr);
3475 /* scale, scalex, scaley */
3477 oldbbox = s_getCharBBox(character);
3479 oldbbox = s_getInstanceBBox(instance);
3480 oldwidth = oldbbox.xmax - oldbbox.xmin;
3481 oldheight = oldbbox.ymax - oldbbox.ymin;
3488 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3489 set = set | SF_SCALEX;
3497 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3498 set = set | SF_SCALEY;
3504 if(isRelative(rotatestr))
3505 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3507 p.rotate = parseFloat(rotatestr);
3508 set = set | SF_ROTATE;
3514 if(isRelative(shearstr))
3515 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3517 p.shear = parseFloat(shearstr);
3518 set = set | SF_SHEAR;
3523 if(isPoint(pivotstr))
3524 p.pivot = parsePoint(pivotstr);
3526 p.pivot = getPoint(oldbbox, pivotstr);
3527 set = set | SF_PIVOT;
3533 p.pin = parsePoint(pinstr);
3535 p.pin = getPoint(oldbbox, pinstr);
3539 /* color transform */
3541 if(rstr[0] || luminancestr[0])
3545 r = parseMulAdd(rstr);
3548 r.add = p.cxform.r0;
3549 r.mul = p.cxform.r1;
3551 r = mergeMulAdd(r, luminance);
3552 p.cxform.r0 = r.mul;
3553 p.cxform.r1 = r.add;
3554 set = set | SF_CX_R;
3556 if(gstr[0] || luminancestr[0])
3560 g = parseMulAdd(gstr);
3563 g.add = p.cxform.g0;
3564 g.mul = p.cxform.g1;
3566 g = mergeMulAdd(g, luminance);
3567 p.cxform.g0 = g.mul;
3568 p.cxform.g1 = g.add;
3569 set = set | SF_CX_G;
3571 if(bstr[0] || luminancestr[0])
3575 b = parseMulAdd(bstr);
3578 b.add = p.cxform.b0;
3579 b.mul = p.cxform.b1;
3581 b = mergeMulAdd(b, luminance);
3582 p.cxform.b0 = b.mul;
3583 p.cxform.b1 = b.add;
3584 set = set | SF_CX_B;
3588 MULADD a = parseMulAdd(astr);
3589 p.cxform.a0 = a.mul;
3590 p.cxform.a1 = a.add;
3591 set = set | SF_CX_A;
3598 for(t = 0; blendModeNames[t]; t++)
3600 if(!strcmp(blendModeNames[t], blendmode))
3608 syntaxerror("unknown blend mode: '%s'", blendmode);
3610 p.blendmode = blend;
3611 set = set | SF_BLEND;
3616 p.filters = parseFilters((char*)filterstr);
3617 set = set | SF_FILTER;
3620 if(type == PT_CHANGE && set & (SF_X | SF_Y))
3621 warning("As of version 0.8.2 using the .change command to modify an \
3622 object's position on the stage is considered deprecated. Future \
3623 versions may consider x and y parameters for the .change command \
3624 to be illegal; please use the .move command.");
3633 s_put(instance, character, p);
3637 const char* interstr = lu(args, "interpolation");
3638 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3640 syntaxerror("unkown interpolation %s", interstr);
3641 s_change(instance, p, inter);
3646 const char* interstr = lu(args, "interpolation");
3647 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3649 syntaxerror("unkown interpolation %s", interstr);
3650 s_schange(instance, p, inter);
3654 s_jump(instance, p);
3657 s_startclip(instance, character, p);
3661 s_buttonput(character, as, p);
3663 s_buttonput(character, "shape", p);
3669 static int c_put(map_t*args)
3671 c_placement(args, PT_PUT);
3674 static int c_change(map_t*args)
3676 if(currentframe == 0)
3677 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3678 c_placement(args, PT_CHANGE);
3681 static int c_schange(map_t*args)
3683 c_placement(args, PT_SCHANGE);
3686 static int c_move(map_t* args)
3688 c_movement(args, PT_MOVE);
3691 static int c_smove(map_t* args)
3693 c_movement(args, PT_SMOVE);
3696 static int c_sweep(map_t* args)
3698 c_movement(args, PT_SWEEP);
3701 static int c_arcchange(map_t*args)
3703 c_placement(args, 0);
3706 static int c_jump(map_t*args)
3708 c_placement(args, PT_JUMP);
3711 static int c_startclip(map_t*args)
3713 c_placement(args, PT_STARTCLIP);
3716 static int c_show(map_t*args)
3718 c_placement(args, PT_BUTTON);
3721 static int c_toggle(map_t* args)
3723 const char*instance = lu(args, "name");
3724 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3725 const char* alignstr = lu(args, "fixed_alignment");
3726 if(!strcmp(alignstr, "on"))
3727 flagsOn += IF_FIXED_ALIGNMENT;
3729 if(!strcmp(alignstr, "off"))
3730 flagsOff -= IF_FIXED_ALIGNMENT;
3732 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3733 s_toggle(instance, flagsOn, flagsOff);
3736 static int c_del(map_t*args)
3738 const char*instance = lu(args, "name");
3739 s_delinstance(instance);
3742 static int c_end(map_t*args)
3747 static int c_sprite(map_t*args)
3749 const char* name = lu(args, "name");
3750 const char* scalinggrid = lu(args, "scalinggrid");
3751 const char* as3name = lu(args, "as3name");
3753 if(scalinggrid && *scalinggrid) {
3754 SRECT r = parseBox(scalinggrid);
3755 s_sprite(name, &r, as3name);
3757 s_sprite(name, 0, as3name);
3761 static int c_frame(map_t*args)
3763 const char*framestr = lu(args, "n");
3764 const char*cutstr = lu(args, "cut");
3766 const char*name = lu(args, "name");
3767 const char*anchor = lu(args, "anchor");
3770 if(!strcmp(anchor, "anchor") && !*name)
3775 if(strcmp(cutstr, "no"))
3777 if(isRelative(framestr)) {
3778 frame = s_getframe();
3779 if(getSign(framestr)<0)
3780 syntaxerror("relative frame expressions must be positive");
3781 frame += parseInt(getOffset(framestr));
3784 frame = parseInt(framestr);
3785 if(s_getframe() >= frame
3786 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3787 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3789 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3792 static int c_primitive(map_t*args)
3794 const char*name = lu(args, "name");
3795 const char*command = lu(args, "commandname");
3796 int width=0, height=0, r=0;
3797 int linewidth = parseTwip(lu(args, "line"));
3798 const char*colorstr = lu(args, "color");
3799 RGBA color = parseColor(colorstr);
3800 const char*fillstr = lu(args, "fill");
3805 const char* outline=0;
3807 if(!strcmp(command, "circle"))
3809 else if(!strcmp(command, "filled"))
3813 width = parseTwip(lu(args, "width"));
3814 height = parseTwip(lu(args, "height"));
3815 } else if(type==1) {
3816 r = parseTwip(lu(args, "r"));
3817 } else if(type==2) {
3818 outline = lu(args, "outline");
3821 if(!strcmp(fillstr, "fill"))
3823 if(!strcmp(fillstr, "none"))
3825 if(width<0 || height<0 || linewidth<0 || r<0)
3826 syntaxerror("values width, height, line, r must be positive");
3828 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3829 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3830 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3834 static int c_textshape(map_t*args)
3836 const char*name = lu(args, "name");
3837 const char*text = lu(args, "text");
3838 const char*font = lu(args, "font");
3839 float size = parsePxOrPercent(font, lu(args, "size"));
3841 s_textshape(name, font, size, text);
3845 static int c_swf(map_t*args)
3847 const char*name = lu(args, "name");
3848 const char*filename = lu(args, "filename");
3849 const char*command = lu(args, "commandname");
3850 if(!strcmp(command, "shape"))
3851 warning("Please use .swf instead of .shape");
3852 s_includeswf(name, filename);
3856 static int c_font(map_t*args)
3858 const char*name = lu(args, "name");
3859 const char*filename = lu(args, "filename");
3860 s_font(name, filename);
3864 static int c_sound(map_t*args)
3866 const char*name = lu(args, "name");
3867 const char*filename = lu(args, "filename");
3868 s_sound(name, filename);
3872 static int c_text(map_t*args)
3874 const char*name = lu(args, "name");
3875 const char*text = lu(args, "text");
3876 const char*font = lu(args, "font");
3877 float size = parsePxOrPercent(font, lu(args, "size"));
3878 RGBA color = parseColor(lu(args, "color"));
3879 s_text(name, font, text, (int)(size*100), color);
3883 static int c_soundtrack(map_t*args)
3888 static int c_quicktime(map_t*args)
3890 const char*name = lu(args, "name");
3891 const char*url = lu(args, "url");
3892 s_quicktime(name, url);
3896 static int c_video(map_t*args)
3898 const char*name = lu(args, "name");
3899 int width = parseInt(lu(args, "width"));
3900 int height = parseInt(lu(args, "height"));
3901 s_video(name, width, height);
3905 static int c_image(map_t*args)
3907 const char*command = lu(args, "commandname");
3908 const char*name = lu(args, "name");
3909 const char*filename = lu(args, "filename");
3910 if(!strcmp(command,"jpeg")) {
3911 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3912 s_image(name, "jpeg", filename, quality);
3914 s_image(name, "png", filename, 0);
3919 static int c_outline(map_t*args)
3921 const char*name = lu(args, "name");
3922 const char*format = lu(args, "format");
3926 syntaxerror("colon (:) expected");
3928 s_outline(name, format, text);
3932 int fakechar(map_t*args)
3934 const char*name = lu(args, "name");
3935 s_box(name, 0, 0, black, 20, 0);
3939 static int c_egon(map_t*args) {return fakechar(args);}
3940 static int c_button(map_t*args) {
3941 const char*name = lu(args, "name");
3942 const char*as3name = lu(args, "as3name");
3943 s_button(name, as3name);
3946 static int current_button_flags = 0;
3947 static int c_on_press(map_t*args)
3949 const char*position = lu(args, "position");
3950 const char*action = "";
3951 if(!strcmp(position, "inside")) {
3952 current_button_flags |= BC_OVERUP_OVERDOWN;
3953 } else if(!strcmp(position, "outside")) {
3954 //current_button_flags |= BC_IDLE_OUTDOWN;
3955 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3956 } else if(!strcmp(position, "anywhere")) {
3957 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3960 if(type == RAWDATA) {
3962 s_buttonaction(current_button_flags, action);
3963 current_button_flags = 0;
3969 static int c_on_release(map_t*args)
3971 const char*position = lu(args, "position");
3972 const char*action = "";
3973 if(!strcmp(position, "inside")) {
3974 current_button_flags |= BC_OVERDOWN_OVERUP;
3975 } else if(!strcmp(position, "outside")) {
3976 current_button_flags |= BC_OUTDOWN_IDLE;
3977 } else if(!strcmp(position, "anywhere")) {
3978 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3981 if(type == RAWDATA) {
3983 s_buttonaction(current_button_flags, action);
3984 current_button_flags = 0;
3990 static int c_on_move_in(map_t*args)
3992 const char*position = lu(args, "state");
3993 const char*action = "";
3994 if(!strcmp(position, "pressed")) {
3995 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3996 } else if(!strcmp(position, "not_pressed")) {
3997 current_button_flags |= BC_IDLE_OVERUP;
3998 } else if(!strcmp(position, "any")) {
3999 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
4002 if(type == RAWDATA) {
4004 s_buttonaction(current_button_flags, action);
4005 current_button_flags = 0;
4011 static int c_on_move_out(map_t*args)
4013 const char*position = lu(args, "state");
4014 const char*action = "";
4015 if(!strcmp(position, "pressed")) {
4016 current_button_flags |= BC_OVERDOWN_OUTDOWN;
4017 } else if(!strcmp(position, "not_pressed")) {
4018 current_button_flags |= BC_OVERUP_IDLE;
4019 } else if(!strcmp(position, "any")) {
4020 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
4023 if(type == RAWDATA) {
4025 s_buttonaction(current_button_flags, action);
4026 current_button_flags = 0;
4032 static int c_on_key(map_t*args)
4034 const char*key = lu(args, "key");
4035 const char*action = "";
4036 if(strlen(key)==1) {
4039 current_button_flags |= 0x4000 + (key[0]*0x200);
4041 syntaxerror("invalid character: %c"+key[0]);
4046 <ctrl-x> = 0x200*(x-'a')
4050 syntaxerror("invalid key: %s",key);
4053 if(type == RAWDATA) {
4055 s_buttonaction(current_button_flags, action);
4056 current_button_flags = 0;
4063 static int c_edittext(map_t*args)
4065 //"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"},
4066 const char*name = lu(args, "name");
4067 const char*font = lu(args, "font");
4068 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
4069 int width = parseTwip(lu(args, "width"));
4070 int height = parseTwip(lu(args, "height"));
4071 const char*text = lu(args, "text");
4072 RGBA color = parseColor(lu(args, "color"));
4073 int maxlength = parseInt(lu(args, "maxlength"));
4074 const char*variable = lu(args, "variable");
4075 const char*passwordstr = lu(args, "password");
4076 const char*wordwrapstr = lu(args, "wordwrap");
4077 const char*multilinestr = lu(args, "multiline");
4078 const char*htmlstr = lu(args, "html");
4079 const char*noselectstr = lu(args, "noselect");
4080 const char*readonlystr = lu(args, "readonly");
4081 const char*borderstr = lu(args, "border");
4082 const char*autosizestr = lu(args, "autosize");
4083 const char*alignstr = lu(args, "align");
4087 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
4088 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
4089 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
4090 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
4091 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
4092 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
4093 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
4094 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
4095 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
4096 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
4097 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
4098 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
4099 else syntaxerror("Unknown alignment: %s", alignstr);
4101 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
4105 static int c_morphshape(map_t*args) {return fakechar(args);}
4106 static int c_movie(map_t*args) {return fakechar(args);}
4108 static char* readfile(char*filename)
4110 FILE*fi = fopen(filename, "rb");
4114 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
4115 fseek(fi, 0, SEEK_END);
4117 fseek(fi, 0, SEEK_SET);
4118 text = rfx_alloc(l+1);
4119 fread(text, l, 1, fi);
4125 static int c_action(map_t*args)
4127 const char* filename = map_lookup(args, "filename");
4128 if(!filename ||!*filename) {
4130 if(type != RAWDATA) {
4131 syntaxerror("colon (:) expected");
4135 s_action(readfile((char*)filename));
4141 static int c_initaction(map_t*args)
4143 const char* character = lu(args, "name");
4144 const char* filename = map_lookup(args, "filename");
4145 if(!filename ||!*filename) {
4147 if(type != RAWDATA) {
4148 syntaxerror("colon (:) expected");
4150 s_initaction(character, text);
4152 s_initaction(character, readfile((char*)filename));
4160 command_func_t* func;
4163 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1 @mainclass="},
4164 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
4165 // "import" type stuff
4166 {"swf", c_swf, "name filename"},
4167 {"shape", c_swf, "name filename"},
4168 {"jpeg", c_image, "name filename quality=80%"},
4169 {"png", c_image, "name filename"},
4170 {"movie", c_movie, "name filename"},
4171 {"sound", c_sound, "name filename"},
4172 {"font", c_font, "name filename glyphs= @flashtype="},
4173 {"soundtrack", c_soundtrack, "filename"},
4174 {"quicktime", c_quicktime, "url"},
4175 {"video", c_video, "name width= height="},
4177 // generators of primitives
4179 {"define", c_define, "name value=0"},
4180 {"point", c_point, "name x=0 y=0"},
4181 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4182 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4183 {"outline", c_outline, "name format=simple"},
4184 {"textshape", c_textshape, "name font size=100% text"},
4187 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4188 {"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"},
4189 {"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"},
4190 {"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"},
4192 // character generators
4193 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4194 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4195 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4197 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4198 {"text", c_text, "name text font size=100% color=white"},
4199 {"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="},
4200 {"morphshape", c_morphshape, "name start end"},
4201 {"button", c_button, "name as3name="},
4202 {"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="},
4203 {"on_press", c_on_press, "position=inside"},
4204 {"on_release", c_on_release, "position=anywhere"},
4205 {"on_move_in", c_on_move_in, "state=not_pressed"},
4206 {"on_move_out", c_on_move_out, "state=not_pressed"},
4207 {"on_key", c_on_key, "key=any"},
4210 {"play", c_play, "name loop=0 @nomultiple=0"},
4211 {"stop", c_stop, "name= "},
4212 {"nextframe", c_nextframe, "name"},
4213 {"previousframe", c_previousframe, "name"},
4215 // object placement tags
4216 {"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="},
4217 {"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="},
4218 {"move", c_move, "name x= y= interpolation=linear"},
4219 {"smove", c_smove, "name x= y= interpolation=linear"},
4220 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4221 {"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"},
4222 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4223 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4224 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4225 {"del", c_del, "name"},
4226 // virtual object placement
4227 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4229 {"toggle", c_toggle, "name fixed_alignment="},
4231 // commands which start a block
4232 //startclip (see above)
4233 {"sprite", c_sprite, "name scalinggrid= as3name="},
4234 {"action", c_action, "filename="},
4235 {"initaction", c_initaction, "name filename="},
4241 static map_t parseArguments(char*command, char*pattern)
4257 string_set(&t1, "commandname");
4258 string_set(&t2, command);
4259 map_put(&result, t1, t2);
4261 if(!pattern || !*pattern)
4268 if(!strncmp("<i> ", x, 3)) {
4270 if(type == COMMAND || type == RAWDATA) {
4272 syntaxerror("character name expected");
4274 name[pos].str = "instance";
4276 value[pos].str = text;
4277 value[pos].len = strlen(text);
4281 if(type == ASSIGNMENT)
4284 name[pos].str = "character";
4286 value[pos].str = text;
4287 value[pos].len = strlen(text);
4295 isboolean[pos] = (x[0] =='@');
4308 name[pos].len = d-x;
4313 name[pos].len = e-x;
4314 value[pos].str = e+1;
4315 value[pos].len = d-e-1;
4323 /* for(t=0;t<len;t++) {
4324 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4325 isboolean[t]?"(boolean)":"");
4330 if(type == RAWDATA || type == COMMAND) {
4335 // first, search for boolean arguments
4336 for(pos=0;pos<len;pos++)
4338 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4340 if(type == ASSIGNMENT)
4342 value[pos].str = text;
4343 value[pos].len = strlen(text);
4344 /*printf("setting boolean parameter %s (to %s)\n",
4345 strdup_n(name[pos], namelen[pos]),
4346 strdup_n(value[pos], valuelen[pos]));*/
4351 // second, search for normal arguments
4353 for(pos=0;pos<len;pos++)
4355 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4356 (type != ASSIGNMENT && !set[pos])) {
4358 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4360 if(type == ASSIGNMENT)
4363 value[pos].str = text;
4364 value[pos].len = strlen(text);
4366 printf("setting parameter %s (to %s)\n",
4367 strdup_n(name[pos].str, name[pos].len),
4368 strdup_n(value[pos].str, value[pos].len));
4374 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4378 for(t=0;t<len;t++) {
4379 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4382 for(t=0;t<len;t++) {
4383 if(value[t].str && value[t].str[0] == '*') {
4384 //relative default- take value from some other parameter
4386 for(s=0;s<len;s++) {
4387 if(value[s].len == value[t].len-1 &&
4388 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4389 value[t].str = value[s].str;
4392 if(value[t].str == 0) {
4394 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4398 /* ok, now construct the dictionary from the parameters */
4402 map_put(&result, name[t], value[t]);
4406 static void parseArgumentsForCommand(char*command)
4411 msg("<verbose> parse Command: %s (line %d)", command, line);
4413 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4414 if(!strcmp(arguments[t].command, command)) {
4416 /* ugly hack- will be removed soon (once documentation and .sc generating
4417 utilities have been changed) */
4418 if(!strcmp(command, "swf") && !stackpos) {
4419 warning("Please use .flash instead of .swf- this will be mandatory soon");
4424 args = parseArguments(command, arguments[t].arguments);
4430 syntaxerror("command %s not known", command);
4433 // catch missing .flash directives at the beginning of a file
4434 if(strcmp(command, "flash") && !stackpos)
4436 syntaxerror("No movie defined- use .flash first");
4441 printf(".%s\n", command);fflush(stdout);
4442 map_dump(&args, stdout, "\t");fflush(stdout);
4446 (*arguments[nr].func)(&args);
4448 if(!strcmp(command, "action") || !strcmp(command, "initaction") ||
4449 !strcmp(command, "outline") || !strcmp(command, "gradient")) {
4451 if(type != RAWDATA) {
4452 syntaxerror("colon (:) expected");
4461 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4462 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4463 * No syntax checking is done */
4464 static void analyseArgumentsForCommand(char*command)
4469 U8* glyphs_to_include;
4470 msg("<verbose> analyse Command: %s (line %d)", command, line);
4472 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4474 if(!strcmp(arguments[t].command, command))
4476 args = parseArguments(command, arguments[t].arguments);
4482 printf(".%s\n", command);fflush(stdout);
4483 map_dump(&args, stdout, "\t");fflush(stdout);
4485 const char* name = lu(&args, "name");
4486 if(!strcmp(command, "font"))
4488 const char* fontfile = lu(&args, "filename");
4489 const char* glyphs = lu(&args, "glyphs");
4490 const char* flashtype = lu(&args, "flashtype");
4491 s_createfont(name, fontfile, glyphs, flashtype[0]);
4493 SWFFONT* font = dict_lookup(&fonts, lu(&args, "font"));
4495 //that's ok... it might be an edittext with a system font
4496 //syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4498 if(font->use && !font->use->glyphs_specified) {
4499 if(!strcmp(command, "edittext"))
4501 swf_FontUseAll(font);
4502 font->use->glyphs_specified = 1;
4505 swf_FontUseUTF8(font, (U8*)lu(&args, "text"), 0xffff);
4512 void skipParameters()
4516 while (type != COMMAND);
4520 void findFontUsage()
4522 char* fontRelated = "font;text;textshape;edittext;";
4523 while(!noMoreTokens())
4527 syntaxerror("command expected");
4528 if(strstr(fontRelated, text))
4529 analyseArgumentsForCommand(text);
4531 if(strcmp(text, "end"))
4540 dict_init(&fonts, 16);
4541 cleanUp = &freeFontDictionary;
4545 int main (int argc,char ** argv)
4548 processargs(argc, argv);
4549 initLog(0,-1,0,0,-1,verbose);
4552 args_callback_usage(argv[0]);
4556 file = generateTokens(filename);
4558 fprintf(stderr, "parser returned error.\n");
4565 while(!noMoreTokens()) {
4568 syntaxerror("command expected");
4569 parseArgumentsForCommand(text);