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;
52 static struct options_t options[] = {
61 int args_callback_option(char*name,char*val)
63 if(!strcmp(name, "V")) {
64 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
67 else if(!strcmp(name, "o")) {
69 override_outputname = 1;
72 else if(!strcmp(name, "O")) {
76 else if(!strcmp(name, "C")) {
80 else if(!strcmp(name, "v")) {
85 printf("Unknown option: -%s\n", name);
90 int args_callback_longoption(char*name,char*val)
92 return args_long2shortoption(options, name, val);
94 void args_callback_usage(char *name)
97 printf("Usage: %s [-o file.swf] file.sc\n", name);
99 printf("-h , --help Print short help message and exit\n");
100 printf("-V , --version Print version info and exit\n");
101 printf("-C , --cgi Output to stdout (for use in CGI environments)\n");
102 printf("-v , --verbose Increase verbosity. \n");
103 printf("-o , --output <filename> Set output file to <filename>.\n");
106 int args_callback_command(char*name,char*val)
109 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
116 static struct token_t* file;
123 static void readToken()
125 type = file[pos].type;
127 syntaxerror("unexpected end of file");
129 text = file[pos].text;
130 textlen = strlen(text);
131 line = file[pos].line;
132 column = file[pos].column;
134 //printf("---> %d(%s) %s\n", type, type_names[type], text);
137 static void pushBack()
140 if(!pos) syntaxerror("internal error 3");
145 textlen = strlen(text);
148 column = file[p].column;
151 static int noMoreTokens()
153 if(file[pos].type == END)
171 // ------------------------------ swf routines ----------------------------
175 int type; //0=swf, 1=sprite, 2=clip, 3=button
182 /* for sprites (1): */
195 static int stackpos = 0;
197 static dict_t characters;
198 static dict_t images;
199 static dict_t textures;
200 static dict_t outlines;
201 static dict_t gradients;
202 static dict_t filters;
203 static dict_t interpolations;
204 static char idmap[65536];
205 static TAG*tag = 0; //current tag
207 static int id; //current character id
208 static int currentframe; //current frame in current level
209 static SRECT currentrect; //current bounding box in current level
210 static U16 currentdepth;
211 static dict_t instances;
213 static dict_t sounds;
214 static dict_t fontUsage;
216 typedef struct _parameters {
218 float scalex, scaley;
224 U8 blendmode; //not interpolated
226 U16 set; // bits indicating wether a parameter was set in the c_placement function
227 U16 flags; // bits to toggle anything you may care to implement as a toggle
230 typedef struct _character {
236 typedef struct _instance {
237 character_t*character;
239 parameters_t parameters;
243 typedef struct _outline {
248 typedef struct _gradient {
254 typedef struct _filter {
258 typedef struct _texture {
262 char* interpolationFunctions[] = {"linear", \
263 "quadIn", "quadOut", "quadInOut", \
264 "cubicIn", "cubicOut", "cubicInOut", \
265 "quartIn", "quartOut", "quartInOut", \
266 "quintIn", "quintOut", "quintInOut", \
267 "circleIn", "circleOut", "circleInOut", \
268 "exponentialIn", "exponentialOut", "exponentialInOut", \
269 "sineIn", "sineOut", "sineInOut", \
270 "elasticIn", "elasticOut", "elasticInOut", \
271 "backIn", "backOut", "backInOut", \
272 "bounceIn", "bounceOut", "bounceInOut", \
273 "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
275 static void character_init(character_t*c)
277 memset(c, 0, sizeof(character_t));
280 static character_t* character_new()
283 c = (character_t*)malloc(sizeof(character_t));
288 static void instance_init(instance_t*i)
290 memset(i, 0, sizeof(instance_t));
291 i->history = history_new();
294 static void instance_free(instance_t* i)
296 history_free(i->history);
300 static instance_t* instance_new()
303 c = (instance_t*)malloc(sizeof(instance_t));
308 static void free_instance(void* i)
310 instance_free((instance_t*)i);
313 static void free_font(void* f)
315 swf_FontFree((SWFFONT*)f);
318 static void gradient_free(GRADIENT* grad)
325 static void free_gradient(void* grad)
327 gradient_free((GRADIENT*) grad);
330 static void outline_free(outline_t* o)
332 free(o->shape->data);
337 static void free_outline(void* o)
339 outline_free((outline_t*)o);
342 static void freeDictionaries()
344 dict_free_all(&instances, 1, free_instance);
345 dict_free_all(&characters, 1, free);
346 dict_free_all(&images, 1, free);
347 dict_free_all(&textures, 1, free);
348 dict_free_all(&outlines, 1, free_outline);
349 dict_free_all(&gradients, 1, free_gradient);
350 dict_free_all(&filters, 1, free);
351 dict_free_all(&fonts, 1, free_font);
352 dict_free_all(&sounds, 1, free);
353 dict_free_all(&interpolations, 1, free);
357 static void freeFontDictionary()
359 dict_free_all(&fonts, 1, free_font);
362 static void incrementid()
364 while(id<65536 && idmap[id]) {
368 syntaxerror("Out of character ids.");
372 static void s_addcharacter(const char*name, U16 id, TAG*ctag, SRECT r)
374 if(dict_lookup(&characters, name))
375 syntaxerror("character %s defined twice", name);
376 character_t* c = character_new();
378 c->definingTag = ctag;
381 dict_put(&characters, name, c);
384 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
386 swf_SetString(tag, name);
387 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
390 swf_SetString(tag, name);
393 static void s_addimage(const char*name, U16 id, TAG*ctag, SRECT r)
395 if(dict_lookup(&images, name))
396 syntaxerror("image %s defined twice", name);
398 character_t* c = character_new();
399 c->definingTag = ctag;
402 dict_put(&images, name, c);
404 static instance_t* s_addinstance(const char*name, character_t*c, U16 depth)
406 if(dict_lookup(&instances, name))
407 syntaxerror("object %s defined twice", name);
408 instance_t* i = instance_new();
411 //swf_GetMatrix(0, &i->matrix);
412 dict_put(&instances, name, i);
416 static void parameters_clear(parameters_t*p)
419 p->scalex = 1.0; p->scaley = 1.0;
422 p->pivot.x = 0; p->pivot.y = 0;
427 swf_GetCXForm(0, &p->cxform, 1);
430 static void makeMatrix(MATRIX*m, parameters_t*p)
439 sx = p->scalex*cos(p->rotate/360*2*M_PI);
440 r1 = -p->scalex*sin(p->rotate/360*2*M_PI)+sx*p->shear;
441 r0 = p->scaley*sin(p->rotate/360*2*M_PI);
442 sy = p->scaley*cos(p->rotate/360*2*M_PI)+r0*p->shear;
444 m->sx = (int)(sx*65536+0.5);
445 m->r1 = (int)(r1*65536+0.5);
446 m->r0 = (int)(r0*65536+0.5);
447 m->sy = (int)(sy*65536+0.5);
451 h = swf_TurnPoint(p->pin, m);
456 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
461 r = swf_TurnRect(rect, &m);
462 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
463 currentrect.xmax == 0 && currentrect.ymax == 0)
466 swf_ExpandRect2(¤trect, &r);
472 interpolation_t* new;
473 new = (interpolation_t*)malloc(sizeof(interpolation_t));
474 new->function = IF_LINEAR;
475 dict_put(&interpolations, "linear", new);
477 new = (interpolation_t*)malloc(sizeof(interpolation_t));
478 new->function = IF_QUAD_IN;
480 dict_put(&interpolations, "quadIn", new);
481 new = (interpolation_t*)malloc(sizeof(interpolation_t));
482 new->function = IF_QUAD_OUT;
484 dict_put(&interpolations, "quadOut", new);
485 new = (interpolation_t*)malloc(sizeof(interpolation_t));
486 new->function = IF_QUAD_IN_OUT;
488 dict_put(&interpolations, "quadInOut", new);
490 new = (interpolation_t*)malloc(sizeof(interpolation_t));
491 new->function = IF_CUBIC_IN;
493 dict_put(&interpolations, "cubicIn", new);
494 new = (interpolation_t*)malloc(sizeof(interpolation_t));
495 new->function = IF_CUBIC_OUT;
497 dict_put(&interpolations, "cubicOut", new);
498 new = (interpolation_t*)malloc(sizeof(interpolation_t));
499 new->function = IF_CUBIC_IN_OUT;
501 dict_put(&interpolations, "cubicInOut", new);
503 new = (interpolation_t*)malloc(sizeof(interpolation_t));
504 new->function = IF_QUART_IN;
506 dict_put(&interpolations, "quartIn", new);
507 new = (interpolation_t*)malloc(sizeof(interpolation_t));
508 new->function = IF_QUART_OUT;
510 dict_put(&interpolations, "quartOut", new);
511 new = (interpolation_t*)malloc(sizeof(interpolation_t));
512 new->function = IF_QUART_IN_OUT;
514 dict_put(&interpolations, "quartInOut", new);
516 new = (interpolation_t*)malloc(sizeof(interpolation_t));
517 new->function = IF_QUINT_IN;
519 dict_put(&interpolations, "quintIn", new);
520 new = (interpolation_t*)malloc(sizeof(interpolation_t));
521 new->function = IF_QUINT_OUT;
523 dict_put(&interpolations, "quintOut", new);
524 new = (interpolation_t*)malloc(sizeof(interpolation_t));
525 new->function = IF_QUINT_IN_OUT;
527 dict_put(&interpolations, "quintInOut", new);
529 new = (interpolation_t*)malloc(sizeof(interpolation_t));
530 new->function = IF_CIRCLE_IN;
531 dict_put(&interpolations, "circleIn", new);
532 new = (interpolation_t*)malloc(sizeof(interpolation_t));
533 new->function = IF_CIRCLE_OUT;
534 dict_put(&interpolations, "circleOut", new);
535 new = (interpolation_t*)malloc(sizeof(interpolation_t));
536 new->function = IF_CIRCLE_IN_OUT;
537 dict_put(&interpolations, "circleInOut", new);
539 new = (interpolation_t*)malloc(sizeof(interpolation_t));
540 new->function = IF_EXPONENTIAL_IN;
541 dict_put(&interpolations, "exponentialIn", new);
542 new = (interpolation_t*)malloc(sizeof(interpolation_t));
543 new->function = IF_EXPONENTIAL_OUT;
544 dict_put(&interpolations, "exponentialOut", new);
545 new = (interpolation_t*)malloc(sizeof(interpolation_t));
546 new->function = IF_EXPONENTIAL_IN_OUT;
547 dict_put(&interpolations, "exponentialInOut", new);
549 new = (interpolation_t*)malloc(sizeof(interpolation_t));
550 new->function = IF_SINE_IN;
551 dict_put(&interpolations, "sineIn", new);
552 new = (interpolation_t*)malloc(sizeof(interpolation_t));
553 new->function = IF_SINE_OUT;
554 dict_put(&interpolations, "sineOut", new);
555 new = (interpolation_t*)malloc(sizeof(interpolation_t));
556 new->function = IF_SINE_IN_OUT;
557 dict_put(&interpolations, "sineInOut", new);
560 memset(&c, 0, sizeof(RGBA));
561 gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
562 noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
563 noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
564 noGradient->gradient.num = 2;
565 noGradient->gradient.rgba[0] = c;
566 noGradient->gradient.ratios[0] = 0;
567 noGradient->gradient.rgba[1] = c;
568 noGradient->gradient.ratios[1] = 255;
569 noGradient->radial = 0;
570 noGradient->rotate = 0;
571 dict_put(&gradients, "no_gradient", noGradient);
574 // put a no_filters entry in the filters dictionary to provoce a message when a user tries
575 // to define a no_filters filter. The real filter=no_filters case is handled in parseFilters.
576 FILTER* dummy = (FILTER*)malloc(sizeof(FILTER));
577 dict_put(&filters, "no_filters", dummy);
578 noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
580 dict_put(&filters, "no_blur", noBlur);
581 noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
583 noBevel->composite = 1;
584 dict_put(&filters, "no_bevel", noBevel);
585 noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
586 noDropshadow->passes = 1;
587 noDropshadow->composite = 1;
588 dict_put(&filters, "no_dropshadow", noDropshadow);
589 noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
590 noGradientGlow->passes = 1;
591 noGradientGlow->composite = 1;
592 noGradientGlow->gradient = &noGradient->gradient;
593 dict_put(&filters, "no_gradientglow", noGradientGlow);
596 void s_swf(const char*name, SRECT r, int version, int fps, int compress, RGBA background)
599 syntaxerror(".swf blocks can't be nested");
600 if(stackpos==sizeof(stack)/sizeof(stack[0]))
601 syntaxerror("too many levels of recursion");
603 SWF*swf = (SWF*)malloc(sizeof(SWF));
605 memset(swf, 0, sizeof(swf));
606 swf->fileVersion = version;
608 swf->frameRate = fps;
609 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
610 swf->compressed = compress;
611 swf_SetRGB(tag,&background);
613 dict_init(&characters, 16);
614 dict_init(&images, 16);
615 dict_init(&textures, 16);
616 dict_init(&outlines, 16);
617 dict_init(&gradients, 16);
618 dict_init(&filters, 16);
619 dict_init(&instances, 16);
620 dict_init(&sounds, 16);
621 dict_init(&interpolations, 16);
623 cleanUp = &freeDictionaries;
625 memset(&stack[stackpos], 0, sizeof(stack[0]));
626 stack[stackpos].type = 0;
627 stack[stackpos].filename = strdup(name);
628 stack[stackpos].swf = swf;
629 stack[stackpos].oldframe = -1;
633 memset(¤trect, 0, sizeof(currentrect));
636 memset(idmap, 0, sizeof(idmap));
637 idmap[0]=1; //main movie has ID 0
642 void s_sprite(const char*name, SRECT*scalegrid)
644 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
645 swf_SetU16(tag, id); //id
646 swf_SetU16(tag, 0); //frames
648 memset(&stack[stackpos], 0, sizeof(stack[0]));
649 stack[stackpos].type = 1;
650 stack[stackpos].oldframe = currentframe;
651 stack[stackpos].olddepth = currentdepth;
652 stack[stackpos].oldrect = currentrect;
653 stack[stackpos].oldinstances = instances;
654 stack[stackpos].tag = tag;
655 stack[stackpos].id = id;
656 stack[stackpos].name = strdup(name);
658 stack[stackpos].scalegrid = *scalegrid;
660 memset(&stack[stackpos].scalegrid, 0, sizeof(SRECT));
663 /* FIXME: those four fields should be bundled together */
664 dict_init(&instances, 16);
667 memset(¤trect, 0, sizeof(currentrect));
673 typedef struct _buttonrecord
681 typedef struct _button
685 buttonrecord_t records[4];
688 static button_t mybutton;
690 void s_button(const char*name)
692 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
693 swf_SetU16(tag, id); //id
694 swf_ButtonSetFlags(tag, 0); //menu=no
696 memset(&mybutton, 0, sizeof(mybutton));
698 memset(&stack[stackpos], 0, sizeof(stack[0]));
699 stack[stackpos].type = 3;
700 stack[stackpos].tag = tag;
701 stack[stackpos].id = id;
702 stack[stackpos].name = strdup(name);
703 stack[stackpos].oldrect = currentrect;
704 memset(¤trect, 0, sizeof(currentrect));
709 void s_buttonput(const char*character, const char*as, parameters_t p)
711 character_t* c = dict_lookup(&characters, character);
714 const char*o = as,*s = as;
716 if(!stackpos || (stack[stackpos-1].type != 3)) {
717 syntaxerror(".show may only appear in .button");
720 syntaxerror("character %s not known (in .shape %s)", character, character);
722 if(mybutton.endofshapes) {
723 syntaxerror("a .do may not precede a .show", character, character);
726 m = s_instancepos(c->size, &p);
734 if(*s==',' || *s==0) {
735 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
736 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
737 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
738 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
739 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
740 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
747 static void setbuttonrecords(TAG*tag)
749 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
750 if(!mybutton.endofshapes) {
753 if(!mybutton.records[3].set) {
754 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
758 if(mybutton.records[t].set) {
759 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
762 swf_SetU8(tag,0); // end of button records
763 mybutton.endofshapes = 1;
767 void s_buttonaction(int flags, const char*action)
773 if(!stackpos || !stack[stackpos-1].tag ||
774 stack[stackpos-1].tag->id != ST_DEFINEBUTTON2) {
775 syntaxerror("Need to be inside a button for .on_* commands");
777 setbuttonrecords(stack[stackpos-1].tag);
779 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
781 syntaxerror("Couldn't compile ActionScript");
784 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
785 swf_ActionSet(stack[stackpos-1].tag, a);
786 mybutton.nr_actions++;
791 static void setactionend(TAG*tag)
793 if(!mybutton.nr_actions) {
794 /* no actions means we didn't have an actionoffset,
795 which means we can't signal the end of the
796 buttonaction records, so, *sigh*, we have
797 to insert a dummy record */
798 swf_SetU16(tag, 0); //offset
799 swf_SetU16(tag, 0); //condition
800 swf_SetU8(tag, 0); //action
804 static void s_endButton()
807 setbuttonrecords(stack[stackpos-1].tag);
808 setactionend(stack[stackpos-1].tag);
811 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
815 tag = stack[stackpos].tag;
816 currentrect = stack[stackpos].oldrect;
818 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
819 free(stack[stackpos].name);
822 TAG* removeFromTo(TAG*from, TAG*to)
824 TAG*save = from->prev;
826 TAG*next = from->next;
827 if(swf_isAllowedSpriteTag(from))
828 swf_DeleteTag(0, from);
835 static int parametersChange(history_t* history, int frame)
839 willChange = willChange || history_change(history, frame, "x");
840 willChange = willChange || history_change(history, frame, "y");
841 willChange = willChange || history_change(history, frame, "scalex");
842 willChange = willChange || history_change(history, frame, "scaley");
843 willChange = willChange || history_change(history, frame, "cxform.r0");
844 willChange = willChange || history_change(history, frame, "cxform.g0");
845 willChange = willChange || history_change(history, frame, "cxform.b0");
846 willChange = willChange || history_change(history, frame, "cxform.a0");
847 willChange = willChange || history_change(history, frame, "cxform.r1");
848 willChange = willChange || history_change(history, frame, "cxform.g1");
849 willChange = willChange || history_change(history, frame, "cxform.b1");
850 willChange = willChange || history_change(history, frame, "cxform.a1");
851 willChange = willChange || history_change(history, frame, "rotate");
852 willChange = willChange || history_change(history, frame, "shear");
853 willChange = willChange || history_change(history, frame, "pivot.x");
854 willChange = willChange || history_change(history, frame, "pivot.y");
855 willChange = willChange || history_change(history, frame, "pin.x");
856 willChange = willChange || history_change(history, frame, "pin.y");
857 willChange = willChange || history_change(history, frame, "blendmode");
858 willChange = willChange || history_changeFilter(history, frame);
863 static void free_filterlist(FILTERLIST* f_list)
866 for (i = 0; i < f_list->num; i++)
868 if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
869 gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
870 free(f_list->filter[i]);
875 static void readParameters(history_t* history, parameters_t* p, int frame)
877 p->x = history_value(history, frame, "x");
878 p->y = history_value(history, frame, "y");
879 p->scalex = history_value(history, frame, "scalex");
880 p->scaley = history_value(history, frame, "scaley");
881 p->cxform.r0 = history_value(history, frame, "cxform.r0");
882 p->cxform.g0 = history_value(history, frame, "cxform.g0");
883 p->cxform.b0 = history_value(history, frame, "cxform.b0");
884 p->cxform.a0 = history_value(history, frame, "cxform.a0");
885 p->cxform.r1 = history_value(history, frame, "cxform.r1");
886 p->cxform.g1 = history_value(history, frame, "cxform.g1");
887 p->cxform.b1 = history_value(history, frame, "cxform.b1");
888 p->cxform.a1 = history_value(history, frame, "cxform.a1");
889 p->rotate = history_rotateValue(history, frame);
890 p->shear = history_value(history, frame, "shear");
891 p->pivot.x = history_value(history, frame, "pivot.x");
892 p->pivot.y = history_value(history, frame, "pivot.y");
893 p->pin.x = history_value(history, frame, "pin.x");
894 p->pin.y = history_value(history, frame, "pin.y");
895 p->blendmode = history_value(history, frame, "blendmode");
896 p->filters = history_filterValue(history, frame);
899 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, const char*name, parameters_t*p, char move)
903 swf_GetPlaceObject(NULL, &po);
907 po.cxform = p->cxform;
908 po.name = (char*)name;
913 po.blendmode = p->blendmode;
916 po.filters = p->filters;
917 swf_SetPlaceObject(tag, &po);
920 static void writeInstance(void* _i)
922 instance_t*i = (instance_t*)_i;
925 int frame = i->history->firstFrame;
926 TAG* tag = i->history->firstTag;
927 history_processFlags(i->history);
928 while (tag && frame < currentframe)
931 while (tag && tag->id != ST_SHOWFRAME)
933 if (parametersChange(i->history, frame))
935 readParameters(i->history, &p, frame);
936 m = s_instancepos(i->character->size, &p);
938 if(p.blendmode || p.filters)
939 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
941 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
942 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
944 free_filterlist(p.filters);
951 void dumpSWF(SWF*swf)
953 TAG* tag = swf->firstTag;
954 printf("vvvvvvvvvvvvvvvvvvvvv\n");
956 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
959 printf("^^^^^^^^^^^^^^^^^^^^^\n");
962 static void s_endSprite()
964 SRECT r = currentrect;
969 dict_foreach_value(&instances, writeInstance);
971 if(stack[stackpos].cut)
972 tag = removeFromTo(stack[stackpos].cut, tag);
974 // the writeInstance loop above may have inserted tags after what used to be the current tag,
975 // so let's make sure 'tag' point to the current tag again.
979 tag = swf_InsertTag(tag, ST_SHOWFRAME);
980 tag = swf_InsertTag(tag, ST_END);
982 tag = stack[stackpos].tag;
985 if(stack[stackpos].scalegrid.xmin | stack[stackpos].scalegrid.ymin |
986 stack[stackpos].scalegrid.xmax | stack[stackpos].scalegrid.ymax)
988 tag = swf_InsertTag(tag, ST_DEFINESCALINGGRID);
989 swf_SetU16(tag, stack[stackpos].id);
990 swf_SetRect(tag, &stack[stackpos].scalegrid);
994 syntaxerror("internal error(7)");
995 /* TODO: before clearing, prepend "<spritename>." to names and
996 copy into old instances dict */
997 dict_free_all(&instances, 1, free_instance);
999 currentframe = stack[stackpos].oldframe;
1000 currentrect = stack[stackpos].oldrect;
1001 currentdepth = stack[stackpos].olddepth;
1002 instances = stack[stackpos].oldinstances;
1004 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
1005 free(stack[stackpos].name);
1008 static void s_endSWF()
1014 dict_foreach_value(&instances, writeInstance);
1016 if(stack[stackpos].cut)
1017 tag = removeFromTo(stack[stackpos].cut, tag);
1021 swf = stack[stackpos].swf;
1022 filename = stack[stackpos].filename;
1024 // the writeInstance loop above may have inserted tags after what used yo be the current tag,
1025 // so let's make sure 'tag' point to the current tag again.
1029 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1030 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
1031 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1034 TAG*tag = swf->firstTag;
1035 tag = swf_InsertTag(tag, ST_DOABC);
1036 void*code = as3_getcode();
1037 swf_WriteABC(tag, code);
1038 if(as3_getglobalclass()) {
1039 tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
1042 swf_SetString(tag, as3_getglobalclass());
1044 warning("no global public MovieClip subclass");
1049 tag = swf_InsertTag(tag, ST_END);
1051 swf_OptimizeTagOrder(swf);
1057 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1058 swf->movieSize = currentrect; /* "autocrop" */
1061 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1062 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1063 swf->movieSize.ymax += 20;
1064 warning("Empty bounding box for movie");
1067 if(do_cgi || !strcmp(filename, "-"))
1068 fi = fileno(stdout);
1070 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1072 syntaxerror("couldn't create output file %s", filename);
1075 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1077 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1091 if(stack[stackpos-1].type == 0)
1092 syntaxerror("End of file encountered in .flash block");
1093 if(stack[stackpos-1].type == 1)
1094 syntaxerror("End of file encountered in .sprite block");
1095 if(stack[stackpos-1].type == 2)
1096 syntaxerror("End of file encountered in .clip block");
1102 return currentframe+1;
1105 void s_frame(int nr, int cut, const char*name, char anchor)
1111 syntaxerror("Illegal frame number");
1112 nr--; // internally, frame 1 is frame 0
1114 for(t=currentframe;t<nr;t++) {
1115 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1116 if(t==nr-1 && name && *name) {
1117 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1118 swf_SetString(tag, name);
1120 swf_SetU8(tag, 1); //make this an anchor
1123 if(nr == 0 && currentframe == 0 && name && *name) {
1124 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1125 swf_SetString(tag, name);
1127 swf_SetU8(tag, 1); //make this an anchor
1132 syntaxerror("Can't cut, frame empty");
1134 stack[stackpos].cut = tag;
1140 int parseColor2(const char*str, RGBA*color);
1142 int addFillStyle(SHAPE*s, SRECT*r, const char*name)
1146 gradient_t*gradient;
1148 if(name[0] == '#') {
1149 parseColor2(name, &color);
1150 return swf_ShapeAddSolidFillStyle(s, &color);
1151 } else if ((texture = dict_lookup(&textures, name))) {
1152 return swf_ShapeAddFillStyle2(s, &texture->fs);
1153 } else if((image = dict_lookup(&images, name))) {
1155 swf_GetMatrix(0, &m);
1156 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1157 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1160 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1161 } else if ((gradient = dict_lookup(&gradients, name))) {
1165 swf_GetMatrix(0, &rot);
1166 ccos = cos(-gradient->rotate*2*M_PI/360);
1167 csin = sin(-gradient->rotate*2*M_PI/360);
1168 rot.sx = ccos*65536;
1169 rot.r1 = -csin*65536;
1170 rot.r0 = csin*65536;
1171 rot.sy = ccos*65536;
1172 r2 = swf_TurnRect(*r, &rot);
1173 swf_GetMatrix(0, &m);
1174 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1175 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1176 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1177 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1178 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1179 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1180 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1181 } else if (parseColor2(name, &color)) {
1182 return swf_ShapeAddSolidFillStyle(s, &color);
1184 syntaxerror("not a color/fillstyle: %s", name);
1189 RGBA black={r:0,g:0,b:0,a:0};
1190 void s_box(const char*name, int width, int height, RGBA color, int linewidth, const char*texture)
1199 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1202 linewidth = linewidth>=20?linewidth-20:0;
1203 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1206 fs1 = addFillStyle(s, &r2, texture);
1209 r.xmin = r2.xmin-linewidth/2;
1210 r.ymin = r2.ymin-linewidth/2;
1211 r.xmax = r2.xmax+linewidth/2;
1212 r.ymax = r2.ymax+linewidth/2;
1213 swf_SetRect(tag,&r);
1214 swf_SetShapeHeader(tag,s);
1215 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1216 swf_ShapeSetLine(tag,s,width,0);
1217 swf_ShapeSetLine(tag,s,0,height);
1218 swf_ShapeSetLine(tag,s,-width,0);
1219 swf_ShapeSetLine(tag,s,0,-height);
1220 swf_ShapeSetEnd(tag);
1223 s_addcharacter(name, id, tag, r);
1227 void s_filled(const char*name, const char*outlinename, RGBA color, int linewidth, const char*texture)
1233 outline = dict_lookup(&outlines, outlinename);
1235 syntaxerror("outline %s not defined", outlinename);
1239 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1242 linewidth = linewidth>=20?linewidth-20:0;
1243 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1246 fs1 = addFillStyle(s, &r2, texture);
1249 rect.xmin = r2.xmin-linewidth/2;
1250 rect.ymin = r2.ymin-linewidth/2;
1251 rect.xmax = r2.xmax+linewidth/2;
1252 rect.ymax = r2.ymax+linewidth/2;
1254 swf_SetRect(tag,&rect);
1255 swf_SetShapeStyles(tag, s);
1256 swf_ShapeCountBits(s,0,0);
1257 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1258 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1259 swf_SetShapeBits(tag, s);
1260 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1263 s_addcharacter(name, id, tag, rect);
1267 void s_circle(const char*name, int r, RGBA color, int linewidth, const char*texture)
1272 r2.xmin = r2.ymin = 0;
1276 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1279 linewidth = linewidth>=20?linewidth-20:0;
1280 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1283 fs1 = addFillStyle(s, &r2, texture);
1285 rect.xmin = r2.xmin-linewidth/2;
1286 rect.ymin = r2.ymin-linewidth/2;
1287 rect.xmax = r2.xmax+linewidth/2;
1288 rect.ymax = r2.ymax+linewidth/2;
1290 swf_SetRect(tag,&rect);
1291 swf_SetShapeHeader(tag,s);
1292 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1293 swf_ShapeSetCircle(tag, s, r,r,r,r);
1294 swf_ShapeSetEnd(tag);
1297 s_addcharacter(name, id, tag, rect);
1301 void s_textshape(const char*name, const char*fontname, float size, const char*_text)
1304 U8*text = (U8*)_text;
1308 font = dict_lookup(&fonts, fontname);
1310 syntaxerror("font \"%s\" not known!", fontname);
1312 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1313 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1314 s_box(name, 0, 0, black, 20, 0);
1317 g = font->ascii2glyph[text[0]];
1319 outline = malloc(sizeof(outline_t));
1320 memset(outline, 0, sizeof(outline_t));
1321 outline->shape = font->glyph[g].shape;
1322 outline->bbox = font->layout->bounds[g];
1326 swf_Shape11DrawerInit(&draw, 0);
1327 swf_DrawText(&draw, font, (int)(size*100), (char*)_text);
1329 outline->shape = swf_ShapeDrawerToShape(&draw);
1330 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1331 draw.dealloc(&draw);
1334 if(dict_lookup(&outlines, name))
1335 syntaxerror("outline %s defined twice", name);
1336 dict_put(&outlines, name, outline);
1339 void s_text(const char*name, const char*fontname, const char*text, int size, RGBA color)
1344 font = dict_lookup(&fonts, fontname);
1346 syntaxerror("font \"%s\" not known!", fontname);
1348 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1349 swf_SetU16(tag, id);
1350 if(!font->numchars) {
1351 s_box(name, 0, 0, black, 20, 0);
1354 r = swf_SetDefineText(tag, font, &color, (char*)text, size);
1356 if(stack[0].swf->fileVersion >= 8) {
1357 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1358 swf_SetU16(tag, id);
1359 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1360 swf_SetU32(tag, 0);//thickness
1361 swf_SetU32(tag, 0);//sharpness
1362 swf_SetU8(tag, 0);//reserved
1365 s_addcharacter(name, id, tag, r);
1369 void s_quicktime(const char*name, const char*url)
1374 memset(&r, 0, sizeof(r));
1376 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1377 swf_SetU16(tag, id);
1378 swf_SetString(tag, url);
1380 s_addcharacter(name, id, tag, r);
1384 void s_video(const char *name, int width, int height)
1388 memset(&r, 0, sizeof(r));
1390 tag = swf_InsertTag(tag, ST_DEFINEVIDEOSTREAM);
1391 swf_SetU16(tag, id);
1392 swf_SetU16(tag, 0); // numframes
1393 swf_SetU16(tag, width);
1394 swf_SetU16(tag, height);
1395 swf_SetU8(tag, 0); // videoflags
1396 swf_SetU8(tag, 0); // codecid
1398 s_addcharacter(name, id, tag, r);
1402 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)
1405 EditTextLayout layout;
1408 if(fontname && *fontname) {
1409 flags |= ET_USEOUTLINES;
1410 font = dict_lookup(&fonts, fontname);
1412 syntaxerror("font \"%s\" not known!", fontname);
1414 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1415 swf_SetU16(tag, id);
1416 layout.align = align;
1417 layout.leftmargin = 0;
1418 layout.rightmargin = 0;
1426 swf_SetEditText(tag, flags, r, (char*)text, color, maxlength, font?font->id:0, size, &layout, (char*)variable);
1428 s_addcharacter(name, id, tag, r);
1432 /* type: either "jpeg" or "png"
1434 void s_image(const char*name, const char*type, const char*filename, int quality)
1436 /* an image is actually two folded: 1st bitmap, 2nd character.
1437 Both of them can be used separately */
1439 /* step 1: the bitmap */
1443 if(!strcmp(type,"jpeg")) {
1444 #ifndef HAVE_JPEGLIB
1445 warning("no jpeg support compiled in");
1446 s_box(name, 0, 0, black, 20, 0);
1449 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1450 swf_SetU16(tag, imageID);
1452 if(swf_SetJPEGBits(tag, (char*)filename, quality) < 0) {
1453 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1456 swf_GetJPEGSize(filename, &width, &height);
1463 s_addimage(name, id, tag, r);
1466 } else if(!strcmp(type,"png")) {
1468 swf_SetU16(tag, imageID);
1470 getPNG(filename, &width, &height, (unsigned char**)&data);
1473 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1476 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1477 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1478 swf_SetU16(tag, imageID);
1479 swf_SetLosslessImage(tag, data, width, height);
1486 s_addimage(name, id, tag, r);
1489 warning("image type \"%s\" not supported yet!", type);
1490 s_box(name, 0, 0, black, 20, 0);
1494 /* step 2: the character */
1495 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1496 swf_SetU16(tag, id);
1497 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1499 s_addcharacter(name, id, tag, r);
1503 void s_getBitmapSize(const char*name, int*width, int*height)
1505 character_t* image = dict_lookup(&images, name);
1506 gradient_t* gradient = dict_lookup(&gradients,name);
1508 *width = image->size.xmax;
1509 *height = image->size.ymax;
1513 /* internal SWF gradient size */
1514 if(gradient->radial) {
1523 syntaxerror("No such bitmap/gradient: %s", name);
1526 void s_texture(const char*name, const char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1528 if(dict_lookup(&textures, name))
1529 syntaxerror("texture %s defined twice", name);
1530 gradient_t* gradient = dict_lookup(&gradients, object);
1531 character_t* bitmap = dict_lookup(&images, object);
1532 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1534 FILLSTYLE*fs = &texture->fs;
1536 memset(&p, 0, sizeof(parameters_t));
1539 fs->type = FILL_TILED;
1540 fs->id_bitmap = bitmap->id;
1541 } else if(gradient) {
1542 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1543 fs->gradient = gradient->gradient;
1545 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1546 makeMatrix(&fs->m, &p);
1547 if(gradient && !gradient->radial) {
1554 p2 = swf_TurnPoint(p1, &m);
1563 dict_put(&textures, name, texture);
1566 void s_font(const char*name, const char*filename)
1569 font = dict_lookup(&fonts, name);
1572 /* fix the layout. Only needed for old fonts */
1574 for(t=0;t<font->numchars;t++) {
1575 font->glyph[t].advance = 0;
1578 swf_FontCreateLayout(font);
1581 swf_FontReduce_swfc(font);
1582 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1583 swf_FontSetDefine2(tag, font);
1585 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1587 swf_SetU16(tag, id);
1588 swf_SetString(tag, name);
1596 typedef struct _sound_t
1602 void s_sound(const char*name, const char*filename)
1604 struct WAV wav, wav2;
1608 unsigned numsamples = 1;
1609 unsigned blocksize = 1152;
1612 if(dict_lookup(&sounds, name))
1613 syntaxerror("sound %s defined twice", name);
1615 if(wav_read(&wav, filename))
1618 wav_convert2mono(&wav, &wav2, 44100);
1619 samples = (U16*)wav2.data;
1620 numsamples = wav2.size/2;
1622 #ifdef WORDS_BIGENDIAN
1624 for(t=0;t<numsamples;t++)
1625 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1629 if(mp3_read(&mp3, filename))
1631 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1637 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1642 if(numsamples%blocksize != 0)
1644 // apply padding, so that block is a multiple of blocksize
1645 int numblocks = (numsamples+blocksize-1)/blocksize;
1648 numsamples2 = numblocks * blocksize;
1649 samples2 = malloc(sizeof(U16)*numsamples2);
1650 memcpy(samples2, samples, numsamples*sizeof(U16));
1651 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1652 numsamples = numsamples2;
1657 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1658 swf_SetU16(tag, id); //id
1661 swf_SetSoundDefineMP3(
1662 tag, mp3.data, mp3.size,
1669 swf_SetSoundDefine(tag, samples, numsamples);
1672 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1673 swf_SetU16(tag, id);
1674 swf_SetString(tag, name);
1675 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1677 swf_SetU16(tag, id);
1678 swf_SetString(tag, name);
1681 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1685 dict_put(&sounds, name, sound);
1693 static char* gradient_getToken(const char**p)
1697 while(**p && strchr(" \t\n\r", **p)) {
1701 while(**p && !strchr(" \t\n\r", **p)) {
1704 result = malloc((*p)-start+1);
1705 memcpy(result,start,(*p)-start+1);
1706 result[(*p)-start] = 0;
1710 float parsePercent(const char*str);
1711 RGBA parseColor(const char*str);
1713 GRADIENT parseGradient(const char*str)
1717 const char* p = str;
1718 memset(&gradient, 0, sizeof(GRADIENT));
1719 gradient.ratios = rfx_calloc(16*sizeof(U8));
1720 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1724 char*posstr,*colorstr;
1727 posstr = gradient_getToken(&p);
1733 pos = (int)(parsePercent(posstr)*255.0);
1738 rfx_free(gradient.ratios);
1739 rfx_free(gradient.rgba);
1741 syntaxerror("Error in shape data: Color expected after %s", posstr);
1743 colorstr = gradient_getToken(&p);
1744 color = parseColor(colorstr);
1745 if(gradient.num == 16)
1747 warning("gradient record too big- max size is 16, rest ignored");
1750 gradient.ratios[gradient.num] = pos;
1751 gradient.rgba[gradient.num] = color;
1760 FILTERLIST* parseFilters(char* list)
1762 if (!strcmp(list, "no_filters"))
1765 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1767 char* f_start = list;
1771 f_end = strchr(f_start, ',');
1774 f = dict_lookup(&filters, f_start);
1778 syntaxerror("unknown filter %s", f_start);
1780 if (f_list->num == 8)
1782 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1785 f_list->filter[f_list->num] = f;
1790 f_start = f_end + 1;
1798 void s_gradient(const char*name, const char*text, int radial, int rotate)
1800 gradient_t* gradient;
1801 gradient = malloc(sizeof(gradient_t));
1802 memset(gradient, 0, sizeof(gradient_t));
1803 gradient->gradient = parseGradient(text);
1804 gradient->radial = radial;
1805 gradient->rotate = rotate;
1807 dict_put(&gradients, name, gradient);
1810 void s_gradientglow(const char*name, const char*gradient, float blurx, float blury,
1811 float angle, float distance, float strength, char innershadow,
1812 char knockout, char composite, char ontop, int passes)
1814 if(dict_lookup(&filters, name))
1815 syntaxerror("filter %s defined twice", name);
1817 gradient_t* g = dict_lookup(&gradients, gradient);
1819 syntaxerror("unknown gradient %s", gradient);
1823 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1824 filter->type = FILTERTYPE_GRADIENTGLOW;
1825 filter->gradient = &g->gradient;
1826 filter->blurx = blurx;
1827 filter->blury = blury;
1828 filter->strength = strength;
1829 filter->angle = angle;
1830 filter->distance = distance;
1831 filter->innershadow = innershadow;
1832 filter->knockout = knockout;
1833 filter->composite = composite;
1834 filter->ontop = ontop;
1835 filter->passes = passes;
1837 dict_put(&filters, name, filter);
1840 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)
1842 if(dict_lookup(&filters, name))
1843 syntaxerror("filter %s defined twice", name);
1846 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1847 filter->type = FILTERTYPE_DROPSHADOW;
1848 filter->color= color;
1849 filter->blurx = blurx;
1850 filter->blury = blury;
1851 filter->strength = strength;
1852 filter->angle = angle;
1853 filter->distance = distance;
1854 filter->innershadow = innershadow;
1855 filter->knockout = knockout;
1856 filter->composite = composite;
1857 filter->passes = passes;
1859 dict_put(&filters, name, filter);
1862 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)
1864 if(dict_lookup(&filters, name))
1865 syntaxerror("filter %s defined twice", name);
1868 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1869 filter->type = FILTERTYPE_BEVEL;
1870 filter->shadow = shadow;
1871 filter->highlight = highlight;
1872 filter->blurx = blurx;
1873 filter->blury = blury;
1874 filter->strength = strength;
1875 filter->angle = angle;
1876 filter->distance = distance;
1877 filter->innershadow = innershadow;
1878 filter->knockout = knockout;
1879 filter->composite = composite;
1880 filter->ontop = ontop;
1881 filter->passes = passes;
1883 dict_put(&filters, name, filter);
1886 void s_blur(const char*name, double blurx, double blury, int passes)
1888 if(dict_lookup(&filters, name))
1889 syntaxerror("filter %s defined twice", name);
1891 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1892 filter->type = FILTERTYPE_BLUR;
1893 filter->blurx = blurx;
1894 filter->blury = blury;
1895 filter->passes = passes;
1897 dict_put(&filters, name, filter);
1900 void s_action(const char*text)
1902 if(stack[0].swf->fileVersion < 9) {
1904 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1907 syntaxerror("Couldn't compile ActionScript");
1909 tag = swf_InsertTag(tag, ST_DOACTION);
1910 swf_ActionSet(tag, a);
1913 as3_parse_bytearray(stack[0].filename, text, strlen(text));
1918 void s_initaction(const char*character, const char*text)
1922 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1926 syntaxerror("Couldn't compile ActionScript");
1929 c = (character_t*)dict_lookup(&characters, character);
1931 tag = swf_InsertTag(tag, ST_DOINITACTION);
1932 swf_SetU16(tag, c->id);
1933 swf_ActionSet(tag, a);
1938 int s_swf3action(const char*name, const char*action)
1941 instance_t* object = 0;
1943 object = (instance_t*)dict_lookup(&instances, name);
1944 if(!object && name && *name) {
1945 /* we have a name, but couldn't find it. Abort. */
1948 a = action_SetTarget(0, name);
1949 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1950 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1951 else if(!strcmp(action, "stop")) a = action_Stop(a);
1952 else if(!strcmp(action, "play")) a = action_Play(a);
1953 a = action_SetTarget(a, "");
1956 tag = swf_InsertTag(tag, ST_DOACTION);
1957 swf_ActionSet(tag, a);
1962 void s_outline(const char*name, const char*format, const char*source)
1964 if(dict_lookup(&outlines, name))
1965 syntaxerror("outline %s defined twice", name);
1974 //swf_Shape10DrawerInit(&draw, 0);
1975 swf_Shape11DrawerInit(&draw, 0);
1977 draw_string(&draw, source);
1979 shape = swf_ShapeDrawerToShape(&draw);
1980 bounds = swf_ShapeDrawerGetBBox(&draw);
1981 draw.dealloc(&draw);
1983 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1984 outline->shape = shape;
1985 outline->bbox = bounds;
1987 dict_put(&outlines, name, outline);
1990 int s_playsound(const char*name, int loops, int nomultiple, int stop)
1996 sound = dict_lookup(&sounds, name);
2000 tag = swf_InsertTag(tag, ST_STARTSOUND);
2001 swf_SetU16(tag, sound->id); //id
2002 memset(&info, 0, sizeof(info));
2005 info.nomultiple = nomultiple;
2006 swf_SetSoundInfo(tag, &info);
2010 void s_includeswf(const char*name, const char*filename)
2018 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
2019 f = open(filename,O_RDONLY|O_BINARY);
2021 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
2022 s_box(name, 0, 0, black, 20, 0);
2025 if (swf_ReadSWF(f,&swf)<0) {
2026 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
2027 s_box(name, 0, 0, black, 20, 0);
2032 /* FIXME: The following sets the bounding Box for the character.
2033 It is wrong for two reasons:
2034 a) It may be too small (in case objects in the movie clip at the borders)
2035 b) it may be too big (because the poor movie never got autocropped)
2039 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2040 swf_SetU16(tag, id);
2041 swf_SetU16(tag, swf.frameCount);
2043 swf_Relocate(&swf, idmap);
2045 ftag = swf.firstTag;
2049 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2050 if(cutout[t] == ftag->id) {
2054 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2056 if(ftag->id == ST_END)
2061 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2062 /* We simply dump all tags right after the sprite
2063 header, relying on the fact that swf_OptimizeTagOrder() will
2064 sort things out for us later.
2065 We also rely on the fact that the imported SWF is well-formed.
2067 tag = swf_InsertTag(tag, ftag->id);
2068 swf_SetBlock(tag, ftag->data, ftag->len);
2074 syntaxerror("Included file %s contains errors", filename);
2075 tag = swf_InsertTag(tag, ST_END);
2079 s_addcharacter(name, id, tag, r);
2082 SRECT s_getCharBBox(const char*name)
2084 character_t* c = dict_lookup(&characters, name);
2085 if(!c) syntaxerror("character '%s' unknown(2)", name);
2088 SRECT s_getInstanceBBox(const char*name)
2090 instance_t * i = dict_lookup(&instances, name);
2092 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2094 if(!c) syntaxerror("internal error(5)");
2097 void s_getParameters(const char*name, parameters_t* p)
2099 instance_t * i = dict_lookup(&instances, name);
2101 syntaxerror("instance '%s' unknown(10)", name);
2102 if (change_sets_all)
2103 readParameters(i->history, p, currentframe);
2108 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2110 history_begin(i->history, "x", currentframe, tag, p->x);
2111 history_begin(i->history, "y", currentframe, tag, p->y);
2112 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2113 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2114 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2115 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2116 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2117 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2118 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2119 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2120 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2121 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2122 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2123 history_begin(i->history, "shear", currentframe, tag, p->shear);
2124 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2125 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2126 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2127 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2128 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2129 history_beginFilter(i->history, currentframe, tag, p->filters);
2130 history_begin(i->history, "flags", currentframe, tag, 0);
2133 void s_startclip(const char*instance, const char*character, parameters_t p)
2135 character_t* c = dict_lookup(&characters, character);
2139 syntaxerror("character %s not known", character);
2141 i = s_addinstance(instance, c, currentdepth);
2143 m = s_instancepos(i->character->size, &p);
2145 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2146 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2147 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2149 stack[stackpos].tag = tag;
2150 stack[stackpos].type = 2;
2153 setStartparameters(i, &p, tag);
2160 swf_SetTagPos(stack[stackpos].tag, 0);
2161 swf_GetPlaceObject(stack[stackpos].tag, &p);
2162 p.clipdepth = currentdepth;
2164 swf_ClearTag(stack[stackpos].tag);
2165 swf_SetPlaceObject(stack[stackpos].tag, &p);
2169 void s_put(const char*instance, const char*character, parameters_t p)
2171 character_t* c = dict_lookup(&characters, character);
2175 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2177 i = s_addinstance(instance, c, currentdepth);
2179 m = s_instancepos(i->character->size, &p);
2181 if(p.blendmode || p.filters)
2183 if(stack[0].swf->fileVersion < 8)
2186 warning("blendmodes only supported for flash version>=8");
2188 warning("filters only supported for flash version>=8");
2190 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2193 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2194 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2195 setStartparameters(i, &p, tag);
2199 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2202 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2204 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2205 if (p.set & SF_SCALEX)
2206 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2207 if (p.set & SF_SCALEY)
2208 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2209 if (p.set & SF_CX_R)
2211 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2212 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2214 if (p.set & SF_CX_G)
2216 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2217 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2219 if (p.set & SF_CX_B)
2221 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2222 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2224 if (p.set & SF_CX_A)
2226 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2227 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2229 if (p.set & SF_ROTATE)
2230 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2231 if (p.set & SF_SHEAR)
2232 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2233 if (p.set & SF_PIVOT)
2235 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2236 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2240 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2241 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2243 if (p.set & SF_BLEND)
2244 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2245 if (p.set & SF_FILTER)
2246 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2249 void s_jump(const char* instance, parameters_t p)
2251 instance_t* i = dict_lookup(&instances, instance);
2253 syntaxerror("instance %s not known", instance);
2254 recordChanges(i->history, p, CF_JUMP, 0);
2257 void s_change(const char*instance, parameters_t p, interpolation_t* inter)
2259 instance_t* i = dict_lookup(&instances, instance);
2261 syntaxerror("instance %s not known", instance);
2262 recordChanges(i->history, p, CF_CHANGE, inter);
2265 void s_sweep(const char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2267 instance_t* i = dict_lookup(&instances, instance);
2269 syntaxerror("instance %s not known", instance);
2270 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2273 void s_toggle(const char* instance, U16 flagsOn, U16 flagsOff)
2275 instance_t* i = dict_lookup(&instances, instance);
2277 syntaxerror("instance %s not known", instance);
2278 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2281 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2284 void s_delinstance(const char*instance)
2286 instance_t* i = dict_lookup(&instances, instance);
2288 syntaxerror("instance %s not known", instance);
2290 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2291 swf_SetU16(tag, i->depth);
2292 dict_del(&instances, instance);
2296 void s_schange(const char*instance, parameters_t p, interpolation_t* inter)
2298 instance_t* i = dict_lookup(&instances, instance);
2300 syntaxerror("instance %s not known", instance);
2301 recordChanges(i->history, p, CF_SCHANGE, inter);
2307 syntaxerror(".end unexpected");
2308 switch (stack[stackpos-1].type)
2323 syntaxerror("internal error 1");
2327 // ------------------------------------------------------------------------
2329 typedef int command_func_t(map_t*args);
2331 SRECT parseBox(const char*str)
2333 SRECT r = {0,0,0,0};
2334 float xmin, xmax, ymin, ymax;
2335 char*x = strchr(str, 'x');
2337 if(!strcmp(str, "autocrop")) {
2338 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2342 d1 = strchr(x+1, ':');
2344 d2 = strchr(d1+1, ':');
2346 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2350 else if(d1 && !d2) {
2351 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2357 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2362 r.xmin = (SCOORD)(xmin*20);
2363 r.ymin = (SCOORD)(ymin*20);
2364 r.xmax = (SCOORD)(xmax*20);
2365 r.ymax = (SCOORD)(ymax*20);
2368 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2371 float parseFloat(const char*str)
2375 int parseInt(const char*str)
2380 if(str[0]=='+' || str[0]=='-')
2384 if(str[t]<'0' || str[t]>'9')
2385 syntaxerror("Not an Integer: \"%s\"", str);
2388 static double parseRawTwip(const char*str)
2392 if(str[0]=='+' || str[0]=='-') {
2397 dot = strchr(str, '.');
2401 return sign*parseInt(str);
2403 char* old = strdup(str);
2404 int l=strlen(dot+1);
2407 for(s=str;s<dot-1;s++) {
2408 if(*s<'0' || *s>'9')
2411 syntaxerror("Not a coordinate: \"%s\"", str);
2415 if(*s<'0' || *s>'9')
2418 syntaxerror("Not a coordinate: \"%s\"", str);
2421 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2422 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2425 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2429 return sign*(atoi(str));
2431 return sign*(atoi(str)+0.1*atoi(dot));
2433 return sign*(atoi(str)+0.01*atoi(dot));
2438 static dict_t defines;
2439 static int defines_initialized = 0;
2440 static mem_t define_values;
2442 static double parseNameOrTwip(const char*s)
2446 if(defines_initialized) {
2447 l = (int)dict_lookup(&defines, s);
2450 return *(int*)&define_values.buffer[l-1];
2452 return parseRawTwip(s);
2456 /* automatically generated by yiyiyacc, http://www.quiss.org/yiyiyacc/ */
2457 static double parseExpression(char*s)
2460 memset(chr2index, -1, sizeof(chr2index));
2467 chr2index['\0'] = 7;
2475 int left[10]={11,8,8,8,8,9,9,9,10,10}; //production left side
2476 int plen[10]={1,3,2,3,1,3,3,1,1,3}; //production size
2477 int table[18][12] = {
2478 {0, 4, 0, 0, 5, 6, 0, 0, 1, 2, 3, 0},
2479 {7, 8, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0},
2480 {-4, -4, 9, 10, 0, 0, -4, -4, 0, 0, 0, 0},
2481 {-7, -7, -7, -7, 0, 0, -7, -7, 0, 0, 0, 0},
2482 {0, 0, 0, 0, 5, 6, 0, 0, 0, 11, 3, 0},
2483 {-8, -8, -8, -8, 0, 0, -8, -8, 0, 0, 0, 0},
2484 {0, 4, 0, 0, 5, 6, 0, 0, 12, 2, 3, 0},
2485 {0, 0, 0, 0, 5, 6, 0, 0, 0, 13, 3, 0},
2486 {0, 0, 0, 0, 5, 6, 0, 0, 0, 14, 3, 0},
2487 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 15, 0},
2488 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 16, 0},
2489 {-2, -2, 9, 10, 0, 0, -2, -2, 0, 0, 0, 0},
2490 {7, 8, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0},
2491 {-1, -1, 9, 10, 0, 0, -1, -1, 0, 0, 0, 0},
2492 {-3, -3, 9, 10, 0, 0, -3, -3, 0, 0, 0, 0},
2493 {-5, -5, -5, -5, 0, 0, -5, -5, 0, 0, 0, 0},
2494 {-6, -6, -6, -6, 0, 0, -6, -6, 0, 0, 0, 0},
2495 {-9, -9, -9, -9, 0, 0, -9, -9, 0, 0, 0, 0}};
2503 fprintf(stderr, "Error in expression\n");
2507 if(chr2index[*p]<0) {
2508 action = table[stack[stackpos-1]][4];
2510 while(chr2index[*pnext]<0)
2514 value = parseNameOrTwip(p);
2518 action = table[stack[stackpos-1]][chr2index[*p]];
2521 if(action == accept) {
2522 return values[stack[stackpos-1]];
2523 } else if(action>0) { // shift
2525 fprintf(stderr, "Stack overflow while parsing expression\n");
2528 values[stackpos]=value;
2529 stack[stackpos++]=action;
2531 } else if(action<0) { // reduce
2532 stackpos-=plen[-action];
2533 stack[stackpos] = table[stack[stackpos-1]][left[-action]];
2536 values[stackpos] = values[stackpos+0] + values[stackpos+2];
2539 values[stackpos] = 0 - values[stackpos+1];
2542 values[stackpos] = values[stackpos+0] - values[stackpos+2];
2545 values[stackpos] = values[stackpos+0] * values[stackpos+2];
2548 values[stackpos] = values[stackpos+0] / values[stackpos+2];
2551 values[stackpos] = values[stackpos+1];
2556 fprintf(stderr, "Syntax error in expression\n");
2562 int parseTwip(const char*str)
2564 char*str2 = (char*)str;
2565 int v = (int)(parseExpression(str2)*20);
2569 int parseArc(const char* str)
2571 if (!strcmp(str, "short"))
2573 if (!strcmp(str, "long"))
2575 syntaxerror("invalid value for the arc parameter: %s", str);
2579 int parseDir(const char* str)
2581 if (!strcmp(str, "clockwise"))
2583 if (!strcmp(str, "counterclockwise"))
2585 syntaxerror("invalid value for the dir parameter: %s", str);
2589 int isPoint(const char*str)
2591 if(strchr(str, '('))
2597 SPOINT parsePoint(const char*str)
2601 int l = strlen(str);
2602 char*comma = strchr(str, ',');
2603 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2604 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2605 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2606 p.x = parseTwip(tmp);
2607 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2608 p.y = parseTwip(tmp);
2612 int parseColor2(const char*str, RGBA*color)
2614 int l = strlen(str);
2618 struct {unsigned char r,g,b;char*name;} colors[] =
2619 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2620 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2621 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2622 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2623 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2624 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2625 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2626 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2627 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2628 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2629 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2630 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2634 if(str[0]=='#' && (l==7 || l==9)) {
2635 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2637 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2639 color->r = r; color->g = g; color->b = b; color->a = a;
2642 int len=strlen(str);
2644 if(strchr(str, '/')) {
2645 len = strchr(str, '/')-str;
2646 sscanf(str+len+1,"%02x", &alpha);
2648 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2649 if(!strncmp(str, colors[t].name, len)) {
2654 color->r = r; color->g = g; color->b = b; color->a = a;
2660 RGBA parseColor(const char*str)
2663 if(!parseColor2(str, &c))
2664 syntaxerror("Expression '%s' is not a color", str);
2668 typedef struct _muladd {
2673 MULADD parseMulAdd(const char*str)
2676 char* str2 = (char*)malloc(strlen(str)+5);
2683 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2684 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2685 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2686 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2687 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2688 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2689 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2690 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2691 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2692 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2694 syntaxerror("'%s' is not a valid color transform expression", str);
2696 m.add = (int)(add*256);
2697 m.mul = (int)(mul*256);
2702 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2704 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2705 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2707 if(a<-32768) a=-32768;
2708 if(a>32767) a=32767;
2709 if(m<-32768) m=-32768;
2710 if(m>32767) m=32767;
2716 float parsePxOrPercent(const char*fontname, const char*str)
2718 int l = strlen(str);
2719 if(strchr(str, '%'))
2720 return parsePercent(str);
2721 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2722 float p = atof(str);
2723 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2725 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2729 float parsePercent(const char*str)
2731 int l = strlen(str);
2735 return atof(str)/100.0;
2737 syntaxerror("Expression '%s' is not a percentage", str);
2740 int isPercent(const char*str)
2742 return str[strlen(str)-1]=='%';
2744 int parseNewSize(const char*str, int size)
2747 return parsePercent(str)*size;
2749 return (int)(atof(str)*20);
2752 int isColor(char*str)
2755 return parseColor2(str, &c);
2758 static const char* lu(map_t* args, char*name)
2760 const char* value = map_lookup(args, name);
2762 map_dump(args, stdout, "");
2763 syntaxerror("internal error 2: value %s should be set", name);
2768 static int c_flash(map_t*args)
2770 const char* filename = map_lookup(args, "filename");
2771 const char* compressstr = lu(args, "compress");
2772 const char* change_modestr = lu(args, "change-sets-all");
2773 const char* exportstr = lu(args, "export");
2774 SRECT bbox = parseBox(lu(args, "bbox"));
2775 int version = parseInt(lu(args, "version"));
2776 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2777 RGBA color = parseColor(lu(args, "background"));
2780 if(!filename || !*filename) {
2781 /* for compatibility */
2782 filename = map_lookup(args, "name");
2783 if(!filename || !*filename) {
2786 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2787 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2791 if(!filename || override_outputname)
2792 filename = outputname;
2794 if(!strcmp(compressstr, "default"))
2795 compress = version>=6;
2796 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2798 else if(!strcmp(compressstr, "no"))
2800 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2802 if(!strcmp(change_modestr, "yes"))
2803 change_sets_all = 1;
2805 if(strcmp(change_modestr, "no"))
2806 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2808 do_exports=atoi(exportstr);
2810 s_swf(filename, bbox, version, fps, compress, color);
2813 int isRelative(const char*str)
2815 return !strncmp(str, "<plus>", 6) ||
2816 !strncmp(str, "<minus>", 7);
2818 const char* getOffset(const char*str)
2820 if(!strncmp(str, "<plus>", 6))
2822 if(!strncmp(str, "<minus>", 7))
2824 syntaxerror("internal error (347)");
2827 int getSign(const char*str)
2829 if(!strncmp(str, "<plus>", 6))
2831 if(!strncmp(str, "<minus>", 7))
2833 syntaxerror("internal error (348)");
2837 static dict_t points;
2838 static mem_t mpoints;
2839 static int points_initialized = 0;
2841 static int c_interpolation(map_t *args)
2844 const char* name = lu(args, "name");
2845 if (dict_lookup(&interpolations, name))
2846 syntaxerror("interpolation %s defined twice", name);
2848 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2849 const char* functionstr = lu(args, "function");
2850 inter->function = 0;
2851 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2852 if (!strcmp(functionstr,interpolationFunctions[i]))
2854 inter->function = i + 1;
2857 if (!inter->function)
2858 syntaxerror("unkown interpolation function %s", functionstr);
2859 inter->speed = parseFloat(lu(args, "speed"));
2860 inter->amplitude = parseTwip(lu(args, "amplitude"));
2861 inter->growth = parseFloat(lu(args, "growth"));
2862 inter->bounces = parseInt(lu(args, "bounces"));
2863 inter->damping = parseFloat(lu(args, "damping"));
2864 inter->slope = parseFloat(lu(args, "slope"));
2866 dict_put(&interpolations, name, inter);
2870 SPOINT getPoint(SRECT r, const char*name)
2873 if(!strcmp(name, "center")) {
2875 p.x = (r.xmin + r.xmax)/2;
2876 p.y = (r.ymin + r.ymax)/2;
2879 if (!strcmp(name, "bottom-center")) {
2881 p.x = (r.xmin + r.xmax)/2;
2885 if (!strcmp(name, "top-center")) {
2887 p.x = (r.xmin + r.xmax)/2;
2891 if (!strcmp(name, "top-left")) {
2897 if (!strcmp(name, "top-right")) {
2903 if (!strcmp(name, "bottom-right")) {
2909 if (!strcmp(name, "bottom-left")) {
2915 if (!strcmp(name, "left-center")) {
2918 p.y = (r.ymin + r.ymax)/2;
2921 if (!strcmp(name, "right-center")) {
2924 p.y = (r.ymin + r.ymax)/2;
2929 if(points_initialized)
2930 l = (int)dict_lookup(&points, name);
2932 syntaxerror("Invalid point: \"%s\".", name);
2934 return *(SPOINT*)&mpoints.buffer[l-1];
2938 static int texture2(const char*name, const char*object, map_t*args, int errors)
2941 const char*xstr = map_lookup(args, "x");
2942 const char*ystr = map_lookup(args, "y");
2943 const char*widthstr = map_lookup(args, "width");
2944 const char*heightstr = map_lookup(args, "height");
2945 const char*scalestr = map_lookup(args, "scale");
2946 const char*scalexstr = map_lookup(args, "scalex");
2947 const char*scaleystr = map_lookup(args, "scaley");
2948 const char*rotatestr = map_lookup(args, "rotate");
2949 const char* shearstr = map_lookup(args, "shear");
2950 const char* radiusstr = map_lookup(args, "r");
2952 float scalex = 1.0, scaley = 1.0;
2953 float rotate=0, shear=0;
2955 if(!*xstr && !*ystr) {
2957 syntaxerror("x and y must be set");
2960 if(*scalestr && (*scalexstr || *scaleystr)) {
2961 syntaxerror("scale and scalex/scaley can't both be set");
2964 if((*widthstr || *heightstr) && *radiusstr) {
2965 syntaxerror("width/height and radius can't both be set");
2968 widthstr = radiusstr;
2969 heightstr = radiusstr;
2971 if(!*xstr) xstr="0";
2972 if(!*ystr) ystr="0";
2973 if(!*rotatestr) rotatestr="0";
2974 if(!*shearstr) shearstr="0";
2977 scalex = scaley = parsePercent(scalestr);
2978 } else if(*scalexstr || *scaleystr) {
2979 if(scalexstr) scalex = parsePercent(scalexstr);
2980 if(scaleystr) scaley = parsePercent(scaleystr);
2981 } else if(*widthstr || *heightstr) {
2984 s_getBitmapSize(object, &width, &height);
2986 scalex = (float)parseTwip(widthstr)/(float)width;
2988 scaley = (float)parseTwip(heightstr)/(float)height;
2990 x = parseTwip(xstr);
2991 y = parseTwip(ystr);
2992 rotate = parseFloat(rotatestr);
2993 shear = parseFloat(shearstr);
2995 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
3000 static int c_texture(map_t*args)
3002 const char*name = lu(args, "instance");
3003 const char*object = lu(args, "character");
3004 return texture2(name, object, args, 1);
3007 static int c_gradient(map_t*args)
3009 const char*name = lu(args, "name");
3010 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
3011 int rotate = parseInt(lu(args, "rotate"));
3015 syntaxerror("colon (:) expected");
3017 if(dict_lookup(&gradients, name))
3018 syntaxerror("gradient %s defined twice", name);
3020 s_gradient(name, text, radial, rotate);
3022 /* check whether we also have placement information,
3023 which would make this a positioned gradient.
3024 If there is placement information, texture2() will
3025 add a texture, which has priority over the gradient.
3027 texture2(name, name, args, 0);
3031 static const char* checkFiltername(map_t* args)
3033 const char* name = lu(args, "name");
3034 if (strchr(name, ','))
3035 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
3039 static int c_blur(map_t*args)
3041 const char*name = checkFiltername(args);
3042 const char*blurstr = lu(args, "blur");
3043 const char*blurxstr = lu(args, "blurx");
3044 const char*blurystr = lu(args, "blury");
3045 float blurx=1.0, blury=1.0;
3047 blurx = parseFloat(blurstr);
3048 blury = parseFloat(blurstr);
3051 blurx = parseFloat(blurxstr);
3053 blury = parseFloat(blurystr);
3054 int passes = parseInt(lu(args, "passes"));
3055 s_blur(name, blurx, blury, passes);
3059 static int c_gradientglow(map_t*args)
3061 const char*name = checkFiltername(args);
3062 const char*gradient = lu(args, "gradient");
3063 const char*blurstr = lu(args, "blur");
3064 const char*blurxstr = lu(args, "blurx");
3065 const char*blurystr = lu(args, "blury");
3066 float blurx=1.0, blury=1.0;
3068 blurx = parseFloat(blurstr);
3069 blury = parseFloat(blurstr);
3072 blurx = parseFloat(blurxstr);
3074 blury = parseFloat(blurystr);
3076 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3077 float distance = parseFloat(lu(args, "distance"));
3078 float strength = parseFloat(lu(args, "strength"));
3079 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3080 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3081 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3082 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3083 int passes = parseInt(lu(args, "passes"));
3085 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3089 static int c_dropshadow(map_t*args)
3091 const char*name = checkFiltername(args);
3092 RGBA color = parseColor(lu(args, "color"));
3093 const char*blurstr = lu(args, "blur");
3094 const char*blurxstr = lu(args, "blurx");
3095 const char*blurystr = lu(args, "blury");
3096 float blurx=1.0, blury=1.0;
3098 blurx = parseFloat(blurstr);
3099 blury = parseFloat(blurstr);
3102 blurx = parseFloat(blurxstr);
3104 blury = parseFloat(blurystr);
3106 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3107 float distance = parseFloat(lu(args, "distance"));
3108 float strength = parseFloat(lu(args, "strength"));
3109 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3110 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3111 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3112 int passes = parseInt(lu(args, "passes"));
3114 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3118 static int c_bevel(map_t*args)
3120 const char*name = checkFiltername(args);
3121 RGBA shadow = parseColor(lu(args, "shadow"));
3122 RGBA highlight = parseColor(lu(args, "highlight"));
3123 const char*blurstr = lu(args, "blur");
3124 const char*blurxstr = lu(args, "blurx");
3125 const char*blurystr = lu(args, "blury");
3126 float blurx=1.0, blury=1.0;
3128 blurx = parseFloat(blurstr);
3129 blury = parseFloat(blurstr);
3132 blurx = parseFloat(blurxstr);
3134 blury = parseFloat(blurystr);
3136 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3137 float distance = parseFloat(lu(args, "distance"));
3138 float strength = parseFloat(lu(args, "strength"));
3139 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3140 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3141 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3142 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3143 int passes = parseInt(lu(args, "passes"));
3145 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3149 static int c_define(map_t*args)
3151 const char*name = lu(args, "name");
3152 const char*value = lu(args, "value");
3154 if(!defines_initialized) {
3155 dict_init(&defines, 16);
3156 mem_init(&define_values);
3157 defines_initialized = 1;
3159 int val = parseTwip(value);
3160 int pos = mem_put(&define_values, &val, sizeof(val));
3161 dict_put(&defines, name, (void*)(pos+1));
3164 static int c_point(map_t*args)
3166 const char*name = lu(args, "name");
3169 if(!points_initialized) {
3170 dict_init(&points, 16);
3172 points_initialized = 1;
3174 p.x = parseTwip(lu(args, "x"));
3175 p.y = parseTwip(lu(args, "y"));
3176 pos = mem_put(&mpoints, &p, sizeof(p));
3177 dict_put(&points, name, (void*)(pos+1));
3180 static int c_play(map_t*args)
3182 const char*name = lu(args, "name");
3183 const char*loop = lu(args, "loop");
3184 const char*nomultiple = lu(args, "nomultiple");
3186 if(!strcmp(nomultiple, "nomultiple"))
3189 nm = parseInt(nomultiple);
3191 if(s_playsound(name, parseInt(loop), nm, 0)) {
3193 } else if(s_swf3action(name, "play")) {
3199 static int c_stop(map_t*args)
3201 const char*name = map_lookup(args, "name");
3203 if(s_playsound(name, 0,0,1))
3205 else if(s_swf3action(name, "stop"))
3207 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3211 static int c_nextframe(map_t*args)
3213 const char*name = lu(args, "name");
3215 if(s_swf3action(name, "nextframe")) {
3218 syntaxerror("I don't know anything about movie \"%s\"", name);
3222 static int c_previousframe(map_t*args)
3224 const char*name = lu(args, "name");
3226 if(s_swf3action(name, "previousframe")) {
3229 syntaxerror("I don't know anything about movie \"%s\"", name);
3233 static int c_movement(map_t*args, int type)
3235 const char*instance = lu(args, "name");
3237 const char* xstr="";
3238 const char* ystr="";
3243 xstr = lu(args, "x");
3244 ystr = lu(args, "y");
3246 s_getParameters(instance, &p);
3251 if(isRelative(xstr))
3253 if(type == PT_PUT || type == PT_STARTCLIP)
3254 syntaxerror("relative x values not allowed for initial put or startclip");
3255 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3259 p.x = parseTwip(xstr);
3265 if(isRelative(ystr))
3267 if(type == PT_PUT || type == PT_STARTCLIP)
3268 syntaxerror("relative y values not allowed for initial put or startclip");
3269 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3273 p.y = parseTwip(ystr);
3278 if (change_sets_all)
3286 const char* interstr = lu(args, "interpolation");
3287 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3289 syntaxerror("unkown interpolation %s", interstr);
3290 s_change(instance, p, inter);
3295 const char* interstr = lu(args, "interpolation");
3296 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3298 syntaxerror("unkown interpolation %s", interstr);
3299 s_schange(instance, p, inter);
3304 const char* rstr = lu(args, "r");
3305 int radius = parseTwip(rstr);
3307 syntaxerror("sweep not possible: radius must be greater than 0.");
3308 const char* dirstr = lu(args, "dir");
3309 int clockwise = parseDir(dirstr);
3310 const char* arcstr = lu(args, "arc");
3311 int short_arc = parseArc(arcstr);
3312 const char* interstr = lu(args, "interpolation");
3313 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3315 syntaxerror("unkown interpolation %s", interstr);
3316 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3323 static int c_placement(map_t*args, int type)
3325 const char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3326 const char*character = 0;
3328 const char* luminancestr = lu(args, "luminance");
3329 const char* scalestr = lu(args, "scale");
3330 const char* scalexstr = lu(args, "scalex");
3331 const char* scaleystr = lu(args, "scaley");
3332 const char* rotatestr = lu(args, "rotate");
3333 const char* shearstr = lu(args, "shear");
3334 const char* xstr="", *pivotstr="";
3335 const char* ystr="", *anglestr="";
3336 const char*above = lu(args, "above"); /*FIXME*/
3337 const char*below = lu(args, "below");
3338 const char* rstr = lu(args, "red");
3339 const char* gstr = lu(args, "green");
3340 const char* bstr = lu(args, "blue");
3341 const char* astr = lu(args, "alpha");
3342 const char* pinstr = lu(args, "pin");
3343 const char* as = map_lookup(args, "as");
3344 const char* blendmode = lu(args, "blend");
3345 const char* filterstr = lu(args, "filter");
3356 { // (?) .rotate or .arcchange
3357 pivotstr = lu(args, "pivot");
3358 anglestr = lu(args, "angle");
3362 xstr = lu(args, "x");
3363 ystr = lu(args, "y");
3367 luminance = parseMulAdd(luminancestr);
3371 luminance.mul = 256;
3376 if(scalexstr[0]||scaleystr[0])
3377 syntaxerror("scalex/scaley and scale cannot both be set");
3378 scalexstr = scaleystr = scalestr;
3381 if(type == PT_PUT || type == PT_STARTCLIP) {
3383 character = lu(args, "character");
3384 parameters_clear(&p);
3385 } else if (type == PT_BUTTON) {
3386 character = lu(args, "name");
3387 parameters_clear(&p);
3390 s_getParameters(instance, &p);
3396 if(isRelative(xstr))
3398 if(type == PT_PUT || type == PT_STARTCLIP)
3399 syntaxerror("relative x values not allowed for initial put or startclip");
3400 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3404 p.x = parseTwip(xstr);
3410 if(isRelative(ystr))
3412 if(type == PT_PUT || type == PT_STARTCLIP)
3413 syntaxerror("relative y values not allowed for initial put or startclip");
3414 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3418 p.y = parseTwip(ystr);
3423 /* scale, scalex, scaley */
3425 oldbbox = s_getCharBBox(character);
3427 oldbbox = s_getInstanceBBox(instance);
3428 oldwidth = oldbbox.xmax - oldbbox.xmin;
3429 oldheight = oldbbox.ymax - oldbbox.ymin;
3436 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3437 set = set | SF_SCALEX;
3445 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3446 set = set | SF_SCALEY;
3452 if(isRelative(rotatestr))
3453 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3455 p.rotate = parseFloat(rotatestr);
3456 set = set | SF_ROTATE;
3462 if(isRelative(shearstr))
3463 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3465 p.shear = parseFloat(shearstr);
3466 set = set | SF_SHEAR;
3471 if(isPoint(pivotstr))
3472 p.pivot = parsePoint(pivotstr);
3474 p.pivot = getPoint(oldbbox, pivotstr);
3475 set = set | SF_PIVOT;
3481 p.pin = parsePoint(pinstr);
3483 p.pin = getPoint(oldbbox, pinstr);
3487 /* color transform */
3489 if(rstr[0] || luminancestr[0])
3493 r = parseMulAdd(rstr);
3496 r.add = p.cxform.r0;
3497 r.mul = p.cxform.r1;
3499 r = mergeMulAdd(r, luminance);
3500 p.cxform.r0 = r.mul;
3501 p.cxform.r1 = r.add;
3502 set = set | SF_CX_R;
3504 if(gstr[0] || luminancestr[0])
3508 g = parseMulAdd(gstr);
3511 g.add = p.cxform.g0;
3512 g.mul = p.cxform.g1;
3514 g = mergeMulAdd(g, luminance);
3515 p.cxform.g0 = g.mul;
3516 p.cxform.g1 = g.add;
3517 set = set | SF_CX_G;
3519 if(bstr[0] || luminancestr[0])
3523 b = parseMulAdd(bstr);
3526 b.add = p.cxform.b0;
3527 b.mul = p.cxform.b1;
3529 b = mergeMulAdd(b, luminance);
3530 p.cxform.b0 = b.mul;
3531 p.cxform.b1 = b.add;
3532 set = set | SF_CX_B;
3536 MULADD a = parseMulAdd(astr);
3537 p.cxform.a0 = a.mul;
3538 p.cxform.a1 = a.add;
3539 set = set | SF_CX_A;
3546 for(t = 0; blendModeNames[t]; t++)
3548 if(!strcmp(blendModeNames[t], blendmode))
3556 syntaxerror("unknown blend mode: '%s'", blendmode);
3558 p.blendmode = blend;
3559 set = set | SF_BLEND;
3564 p.filters = parseFilters((char*)filterstr);
3565 set = set | SF_FILTER;
3568 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3569 warning("As of version 0.8.2 using the .change command to modify an \
3570 object's position on the stage is considered deprecated. Future \
3571 versions may consider x and y parameters for the .change command \
3572 to be illegal; please use the .move command.");
3574 if (change_sets_all)
3581 s_put(instance, character, p);
3585 const char* interstr = lu(args, "interpolation");
3586 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3588 syntaxerror("unkown interpolation %s", interstr);
3589 s_change(instance, p, inter);
3594 const char* interstr = lu(args, "interpolation");
3595 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3597 syntaxerror("unkown interpolation %s", interstr);
3598 s_schange(instance, p, inter);
3602 s_jump(instance, p);
3605 s_startclip(instance, character, p);
3609 s_buttonput(character, as, p);
3611 s_buttonput(character, "shape", p);
3617 static int c_put(map_t*args)
3619 c_placement(args, PT_PUT);
3622 static int c_change(map_t*args)
3624 if (currentframe == 0)
3625 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3626 c_placement(args, PT_CHANGE);
3629 static int c_schange(map_t*args)
3631 c_placement(args, PT_SCHANGE);
3634 static int c_move(map_t* args)
3636 c_movement(args, PT_MOVE);
3639 static int c_smove(map_t* args)
3641 c_movement(args, PT_SMOVE);
3644 static int c_sweep(map_t* args)
3646 c_movement(args, PT_SWEEP);
3649 static int c_arcchange(map_t*args)
3651 c_placement(args, 0);
3654 static int c_jump(map_t*args)
3656 c_placement(args, PT_JUMP);
3659 static int c_startclip(map_t*args)
3661 c_placement(args, PT_STARTCLIP);
3664 static int c_show(map_t*args)
3666 c_placement(args, PT_BUTTON);
3669 static int c_toggle(map_t* args)
3671 const char*instance = lu(args, "name");
3672 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3673 const char* alignstr = lu(args, "fixed_alignment");
3674 if (!strcmp(alignstr, "on"))
3675 flagsOn += IF_FIXED_ALIGNMENT;
3677 if (!strcmp(alignstr, "off"))
3678 flagsOff -= IF_FIXED_ALIGNMENT;
3680 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3681 s_toggle(instance, flagsOn, flagsOff);
3684 static int c_del(map_t*args)
3686 const char*instance = lu(args, "name");
3687 s_delinstance(instance);
3690 static int c_end(map_t*args)
3695 static int c_sprite(map_t*args)
3697 const char* name = lu(args, "name");
3698 const char* scalinggrid = lu(args, "scalinggrid");
3700 if(scalinggrid && *scalinggrid) {
3701 SRECT r = parseBox(scalinggrid);
3708 static int c_frame(map_t*args)
3710 const char*framestr = lu(args, "n");
3711 const char*cutstr = lu(args, "cut");
3713 const char*name = lu(args, "name");
3714 const char*anchor = lu(args, "anchor");
3717 if(!strcmp(anchor, "anchor") && !*name)
3722 if(strcmp(cutstr, "no"))
3724 if(isRelative(framestr)) {
3725 frame = s_getframe();
3726 if(getSign(framestr)<0)
3727 syntaxerror("relative frame expressions must be positive");
3728 frame += parseInt(getOffset(framestr));
3731 frame = parseInt(framestr);
3732 if(s_getframe() >= frame
3733 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3734 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3736 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3739 static int c_primitive(map_t*args)
3741 const char*name = lu(args, "name");
3742 const char*command = lu(args, "commandname");
3743 int width=0, height=0, r=0;
3744 int linewidth = parseTwip(lu(args, "line"));
3745 const char*colorstr = lu(args, "color");
3746 RGBA color = parseColor(colorstr);
3747 const char*fillstr = lu(args, "fill");
3752 const char* outline=0;
3754 if(!strcmp(command, "circle"))
3756 else if(!strcmp(command, "filled"))
3760 width = parseTwip(lu(args, "width"));
3761 height = parseTwip(lu(args, "height"));
3762 } else if (type==1) {
3763 r = parseTwip(lu(args, "r"));
3764 } else if (type==2) {
3765 outline = lu(args, "outline");
3768 if(!strcmp(fillstr, "fill"))
3770 if(!strcmp(fillstr, "none"))
3772 if(width<0 || height<0 || linewidth<0 || r<0)
3773 syntaxerror("values width, height, line, r must be positive");
3775 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3776 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3777 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3781 static int c_textshape(map_t*args)
3783 const char*name = lu(args, "name");
3784 const char*text = lu(args, "text");
3785 const char*font = lu(args, "font");
3786 float size = parsePxOrPercent(font, lu(args, "size"));
3788 s_textshape(name, font, size, text);
3792 static int c_swf(map_t*args)
3794 const char*name = lu(args, "name");
3795 const char*filename = lu(args, "filename");
3796 const char*command = lu(args, "commandname");
3797 if(!strcmp(command, "shape"))
3798 warning("Please use .swf instead of .shape");
3799 s_includeswf(name, filename);
3803 static int c_font(map_t*args)
3805 const char*name = lu(args, "name");
3806 const char*filename = lu(args, "filename");
3807 s_font(name, filename);
3811 static int c_sound(map_t*args)
3813 const char*name = lu(args, "name");
3814 const char*filename = lu(args, "filename");
3815 s_sound(name, filename);
3819 static int c_text(map_t*args)
3821 const char*name = lu(args, "name");
3822 const char*text = lu(args, "text");
3823 const char*font = lu(args, "font");
3824 float size = parsePxOrPercent(font, lu(args, "size"));
3825 RGBA color = parseColor(lu(args, "color"));
3826 s_text(name, font, text, (int)(size*100), color);
3830 static int c_soundtrack(map_t*args)
3835 static int c_quicktime(map_t*args)
3837 const char*name = lu(args, "name");
3838 const char*url = lu(args, "url");
3839 s_quicktime(name, url);
3843 static int c_video(map_t*args)
3845 const char*name = lu(args, "name");
3846 int width = parseInt(lu(args, "width"));
3847 int height = parseInt(lu(args, "height"));
3848 s_video(name, width, height);
3852 static int c_image(map_t*args)
3854 const char*command = lu(args, "commandname");
3855 const char*name = lu(args, "name");
3856 const char*filename = lu(args, "filename");
3857 if(!strcmp(command,"jpeg")) {
3858 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3859 s_image(name, "jpeg", filename, quality);
3861 s_image(name, "png", filename, 0);
3866 static int c_outline(map_t*args)
3868 const char*name = lu(args, "name");
3869 const char*format = lu(args, "format");
3873 syntaxerror("colon (:) expected");
3875 s_outline(name, format, text);
3879 int fakechar(map_t*args)
3881 const char*name = lu(args, "name");
3882 s_box(name, 0, 0, black, 20, 0);
3886 static int c_egon(map_t*args) {return fakechar(args);}
3887 static int c_button(map_t*args) {
3888 const char*name = lu(args, "name");
3892 static int current_button_flags = 0;
3893 static int c_on_press(map_t*args)
3895 const char*position = lu(args, "position");
3896 const char*action = "";
3897 if(!strcmp(position, "inside")) {
3898 current_button_flags |= BC_OVERUP_OVERDOWN;
3899 } else if(!strcmp(position, "outside")) {
3900 //current_button_flags |= BC_IDLE_OUTDOWN;
3901 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3902 } else if(!strcmp(position, "anywhere")) {
3903 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3906 if(type == RAWDATA) {
3908 s_buttonaction(current_button_flags, action);
3909 current_button_flags = 0;
3915 static int c_on_release(map_t*args)
3917 const char*position = lu(args, "position");
3918 const char*action = "";
3919 if(!strcmp(position, "inside")) {
3920 current_button_flags |= BC_OVERDOWN_OVERUP;
3921 } else if(!strcmp(position, "outside")) {
3922 current_button_flags |= BC_OUTDOWN_IDLE;
3923 } else if(!strcmp(position, "anywhere")) {
3924 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3927 if(type == RAWDATA) {
3929 s_buttonaction(current_button_flags, action);
3930 current_button_flags = 0;
3936 static int c_on_move_in(map_t*args)
3938 const char*position = lu(args, "state");
3939 const char*action = "";
3940 if(!strcmp(position, "pressed")) {
3941 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3942 } else if(!strcmp(position, "not_pressed")) {
3943 current_button_flags |= BC_IDLE_OVERUP;
3944 } else if(!strcmp(position, "any")) {
3945 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3948 if(type == RAWDATA) {
3950 s_buttonaction(current_button_flags, action);
3951 current_button_flags = 0;
3957 static int c_on_move_out(map_t*args)
3959 const char*position = lu(args, "state");
3960 const char*action = "";
3961 if(!strcmp(position, "pressed")) {
3962 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3963 } else if(!strcmp(position, "not_pressed")) {
3964 current_button_flags |= BC_OVERUP_IDLE;
3965 } else if(!strcmp(position, "any")) {
3966 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3969 if(type == RAWDATA) {
3971 s_buttonaction(current_button_flags, action);
3972 current_button_flags = 0;
3978 static int c_on_key(map_t*args)
3980 const char*key = lu(args, "key");
3981 const char*action = "";
3982 if(strlen(key)==1) {
3985 current_button_flags |= 0x4000 + (key[0]*0x200);
3987 syntaxerror("invalid character: %c"+key[0]);
3992 <ctrl-x> = 0x200*(x-'a')
3996 syntaxerror("invalid key: %s",key);
3999 if(type == RAWDATA) {
4001 s_buttonaction(current_button_flags, action);
4002 current_button_flags = 0;
4009 static int c_edittext(map_t*args)
4011 //"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"},
4012 const char*name = lu(args, "name");
4013 const char*font = lu(args, "font");
4014 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
4015 int width = parseTwip(lu(args, "width"));
4016 int height = parseTwip(lu(args, "height"));
4017 const char*text = lu(args, "text");
4018 RGBA color = parseColor(lu(args, "color"));
4019 int maxlength = parseInt(lu(args, "maxlength"));
4020 const char*variable = lu(args, "variable");
4021 const char*passwordstr = lu(args, "password");
4022 const char*wordwrapstr = lu(args, "wordwrap");
4023 const char*multilinestr = lu(args, "multiline");
4024 const char*htmlstr = lu(args, "html");
4025 const char*noselectstr = lu(args, "noselect");
4026 const char*readonlystr = lu(args, "readonly");
4027 const char*borderstr = lu(args, "border");
4028 const char*autosizestr = lu(args, "autosize");
4029 const char*alignstr = lu(args, "align");
4033 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
4034 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
4035 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
4036 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
4037 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
4038 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
4039 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
4040 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
4041 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
4042 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
4043 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
4044 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
4045 else syntaxerror("Unknown alignment: %s", alignstr);
4047 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
4051 static int c_morphshape(map_t*args) {return fakechar(args);}
4052 static int c_movie(map_t*args) {return fakechar(args);}
4054 static char* readfile(char*filename)
4056 FILE*fi = fopen(filename, "rb");
4060 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
4061 fseek(fi, 0, SEEK_END);
4063 fseek(fi, 0, SEEK_SET);
4064 text = rfx_alloc(l+1);
4065 fread(text, l, 1, fi);
4071 static int c_action(map_t*args)
4073 const char* filename = map_lookup(args, "filename");
4074 if(!filename ||!*filename) {
4076 if(type != RAWDATA) {
4077 syntaxerror("colon (:) expected");
4081 s_action(readfile((char*)filename));
4087 static int c_initaction(map_t*args)
4089 const char* character = lu(args, "name");
4090 const char* filename = map_lookup(args, "filename");
4091 if(!filename ||!*filename) {
4093 if(type != RAWDATA) {
4094 syntaxerror("colon (:) expected");
4096 s_initaction(character, text);
4098 s_initaction(character, readfile((char*)filename));
4106 command_func_t* func;
4109 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1"},
4110 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
4111 // "import" type stuff
4112 {"swf", c_swf, "name filename"},
4113 {"shape", c_swf, "name filename"},
4114 {"jpeg", c_image, "name filename quality=80%"},
4115 {"png", c_image, "name filename"},
4116 {"movie", c_movie, "name filename"},
4117 {"sound", c_sound, "name filename"},
4118 {"font", c_font, "name filename glyphs="},
4119 {"soundtrack", c_soundtrack, "filename"},
4120 {"quicktime", c_quicktime, "url"},
4121 {"video", c_video, "name width= height="},
4123 // generators of primitives
4125 {"define", c_define, "name value=0"},
4126 {"point", c_point, "name x=0 y=0"},
4127 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4128 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4129 {"outline", c_outline, "name format=simple"},
4130 {"textshape", c_textshape, "name font size=100% text"},
4133 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4134 {"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"},
4135 {"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"},
4136 {"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"},
4138 // character generators
4139 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4140 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4141 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4143 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4144 {"text", c_text, "name text font size=100% color=white"},
4145 {"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="},
4146 {"morphshape", c_morphshape, "name start end"},
4147 {"button", c_button, "name"},
4148 {"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="},
4149 {"on_press", c_on_press, "position=inside"},
4150 {"on_release", c_on_release, "position=anywhere"},
4151 {"on_move_in", c_on_move_in, "state=not_pressed"},
4152 {"on_move_out", c_on_move_out, "state=not_pressed"},
4153 {"on_key", c_on_key, "key=any"},
4156 {"play", c_play, "name loop=0 @nomultiple=0"},
4157 {"stop", c_stop, "name= "},
4158 {"nextframe", c_nextframe, "name"},
4159 {"previousframe", c_previousframe, "name"},
4161 // object placement tags
4162 {"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="},
4163 {"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="},
4164 {"move", c_move, "name x= y= interpolation=linear"},
4165 {"smove", c_smove, "name x= y= interpolation=linear"},
4166 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4167 {"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"},
4168 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4169 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4170 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4171 {"del", c_del, "name"},
4172 // virtual object placement
4173 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4175 {"toggle", c_toggle, "name fixed_alignment="},
4177 // commands which start a block
4178 //startclip (see above)
4179 {"sprite", c_sprite, "name scalinggrid="},
4180 {"action", c_action, "filename="},
4181 {"initaction", c_initaction, "name filename="},
4187 static map_t parseArguments(char*command, char*pattern)
4203 string_set(&t1, "commandname");
4204 string_set(&t2, command);
4205 map_put(&result, t1, t2);
4207 if(!pattern || !*pattern)
4214 if(!strncmp("<i> ", x, 3)) {
4216 if(type == COMMAND || type == RAWDATA) {
4218 syntaxerror("character name expected");
4220 name[pos].str = "instance";
4222 value[pos].str = text;
4223 value[pos].len = strlen(text);
4227 if(type == ASSIGNMENT)
4230 name[pos].str = "character";
4232 value[pos].str = text;
4233 value[pos].len = strlen(text);
4241 isboolean[pos] = (x[0] =='@');
4254 name[pos].len = d-x;
4259 name[pos].len = e-x;
4260 value[pos].str = e+1;
4261 value[pos].len = d-e-1;
4269 /* for(t=0;t<len;t++) {
4270 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4271 isboolean[t]?"(boolean)":"");
4276 if(type == RAWDATA || type == COMMAND) {
4281 // first, search for boolean arguments
4282 for(pos=0;pos<len;pos++)
4284 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4286 if(type == ASSIGNMENT)
4288 value[pos].str = text;
4289 value[pos].len = strlen(text);
4290 /*printf("setting boolean parameter %s (to %s)\n",
4291 strdup_n(name[pos], namelen[pos]),
4292 strdup_n(value[pos], valuelen[pos]));*/
4297 // second, search for normal arguments
4299 for(pos=0;pos<len;pos++)
4301 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4302 (type != ASSIGNMENT && !set[pos])) {
4304 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4306 if(type == ASSIGNMENT)
4309 value[pos].str = text;
4310 value[pos].len = strlen(text);
4312 printf("setting parameter %s (to %s)\n",
4313 strdup_n(name[pos].str, name[pos].len),
4314 strdup_n(value[pos].str, value[pos].len));
4320 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4324 for(t=0;t<len;t++) {
4325 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4328 for(t=0;t<len;t++) {
4329 if(value[t].str && value[t].str[0] == '*') {
4330 //relative default- take value from some other parameter
4332 for(s=0;s<len;s++) {
4333 if(value[s].len == value[t].len-1 &&
4334 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4335 value[t].str = value[s].str;
4338 if(value[t].str == 0) {
4340 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4344 /* ok, now construct the dictionary from the parameters */
4348 map_put(&result, name[t], value[t]);
4352 static void parseArgumentsForCommand(char*command)
4357 msg("<verbose> parse Command: %s (line %d)", command, line);
4359 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4360 if(!strcmp(arguments[t].command, command)) {
4362 /* ugly hack- will be removed soon (once documentation and .sc generating
4363 utilities have been changed) */
4364 if(!strcmp(command, "swf") && !stackpos) {
4365 warning("Please use .flash instead of .swf- this will be mandatory soon");
4370 args = parseArguments(command, arguments[t].arguments);
4376 syntaxerror("command %s not known", command);
4379 // catch missing .flash directives at the beginning of a file
4380 if(strcmp(command, "flash") && !stackpos)
4382 syntaxerror("No movie defined- use .flash first");
4387 printf(".%s\n", command);fflush(stdout);
4388 map_dump(&args, stdout, "\t");fflush(stdout);
4392 (*arguments[nr].func)(&args);
4394 if(!strcmp(command, "action") || !strcmp(command, "initaction") ||
4395 !strcmp(command, "outline") || !strcmp(command, "gradient")) {
4397 if(type != RAWDATA) {
4398 syntaxerror("colon (:) expected");
4407 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4408 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4409 * No syntax checking is done */
4410 static void analyseArgumentsForCommand(char*command)
4414 const char* fontfile;
4416 U8* glyphs_to_include;
4417 msg("<verbose> analyse Command: %s (line %d)", command, line);
4419 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4421 if(!strcmp(arguments[t].command, command))
4423 args = parseArguments(command, arguments[t].arguments);
4429 printf(".%s\n", command);fflush(stdout);
4430 map_dump(&args, stdout, "\t");fflush(stdout);
4432 const char* name = lu(&args, "name");
4433 if (!strcmp(command, "font"))
4435 if(dict_lookup(&fonts, name))
4436 syntaxerror("font %s defined twice", name);
4439 fontfile = lu(&args, "filename");
4440 font = swf_LoadFont(fontfile);
4442 warning("Couldn't open font file \"%s\"", fontfile);
4443 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4444 memset(font, 0, sizeof(SWFFONT));
4448 swf_FontPrepareForEditText(font);
4449 glyphs_to_include = (U8*)lu(&args, "glyphs");
4450 if (!strcmp(glyphs_to_include, "all"))
4452 swf_FontUseAll(font);
4453 font->use->glyphs_specified = 1;
4457 if (strcmp (glyphs_to_include, ""))
4459 swf_FontUseUTF8(font, glyphs_to_include);
4460 font->use->glyphs_specified = 1;
4463 swf_FontInitUsage(font);
4466 dict_put(&fonts, name, font);
4470 SWFFONT* font = dict_lookup(&fonts, lu(&args, "font"));
4472 //that's ok... it might be an edittext with a system font
4473 //syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4475 if (font->use && !font->use->glyphs_specified)
4477 if (!strcmp(command, "edittext"))
4479 swf_FontUseAll(font);
4480 font->use->glyphs_specified = 1;
4483 swf_FontUseUTF8(font, (U8*)lu(&args, "text"));
4490 void skipParameters()
4494 while (type != COMMAND);
4498 void findFontUsage()
4500 char* fontRelated = "font;text;textshape;edittext;";
4501 while(!noMoreTokens())
4505 syntaxerror("command expected");
4506 if (strstr(fontRelated, text))
4507 analyseArgumentsForCommand(text);
4509 if(strcmp(text, "end"))
4518 dict_init(&fonts, 16);
4519 cleanUp = &freeFontDictionary;
4523 int main (int argc,char ** argv)
4526 processargs(argc, argv);
4527 initLog(0,-1,0,0,-1,verbose);
4530 args_callback_usage(argv[0]);
4534 file = generateTokens(filename);
4536 fprintf(stderr, "parser returned error.\n");
4543 while(!noMoreTokens()) {
4546 syntaxerror("command expected");
4547 parseArgumentsForCommand(text);