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_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)
1387 EditTextLayout layout;
1390 if(fontname && *fontname) {
1391 flags |= ET_USEOUTLINES;
1392 font = dict_lookup(&fonts, fontname);
1394 syntaxerror("font \"%s\" not known!", fontname);
1396 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1397 swf_SetU16(tag, id);
1398 layout.align = align;
1399 layout.leftmargin = 0;
1400 layout.rightmargin = 0;
1408 swf_SetEditText(tag, flags, r, (char*)text, color, maxlength, font?font->id:0, size, &layout, (char*)variable);
1410 s_addcharacter(name, id, tag, r);
1414 /* type: either "jpeg" or "png"
1416 void s_image(const char*name, const char*type, const char*filename, int quality)
1418 /* an image is actually two folded: 1st bitmap, 2nd character.
1419 Both of them can be used separately */
1421 /* step 1: the bitmap */
1425 if(!strcmp(type,"jpeg")) {
1426 #ifndef HAVE_JPEGLIB
1427 warning("no jpeg support compiled in");
1428 s_box(name, 0, 0, black, 20, 0);
1431 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1432 swf_SetU16(tag, imageID);
1434 if(swf_SetJPEGBits(tag, (char*)filename, quality) < 0) {
1435 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1438 swf_GetJPEGSize(filename, &width, &height);
1445 s_addimage(name, id, tag, r);
1448 } else if(!strcmp(type,"png")) {
1450 swf_SetU16(tag, imageID);
1452 getPNG(filename, &width, &height, (unsigned char**)&data);
1455 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1458 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1459 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1460 swf_SetU16(tag, imageID);
1461 swf_SetLosslessImage(tag, data, width, height);
1468 s_addimage(name, id, tag, r);
1471 warning("image type \"%s\" not supported yet!", type);
1472 s_box(name, 0, 0, black, 20, 0);
1476 /* step 2: the character */
1477 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1478 swf_SetU16(tag, id);
1479 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1481 s_addcharacter(name, id, tag, r);
1485 void s_getBitmapSize(const char*name, int*width, int*height)
1487 character_t* image = dict_lookup(&images, name);
1488 gradient_t* gradient = dict_lookup(&gradients,name);
1490 *width = image->size.xmax;
1491 *height = image->size.ymax;
1495 /* internal SWF gradient size */
1496 if(gradient->radial) {
1505 syntaxerror("No such bitmap/gradient: %s", name);
1508 void s_texture(const char*name, const char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1510 if(dict_lookup(&textures, name))
1511 syntaxerror("texture %s defined twice", name);
1512 gradient_t* gradient = dict_lookup(&gradients, object);
1513 character_t* bitmap = dict_lookup(&images, object);
1514 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1516 FILLSTYLE*fs = &texture->fs;
1518 memset(&p, 0, sizeof(parameters_t));
1521 fs->type = FILL_TILED;
1522 fs->id_bitmap = bitmap->id;
1523 } else if(gradient) {
1524 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1525 fs->gradient = gradient->gradient;
1527 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1528 makeMatrix(&fs->m, &p);
1529 if(gradient && !gradient->radial) {
1536 p2 = swf_TurnPoint(p1, &m);
1545 dict_put(&textures, name, texture);
1548 void s_font(const char*name, const char*filename)
1551 font = dict_lookup(&fonts, name);
1554 /* fix the layout. Only needed for old fonts */
1556 for(t=0;t<font->numchars;t++) {
1557 font->glyph[t].advance = 0;
1560 swf_FontCreateLayout(font);
1563 swf_FontReduce_swfc(font);
1564 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1565 swf_FontSetDefine2(tag, font);
1567 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1569 swf_SetU16(tag, id);
1570 swf_SetString(tag, name);
1578 typedef struct _sound_t
1584 void s_sound(const char*name, const char*filename)
1586 struct WAV wav, wav2;
1590 unsigned numsamples = 1;
1591 unsigned blocksize = 1152;
1594 if(dict_lookup(&sounds, name))
1595 syntaxerror("sound %s defined twice", name);
1597 if(wav_read(&wav, filename))
1600 wav_convert2mono(&wav, &wav2, 44100);
1601 samples = (U16*)wav2.data;
1602 numsamples = wav2.size/2;
1604 #ifdef WORDS_BIGENDIAN
1606 for(t=0;t<numsamples;t++)
1607 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1611 if(mp3_read(&mp3, filename))
1613 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1619 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1624 if(numsamples%blocksize != 0)
1626 // apply padding, so that block is a multiple of blocksize
1627 int numblocks = (numsamples+blocksize-1)/blocksize;
1630 numsamples2 = numblocks * blocksize;
1631 samples2 = malloc(sizeof(U16)*numsamples2);
1632 memcpy(samples2, samples, numsamples*sizeof(U16));
1633 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1634 numsamples = numsamples2;
1639 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1640 swf_SetU16(tag, id); //id
1643 swf_SetSoundDefineMP3(
1644 tag, mp3.data, mp3.size,
1651 swf_SetSoundDefine(tag, samples, numsamples);
1654 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1655 swf_SetU16(tag, id);
1656 swf_SetString(tag, name);
1657 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1659 swf_SetU16(tag, id);
1660 swf_SetString(tag, name);
1663 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1667 dict_put(&sounds, name, sound);
1675 static char* gradient_getToken(const char**p)
1679 while(**p && strchr(" \t\n\r", **p)) {
1683 while(**p && !strchr(" \t\n\r", **p)) {
1686 result = malloc((*p)-start+1);
1687 memcpy(result,start,(*p)-start+1);
1688 result[(*p)-start] = 0;
1692 float parsePercent(const char*str);
1693 RGBA parseColor(const char*str);
1695 GRADIENT parseGradient(const char*str)
1699 const char* p = str;
1700 memset(&gradient, 0, sizeof(GRADIENT));
1701 gradient.ratios = rfx_calloc(16*sizeof(U8));
1702 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1706 char*posstr,*colorstr;
1709 posstr = gradient_getToken(&p);
1715 pos = (int)(parsePercent(posstr)*255.0);
1720 rfx_free(gradient.ratios);
1721 rfx_free(gradient.rgba);
1723 syntaxerror("Error in shape data: Color expected after %s", posstr);
1725 colorstr = gradient_getToken(&p);
1726 color = parseColor(colorstr);
1727 if(gradient.num == 16)
1729 warning("gradient record too big- max size is 16, rest ignored");
1732 gradient.ratios[gradient.num] = pos;
1733 gradient.rgba[gradient.num] = color;
1742 FILTERLIST* parseFilters(char* list)
1744 if (!strcmp(list, "no_filters"))
1747 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1749 char* f_start = list;
1753 f_end = strchr(f_start, ',');
1756 f = dict_lookup(&filters, f_start);
1760 syntaxerror("unknown filter %s", f_start);
1762 if (f_list->num == 8)
1764 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1767 f_list->filter[f_list->num] = f;
1772 f_start = f_end + 1;
1780 void s_gradient(const char*name, const char*text, int radial, int rotate)
1782 gradient_t* gradient;
1783 gradient = malloc(sizeof(gradient_t));
1784 memset(gradient, 0, sizeof(gradient_t));
1785 gradient->gradient = parseGradient(text);
1786 gradient->radial = radial;
1787 gradient->rotate = rotate;
1789 dict_put(&gradients, name, gradient);
1792 void s_gradientglow(const char*name, const char*gradient, float blurx, float blury,
1793 float angle, float distance, float strength, char innershadow,
1794 char knockout, char composite, char ontop, int passes)
1796 if(dict_lookup(&filters, name))
1797 syntaxerror("filter %s defined twice", name);
1799 gradient_t* g = dict_lookup(&gradients, gradient);
1801 syntaxerror("unknown gradient %s", gradient);
1805 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1806 filter->type = FILTERTYPE_GRADIENTGLOW;
1807 filter->gradient = &g->gradient;
1808 filter->blurx = blurx;
1809 filter->blury = blury;
1810 filter->strength = strength;
1811 filter->angle = angle;
1812 filter->distance = distance;
1813 filter->innershadow = innershadow;
1814 filter->knockout = knockout;
1815 filter->composite = composite;
1816 filter->ontop = ontop;
1817 filter->passes = passes;
1819 dict_put(&filters, name, filter);
1822 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)
1824 if(dict_lookup(&filters, name))
1825 syntaxerror("filter %s defined twice", name);
1828 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1829 filter->type = FILTERTYPE_DROPSHADOW;
1830 filter->color= color;
1831 filter->blurx = blurx;
1832 filter->blury = blury;
1833 filter->strength = strength;
1834 filter->angle = angle;
1835 filter->distance = distance;
1836 filter->innershadow = innershadow;
1837 filter->knockout = knockout;
1838 filter->composite = composite;
1839 filter->passes = passes;
1841 dict_put(&filters, name, filter);
1844 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)
1846 if(dict_lookup(&filters, name))
1847 syntaxerror("filter %s defined twice", name);
1850 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1851 filter->type = FILTERTYPE_BEVEL;
1852 filter->shadow = shadow;
1853 filter->highlight = highlight;
1854 filter->blurx = blurx;
1855 filter->blury = blury;
1856 filter->strength = strength;
1857 filter->angle = angle;
1858 filter->distance = distance;
1859 filter->innershadow = innershadow;
1860 filter->knockout = knockout;
1861 filter->composite = composite;
1862 filter->ontop = ontop;
1863 filter->passes = passes;
1865 dict_put(&filters, name, filter);
1868 void s_blur(const char*name, double blurx, double blury, int passes)
1870 if(dict_lookup(&filters, name))
1871 syntaxerror("filter %s defined twice", name);
1873 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1874 filter->type = FILTERTYPE_BLUR;
1875 filter->blurx = blurx;
1876 filter->blury = blury;
1877 filter->passes = passes;
1879 dict_put(&filters, name, filter);
1882 void s_action(const char*text)
1884 if(stack[0].swf->fileVersion < 9) {
1886 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1889 syntaxerror("Couldn't compile ActionScript");
1891 tag = swf_InsertTag(tag, ST_DOACTION);
1892 swf_ActionSet(tag, a);
1895 as3_parse_bytearray(stack[0].filename, text, strlen(text));
1900 void s_initaction(const char*character, const char*text)
1904 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1908 syntaxerror("Couldn't compile ActionScript");
1911 c = (character_t*)dict_lookup(&characters, character);
1913 tag = swf_InsertTag(tag, ST_DOINITACTION);
1914 swf_SetU16(tag, c->id);
1915 swf_ActionSet(tag, a);
1920 int s_swf3action(const char*name, const char*action)
1923 instance_t* object = 0;
1925 object = (instance_t*)dict_lookup(&instances, name);
1926 if(!object && name && *name) {
1927 /* we have a name, but couldn't find it. Abort. */
1930 a = action_SetTarget(0, name);
1931 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1932 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1933 else if(!strcmp(action, "stop")) a = action_Stop(a);
1934 else if(!strcmp(action, "play")) a = action_Play(a);
1935 a = action_SetTarget(a, "");
1938 tag = swf_InsertTag(tag, ST_DOACTION);
1939 swf_ActionSet(tag, a);
1944 void s_outline(const char*name, const char*format, const char*source)
1946 if(dict_lookup(&outlines, name))
1947 syntaxerror("outline %s defined twice", name);
1956 //swf_Shape10DrawerInit(&draw, 0);
1957 swf_Shape11DrawerInit(&draw, 0);
1959 draw_string(&draw, source);
1961 shape = swf_ShapeDrawerToShape(&draw);
1962 bounds = swf_ShapeDrawerGetBBox(&draw);
1963 draw.dealloc(&draw);
1965 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1966 outline->shape = shape;
1967 outline->bbox = bounds;
1969 dict_put(&outlines, name, outline);
1972 int s_playsound(const char*name, int loops, int nomultiple, int stop)
1978 sound = dict_lookup(&sounds, name);
1982 tag = swf_InsertTag(tag, ST_STARTSOUND);
1983 swf_SetU16(tag, sound->id); //id
1984 memset(&info, 0, sizeof(info));
1987 info.nomultiple = nomultiple;
1988 swf_SetSoundInfo(tag, &info);
1992 void s_includeswf(const char*name, const char*filename)
2000 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
2001 f = open(filename,O_RDONLY|O_BINARY);
2003 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
2004 s_box(name, 0, 0, black, 20, 0);
2007 if (swf_ReadSWF(f,&swf)<0) {
2008 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
2009 s_box(name, 0, 0, black, 20, 0);
2014 /* FIXME: The following sets the bounding Box for the character.
2015 It is wrong for two reasons:
2016 a) It may be too small (in case objects in the movie clip at the borders)
2017 b) it may be too big (because the poor movie never got autocropped)
2021 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2022 swf_SetU16(tag, id);
2023 swf_SetU16(tag, swf.frameCount);
2025 swf_Relocate(&swf, idmap);
2027 ftag = swf.firstTag;
2031 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2032 if(cutout[t] == ftag->id) {
2036 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2038 if(ftag->id == ST_END)
2043 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2044 /* We simply dump all tags right after the sprite
2045 header, relying on the fact that swf_OptimizeTagOrder() will
2046 sort things out for us later.
2047 We also rely on the fact that the imported SWF is well-formed.
2049 tag = swf_InsertTag(tag, ftag->id);
2050 swf_SetBlock(tag, ftag->data, ftag->len);
2056 syntaxerror("Included file %s contains errors", filename);
2057 tag = swf_InsertTag(tag, ST_END);
2061 s_addcharacter(name, id, tag, r);
2064 SRECT s_getCharBBox(const char*name)
2066 character_t* c = dict_lookup(&characters, name);
2067 if(!c) syntaxerror("character '%s' unknown(2)", name);
2070 SRECT s_getInstanceBBox(const char*name)
2072 instance_t * i = dict_lookup(&instances, name);
2074 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2076 if(!c) syntaxerror("internal error(5)");
2079 void s_getParameters(const char*name, parameters_t* p)
2081 instance_t * i = dict_lookup(&instances, name);
2083 syntaxerror("instance '%s' unknown(10)", name);
2084 if (change_sets_all)
2085 readParameters(i->history, p, currentframe);
2090 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2092 history_begin(i->history, "x", currentframe, tag, p->x);
2093 history_begin(i->history, "y", currentframe, tag, p->y);
2094 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2095 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2096 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2097 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2098 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2099 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2100 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2101 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2102 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2103 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2104 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2105 history_begin(i->history, "shear", currentframe, tag, p->shear);
2106 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2107 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2108 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2109 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2110 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2111 history_beginFilter(i->history, currentframe, tag, p->filters);
2112 history_begin(i->history, "flags", currentframe, tag, 0);
2115 void s_startclip(const char*instance, const char*character, parameters_t p)
2117 character_t* c = dict_lookup(&characters, character);
2121 syntaxerror("character %s not known", character);
2123 i = s_addinstance(instance, c, currentdepth);
2125 m = s_instancepos(i->character->size, &p);
2127 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2128 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2129 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2131 stack[stackpos].tag = tag;
2132 stack[stackpos].type = 2;
2135 setStartparameters(i, &p, tag);
2142 swf_SetTagPos(stack[stackpos].tag, 0);
2143 swf_GetPlaceObject(stack[stackpos].tag, &p);
2144 p.clipdepth = currentdepth;
2146 swf_ClearTag(stack[stackpos].tag);
2147 swf_SetPlaceObject(stack[stackpos].tag, &p);
2151 void s_put(const char*instance, const char*character, parameters_t p)
2153 character_t* c = dict_lookup(&characters, character);
2157 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2159 i = s_addinstance(instance, c, currentdepth);
2161 m = s_instancepos(i->character->size, &p);
2163 if(p.blendmode || p.filters)
2165 if(stack[0].swf->fileVersion < 8)
2168 warning("blendmodes only supported for flash version>=8");
2170 warning("filters only supported for flash version>=8");
2172 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2175 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2176 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2177 setStartparameters(i, &p, tag);
2181 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2184 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2186 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2187 if (p.set & SF_SCALEX)
2188 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2189 if (p.set & SF_SCALEY)
2190 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2191 if (p.set & SF_CX_R)
2193 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2194 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2196 if (p.set & SF_CX_G)
2198 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2199 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2201 if (p.set & SF_CX_B)
2203 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2204 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2206 if (p.set & SF_CX_A)
2208 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2209 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2211 if (p.set & SF_ROTATE)
2212 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2213 if (p.set & SF_SHEAR)
2214 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2215 if (p.set & SF_PIVOT)
2217 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2218 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2222 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2223 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2225 if (p.set & SF_BLEND)
2226 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2227 if (p.set & SF_FILTER)
2228 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2231 void s_jump(const char* instance, parameters_t p)
2233 instance_t* i = dict_lookup(&instances, instance);
2235 syntaxerror("instance %s not known", instance);
2236 recordChanges(i->history, p, CF_JUMP, 0);
2239 void s_change(const char*instance, parameters_t p, interpolation_t* inter)
2241 instance_t* i = dict_lookup(&instances, instance);
2243 syntaxerror("instance %s not known", instance);
2244 recordChanges(i->history, p, CF_CHANGE, inter);
2247 void s_sweep(const char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2249 instance_t* i = dict_lookup(&instances, instance);
2251 syntaxerror("instance %s not known", instance);
2252 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2255 void s_toggle(const char* instance, U16 flagsOn, U16 flagsOff)
2257 instance_t* i = dict_lookup(&instances, instance);
2259 syntaxerror("instance %s not known", instance);
2260 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2263 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2266 void s_delinstance(const char*instance)
2268 instance_t* i = dict_lookup(&instances, instance);
2270 syntaxerror("instance %s not known", instance);
2272 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2273 swf_SetU16(tag, i->depth);
2274 dict_del(&instances, instance);
2278 void s_schange(const char*instance, parameters_t p, interpolation_t* inter)
2280 instance_t* i = dict_lookup(&instances, instance);
2282 syntaxerror("instance %s not known", instance);
2283 recordChanges(i->history, p, CF_SCHANGE, inter);
2289 syntaxerror(".end unexpected");
2290 switch (stack[stackpos-1].type)
2305 syntaxerror("internal error 1");
2309 // ------------------------------------------------------------------------
2311 typedef int command_func_t(map_t*args);
2313 SRECT parseBox(const char*str)
2315 SRECT r = {0,0,0,0};
2316 float xmin, xmax, ymin, ymax;
2317 char*x = strchr(str, 'x');
2319 if(!strcmp(str, "autocrop")) {
2320 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2324 d1 = strchr(x+1, ':');
2326 d2 = strchr(d1+1, ':');
2328 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2332 else if(d1 && !d2) {
2333 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2339 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2344 r.xmin = (SCOORD)(xmin*20);
2345 r.ymin = (SCOORD)(ymin*20);
2346 r.xmax = (SCOORD)(xmax*20);
2347 r.ymax = (SCOORD)(ymax*20);
2350 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2353 float parseFloat(const char*str)
2357 int parseInt(const char*str)
2362 if(str[0]=='+' || str[0]=='-')
2366 if(str[t]<'0' || str[t]>'9')
2367 syntaxerror("Not an Integer: \"%s\"", str);
2370 static double parseRawTwip(const char*str)
2374 if(str[0]=='+' || str[0]=='-') {
2379 dot = strchr(str, '.');
2383 return sign*parseInt(str);
2385 char* old = strdup(str);
2386 int l=strlen(dot+1);
2389 for(s=str;s<dot-1;s++) {
2390 if(*s<'0' || *s>'9')
2393 syntaxerror("Not a coordinate: \"%s\"", str);
2397 if(*s<'0' || *s>'9')
2400 syntaxerror("Not a coordinate: \"%s\"", str);
2403 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2404 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2407 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2411 return sign*(atoi(str));
2413 return sign*(atoi(str)+0.1*atoi(dot));
2415 return sign*(atoi(str)+0.01*atoi(dot));
2420 static dict_t defines;
2421 static int defines_initialized = 0;
2422 static mem_t define_values;
2424 static double parseNameOrTwip(const char*s)
2428 if(defines_initialized) {
2429 l = (int)dict_lookup(&defines, s);
2432 return *(int*)&define_values.buffer[l-1];
2434 return parseRawTwip(s);
2438 /* automatically generated by yiyiyacc, http://www.quiss.org/yiyiyacc/ */
2439 static double parseExpression(char*s)
2442 memset(chr2index, -1, sizeof(chr2index));
2449 chr2index['\0'] = 7;
2457 int left[10]={11,8,8,8,8,9,9,9,10,10}; //production left side
2458 int plen[10]={1,3,2,3,1,3,3,1,1,3}; //production size
2459 int table[18][12] = {
2460 {0, 4, 0, 0, 5, 6, 0, 0, 1, 2, 3, 0},
2461 {7, 8, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0},
2462 {-4, -4, 9, 10, 0, 0, -4, -4, 0, 0, 0, 0},
2463 {-7, -7, -7, -7, 0, 0, -7, -7, 0, 0, 0, 0},
2464 {0, 0, 0, 0, 5, 6, 0, 0, 0, 11, 3, 0},
2465 {-8, -8, -8, -8, 0, 0, -8, -8, 0, 0, 0, 0},
2466 {0, 4, 0, 0, 5, 6, 0, 0, 12, 2, 3, 0},
2467 {0, 0, 0, 0, 5, 6, 0, 0, 0, 13, 3, 0},
2468 {0, 0, 0, 0, 5, 6, 0, 0, 0, 14, 3, 0},
2469 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 15, 0},
2470 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 16, 0},
2471 {-2, -2, 9, 10, 0, 0, -2, -2, 0, 0, 0, 0},
2472 {7, 8, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0},
2473 {-1, -1, 9, 10, 0, 0, -1, -1, 0, 0, 0, 0},
2474 {-3, -3, 9, 10, 0, 0, -3, -3, 0, 0, 0, 0},
2475 {-5, -5, -5, -5, 0, 0, -5, -5, 0, 0, 0, 0},
2476 {-6, -6, -6, -6, 0, 0, -6, -6, 0, 0, 0, 0},
2477 {-9, -9, -9, -9, 0, 0, -9, -9, 0, 0, 0, 0}};
2485 fprintf(stderr, "Error in expression\n");
2489 if(chr2index[*p]<0) {
2490 action = table[stack[stackpos-1]][4];
2492 while(chr2index[*pnext]<0)
2496 value = parseNameOrTwip(p);
2500 action = table[stack[stackpos-1]][chr2index[*p]];
2503 if(action == accept) {
2504 return values[stack[stackpos-1]];
2505 } else if(action>0) { // shift
2507 fprintf(stderr, "Stack overflow while parsing expression\n");
2510 values[stackpos]=value;
2511 stack[stackpos++]=action;
2513 } else if(action<0) { // reduce
2514 stackpos-=plen[-action];
2515 stack[stackpos] = table[stack[stackpos-1]][left[-action]];
2518 values[stackpos] = values[stackpos+0] + values[stackpos+2];
2521 values[stackpos] = 0 - values[stackpos+1];
2524 values[stackpos] = values[stackpos+0] - values[stackpos+2];
2527 values[stackpos] = values[stackpos+0] * values[stackpos+2];
2530 values[stackpos] = values[stackpos+0] / values[stackpos+2];
2533 values[stackpos] = values[stackpos+1];
2538 fprintf(stderr, "Syntax error in expression\n");
2544 int parseTwip(const char*str)
2546 char*str2 = (char*)str;
2547 int v = (int)(parseExpression(str2)*20);
2551 int parseArc(const char* str)
2553 if (!strcmp(str, "short"))
2555 if (!strcmp(str, "long"))
2557 syntaxerror("invalid value for the arc parameter: %s", str);
2561 int parseDir(const char* str)
2563 if (!strcmp(str, "clockwise"))
2565 if (!strcmp(str, "counterclockwise"))
2567 syntaxerror("invalid value for the dir parameter: %s", str);
2571 int isPoint(const char*str)
2573 if(strchr(str, '('))
2579 SPOINT parsePoint(const char*str)
2583 int l = strlen(str);
2584 char*comma = strchr(str, ',');
2585 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2586 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2587 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2588 p.x = parseTwip(tmp);
2589 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2590 p.y = parseTwip(tmp);
2594 int parseColor2(const char*str, RGBA*color)
2596 int l = strlen(str);
2600 struct {unsigned char r,g,b;char*name;} colors[] =
2601 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2602 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2603 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2604 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2605 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2606 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2607 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2608 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2609 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2610 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2611 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2612 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2616 if(str[0]=='#' && (l==7 || l==9)) {
2617 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2619 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2621 color->r = r; color->g = g; color->b = b; color->a = a;
2624 int len=strlen(str);
2626 if(strchr(str, '/')) {
2627 len = strchr(str, '/')-str;
2628 sscanf(str+len+1,"%02x", &alpha);
2630 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2631 if(!strncmp(str, colors[t].name, len)) {
2636 color->r = r; color->g = g; color->b = b; color->a = a;
2642 RGBA parseColor(const char*str)
2645 if(!parseColor2(str, &c))
2646 syntaxerror("Expression '%s' is not a color", str);
2650 typedef struct _muladd {
2655 MULADD parseMulAdd(const char*str)
2658 char* str2 = (char*)malloc(strlen(str)+5);
2665 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2666 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2667 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2668 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2669 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2670 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2671 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2672 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2673 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2674 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2676 syntaxerror("'%s' is not a valid color transform expression", str);
2678 m.add = (int)(add*256);
2679 m.mul = (int)(mul*256);
2684 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2686 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2687 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2689 if(a<-32768) a=-32768;
2690 if(a>32767) a=32767;
2691 if(m<-32768) m=-32768;
2692 if(m>32767) m=32767;
2698 float parsePxOrPercent(const char*fontname, const char*str)
2700 int l = strlen(str);
2701 if(strchr(str, '%'))
2702 return parsePercent(str);
2703 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2704 float p = atof(str);
2705 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2707 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2711 float parsePercent(const char*str)
2713 int l = strlen(str);
2717 return atoi(str)/100.0;
2719 syntaxerror("Expression '%s' is not a percentage", str);
2722 int isPercent(const char*str)
2724 return str[strlen(str)-1]=='%';
2726 int parseNewSize(const char*str, int size)
2729 return parsePercent(str)*size;
2731 return (int)(atof(str)*20);
2734 int isColor(char*str)
2737 return parseColor2(str, &c);
2740 static const char* lu(map_t* args, char*name)
2742 const char* value = map_lookup(args, name);
2744 map_dump(args, stdout, "");
2745 syntaxerror("internal error 2: value %s should be set", name);
2750 static int c_flash(map_t*args)
2752 const char* filename = map_lookup(args, "filename");
2753 const char* compressstr = lu(args, "compress");
2754 const char* change_modestr = lu(args, "change-sets-all");
2755 const char* exportstr = lu(args, "export");
2756 SRECT bbox = parseBox(lu(args, "bbox"));
2757 int version = parseInt(lu(args, "version"));
2758 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2759 RGBA color = parseColor(lu(args, "background"));
2762 if(!filename || !*filename) {
2763 /* for compatibility */
2764 filename = map_lookup(args, "name");
2765 if(!filename || !*filename) {
2768 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2769 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2773 if(!filename || override_outputname)
2774 filename = outputname;
2776 if(!strcmp(compressstr, "default"))
2777 compress = version>=6;
2778 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2780 else if(!strcmp(compressstr, "no"))
2782 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2784 if(!strcmp(change_modestr, "yes"))
2785 change_sets_all = 1;
2787 if(strcmp(change_modestr, "no"))
2788 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2790 do_exports=atoi(exportstr);
2792 s_swf(filename, bbox, version, fps, compress, color);
2795 int isRelative(const char*str)
2797 return !strncmp(str, "<plus>", 6) ||
2798 !strncmp(str, "<minus>", 7);
2800 const char* getOffset(const char*str)
2802 if(!strncmp(str, "<plus>", 6))
2804 if(!strncmp(str, "<minus>", 7))
2806 syntaxerror("internal error (347)");
2809 int getSign(const char*str)
2811 if(!strncmp(str, "<plus>", 6))
2813 if(!strncmp(str, "<minus>", 7))
2815 syntaxerror("internal error (348)");
2819 static dict_t points;
2820 static mem_t mpoints;
2821 static int points_initialized = 0;
2823 static int c_interpolation(map_t *args)
2826 const char* name = lu(args, "name");
2827 if (dict_lookup(&interpolations, name))
2828 syntaxerror("interpolation %s defined twice", name);
2830 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2831 const char* functionstr = lu(args, "function");
2832 inter->function = 0;
2833 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2834 if (!strcmp(functionstr,interpolationFunctions[i]))
2836 inter->function = i + 1;
2839 if (!inter->function)
2840 syntaxerror("unkown interpolation function %s", functionstr);
2841 inter->speed = parseFloat(lu(args, "speed"));
2842 inter->amplitude = parseTwip(lu(args, "amplitude"));
2843 inter->growth = parseFloat(lu(args, "growth"));
2844 inter->bounces = parseInt(lu(args, "bounces"));
2845 inter->damping = parseFloat(lu(args, "damping"));
2846 inter->slope = parseFloat(lu(args, "slope"));
2848 dict_put(&interpolations, name, inter);
2852 SPOINT getPoint(SRECT r, const char*name)
2855 if(!strcmp(name, "center")) {
2857 p.x = (r.xmin + r.xmax)/2;
2858 p.y = (r.ymin + r.ymax)/2;
2861 if (!strcmp(name, "bottom-center")) {
2863 p.x = (r.xmin + r.xmax)/2;
2867 if (!strcmp(name, "top-center")) {
2869 p.x = (r.xmin + r.xmax)/2;
2873 if (!strcmp(name, "top-left")) {
2879 if (!strcmp(name, "top-right")) {
2885 if (!strcmp(name, "bottom-right")) {
2891 if (!strcmp(name, "bottom-left")) {
2897 if (!strcmp(name, "left-center")) {
2900 p.y = (r.ymin + r.ymax)/2;
2903 if (!strcmp(name, "right-center")) {
2906 p.y = (r.ymin + r.ymax)/2;
2911 if(points_initialized)
2912 l = (int)dict_lookup(&points, name);
2914 syntaxerror("Invalid point: \"%s\".", name);
2916 return *(SPOINT*)&mpoints.buffer[l-1];
2920 static int texture2(const char*name, const char*object, map_t*args, int errors)
2923 const char*xstr = map_lookup(args, "x");
2924 const char*ystr = map_lookup(args, "y");
2925 const char*widthstr = map_lookup(args, "width");
2926 const char*heightstr = map_lookup(args, "height");
2927 const char*scalestr = map_lookup(args, "scale");
2928 const char*scalexstr = map_lookup(args, "scalex");
2929 const char*scaleystr = map_lookup(args, "scaley");
2930 const char*rotatestr = map_lookup(args, "rotate");
2931 const char* shearstr = map_lookup(args, "shear");
2932 const char* radiusstr = map_lookup(args, "r");
2934 float scalex = 1.0, scaley = 1.0;
2935 float rotate=0, shear=0;
2937 if(!*xstr && !*ystr) {
2939 syntaxerror("x and y must be set");
2942 if(*scalestr && (*scalexstr || *scaleystr)) {
2943 syntaxerror("scale and scalex/scaley can't both be set");
2946 if((*widthstr || *heightstr) && *radiusstr) {
2947 syntaxerror("width/height and radius can't both be set");
2950 widthstr = radiusstr;
2951 heightstr = radiusstr;
2953 if(!*xstr) xstr="0";
2954 if(!*ystr) ystr="0";
2955 if(!*rotatestr) rotatestr="0";
2956 if(!*shearstr) shearstr="0";
2959 scalex = scaley = parsePercent(scalestr);
2960 } else if(*scalexstr || *scaleystr) {
2961 if(scalexstr) scalex = parsePercent(scalexstr);
2962 if(scaleystr) scaley = parsePercent(scaleystr);
2963 } else if(*widthstr || *heightstr) {
2966 s_getBitmapSize(object, &width, &height);
2968 scalex = (float)parseTwip(widthstr)/(float)width;
2970 scaley = (float)parseTwip(heightstr)/(float)height;
2972 x = parseTwip(xstr);
2973 y = parseTwip(ystr);
2974 rotate = parseFloat(rotatestr);
2975 shear = parseFloat(shearstr);
2977 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2982 static int c_texture(map_t*args)
2984 const char*name = lu(args, "instance");
2985 const char*object = lu(args, "character");
2986 return texture2(name, object, args, 1);
2989 static int c_gradient(map_t*args)
2991 const char*name = lu(args, "name");
2992 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2993 int rotate = parseInt(lu(args, "rotate"));
2997 syntaxerror("colon (:) expected");
2999 if(dict_lookup(&gradients, name))
3000 syntaxerror("gradient %s defined twice", name);
3002 s_gradient(name, text, radial, rotate);
3004 /* check whether we also have placement information,
3005 which would make this a positioned gradient.
3006 If there is placement information, texture2() will
3007 add a texture, which has priority over the gradient.
3009 texture2(name, name, args, 0);
3013 static const char* checkFiltername(map_t* args)
3015 const char* name = lu(args, "name");
3016 if (strchr(name, ','))
3017 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
3021 static int c_blur(map_t*args)
3023 const char*name = checkFiltername(args);
3024 const char*blurstr = lu(args, "blur");
3025 const char*blurxstr = lu(args, "blurx");
3026 const char*blurystr = lu(args, "blury");
3027 float blurx=1.0, blury=1.0;
3029 blurx = parseFloat(blurstr);
3030 blury = parseFloat(blurstr);
3033 blurx = parseFloat(blurxstr);
3035 blury = parseFloat(blurystr);
3036 int passes = parseInt(lu(args, "passes"));
3037 s_blur(name, blurx, blury, passes);
3041 static int c_gradientglow(map_t*args)
3043 const char*name = checkFiltername(args);
3044 const char*gradient = lu(args, "gradient");
3045 const char*blurstr = lu(args, "blur");
3046 const char*blurxstr = lu(args, "blurx");
3047 const char*blurystr = lu(args, "blury");
3048 float blurx=1.0, blury=1.0;
3050 blurx = parseFloat(blurstr);
3051 blury = parseFloat(blurstr);
3054 blurx = parseFloat(blurxstr);
3056 blury = parseFloat(blurystr);
3058 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3059 float distance = parseFloat(lu(args, "distance"));
3060 float strength = parseFloat(lu(args, "strength"));
3061 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3062 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3063 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3064 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3065 int passes = parseInt(lu(args, "passes"));
3067 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3071 static int c_dropshadow(map_t*args)
3073 const char*name = checkFiltername(args);
3074 RGBA color = parseColor(lu(args, "color"));
3075 const char*blurstr = lu(args, "blur");
3076 const char*blurxstr = lu(args, "blurx");
3077 const char*blurystr = lu(args, "blury");
3078 float blurx=1.0, blury=1.0;
3080 blurx = parseFloat(blurstr);
3081 blury = parseFloat(blurstr);
3084 blurx = parseFloat(blurxstr);
3086 blury = parseFloat(blurystr);
3088 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3089 float distance = parseFloat(lu(args, "distance"));
3090 float strength = parseFloat(lu(args, "strength"));
3091 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3092 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3093 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3094 int passes = parseInt(lu(args, "passes"));
3096 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3100 static int c_bevel(map_t*args)
3102 const char*name = checkFiltername(args);
3103 RGBA shadow = parseColor(lu(args, "shadow"));
3104 RGBA highlight = parseColor(lu(args, "highlight"));
3105 const char*blurstr = lu(args, "blur");
3106 const char*blurxstr = lu(args, "blurx");
3107 const char*blurystr = lu(args, "blury");
3108 float blurx=1.0, blury=1.0;
3110 blurx = parseFloat(blurstr);
3111 blury = parseFloat(blurstr);
3114 blurx = parseFloat(blurxstr);
3116 blury = parseFloat(blurystr);
3118 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3119 float distance = parseFloat(lu(args, "distance"));
3120 float strength = parseFloat(lu(args, "strength"));
3121 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3122 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3123 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3124 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3125 int passes = parseInt(lu(args, "passes"));
3127 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3131 static int c_define(map_t*args)
3133 const char*name = lu(args, "name");
3134 const char*value = lu(args, "value");
3136 if(!defines_initialized) {
3137 dict_init(&defines, 16);
3138 mem_init(&define_values);
3139 defines_initialized = 1;
3141 int val = parseTwip(value);
3142 int pos = mem_put(&define_values, &val, sizeof(val));
3143 dict_put(&defines, name, (void*)(pos+1));
3146 static int c_point(map_t*args)
3148 const char*name = lu(args, "name");
3151 if(!points_initialized) {
3152 dict_init(&points, 16);
3154 points_initialized = 1;
3156 p.x = parseTwip(lu(args, "x"));
3157 p.y = parseTwip(lu(args, "y"));
3158 pos = mem_put(&mpoints, &p, sizeof(p));
3159 dict_put(&points, name, (void*)(pos+1));
3162 static int c_play(map_t*args)
3164 const char*name = lu(args, "name");
3165 const char*loop = lu(args, "loop");
3166 const char*nomultiple = lu(args, "nomultiple");
3168 if(!strcmp(nomultiple, "nomultiple"))
3171 nm = parseInt(nomultiple);
3173 if(s_playsound(name, parseInt(loop), nm, 0)) {
3175 } else if(s_swf3action(name, "play")) {
3181 static int c_stop(map_t*args)
3183 const char*name = map_lookup(args, "name");
3185 if(s_playsound(name, 0,0,1))
3187 else if(s_swf3action(name, "stop"))
3189 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3193 static int c_nextframe(map_t*args)
3195 const char*name = lu(args, "name");
3197 if(s_swf3action(name, "nextframe")) {
3200 syntaxerror("I don't know anything about movie \"%s\"", name);
3204 static int c_previousframe(map_t*args)
3206 const char*name = lu(args, "name");
3208 if(s_swf3action(name, "previousframe")) {
3211 syntaxerror("I don't know anything about movie \"%s\"", name);
3215 static int c_movement(map_t*args, int type)
3217 const char*instance = lu(args, "name");
3219 const char* xstr="";
3220 const char* ystr="";
3225 xstr = lu(args, "x");
3226 ystr = lu(args, "y");
3228 s_getParameters(instance, &p);
3233 if(isRelative(xstr))
3235 if(type == PT_PUT || type == PT_STARTCLIP)
3236 syntaxerror("relative x values not allowed for initial put or startclip");
3237 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3241 p.x = parseTwip(xstr);
3247 if(isRelative(ystr))
3249 if(type == PT_PUT || type == PT_STARTCLIP)
3250 syntaxerror("relative y values not allowed for initial put or startclip");
3251 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3255 p.y = parseTwip(ystr);
3260 if (change_sets_all)
3268 const char* interstr = lu(args, "interpolation");
3269 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3271 syntaxerror("unkown interpolation %s", interstr);
3272 s_change(instance, p, inter);
3277 const char* interstr = lu(args, "interpolation");
3278 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3280 syntaxerror("unkown interpolation %s", interstr);
3281 s_schange(instance, p, inter);
3286 const char* rstr = lu(args, "r");
3287 int radius = parseTwip(rstr);
3289 syntaxerror("sweep not possible: radius must be greater than 0.");
3290 const char* dirstr = lu(args, "dir");
3291 int clockwise = parseDir(dirstr);
3292 const char* arcstr = lu(args, "arc");
3293 int short_arc = parseArc(arcstr);
3294 const char* interstr = lu(args, "interpolation");
3295 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3297 syntaxerror("unkown interpolation %s", interstr);
3298 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3305 static int c_placement(map_t*args, int type)
3307 const char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3308 const char*character = 0;
3310 const char* luminancestr = lu(args, "luminance");
3311 const char* scalestr = lu(args, "scale");
3312 const char* scalexstr = lu(args, "scalex");
3313 const char* scaleystr = lu(args, "scaley");
3314 const char* rotatestr = lu(args, "rotate");
3315 const char* shearstr = lu(args, "shear");
3316 const char* xstr="", *pivotstr="";
3317 const char* ystr="", *anglestr="";
3318 const char*above = lu(args, "above"); /*FIXME*/
3319 const char*below = lu(args, "below");
3320 const char* rstr = lu(args, "red");
3321 const char* gstr = lu(args, "green");
3322 const char* bstr = lu(args, "blue");
3323 const char* astr = lu(args, "alpha");
3324 const char* pinstr = lu(args, "pin");
3325 const char* as = map_lookup(args, "as");
3326 const char* blendmode = lu(args, "blend");
3327 const char* filterstr = lu(args, "filter");
3338 { // (?) .rotate or .arcchange
3339 pivotstr = lu(args, "pivot");
3340 anglestr = lu(args, "angle");
3344 xstr = lu(args, "x");
3345 ystr = lu(args, "y");
3349 luminance = parseMulAdd(luminancestr);
3353 luminance.mul = 256;
3358 if(scalexstr[0]||scaleystr[0])
3359 syntaxerror("scalex/scaley and scale cannot both be set");
3360 scalexstr = scaleystr = scalestr;
3363 if(type == PT_PUT || type == PT_STARTCLIP) {
3365 character = lu(args, "character");
3366 parameters_clear(&p);
3367 } else if (type == PT_BUTTON) {
3368 character = lu(args, "name");
3369 parameters_clear(&p);
3372 s_getParameters(instance, &p);
3378 if(isRelative(xstr))
3380 if(type == PT_PUT || type == PT_STARTCLIP)
3381 syntaxerror("relative x values not allowed for initial put or startclip");
3382 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3386 p.x = parseTwip(xstr);
3392 if(isRelative(ystr))
3394 if(type == PT_PUT || type == PT_STARTCLIP)
3395 syntaxerror("relative y values not allowed for initial put or startclip");
3396 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3400 p.y = parseTwip(ystr);
3405 /* scale, scalex, scaley */
3407 oldbbox = s_getCharBBox(character);
3409 oldbbox = s_getInstanceBBox(instance);
3410 oldwidth = oldbbox.xmax - oldbbox.xmin;
3411 oldheight = oldbbox.ymax - oldbbox.ymin;
3418 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3419 set = set | SF_SCALEX;
3427 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3428 set = set | SF_SCALEY;
3434 if(isRelative(rotatestr))
3435 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3437 p.rotate = parseFloat(rotatestr);
3438 set = set | SF_ROTATE;
3444 if(isRelative(shearstr))
3445 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3447 p.shear = parseFloat(shearstr);
3448 set = set | SF_SHEAR;
3453 if(isPoint(pivotstr))
3454 p.pivot = parsePoint(pivotstr);
3456 p.pivot = getPoint(oldbbox, pivotstr);
3457 set = set | SF_PIVOT;
3463 p.pin = parsePoint(pinstr);
3465 p.pin = getPoint(oldbbox, pinstr);
3469 /* color transform */
3471 if(rstr[0] || luminancestr[0])
3475 r = parseMulAdd(rstr);
3478 r.add = p.cxform.r0;
3479 r.mul = p.cxform.r1;
3481 r = mergeMulAdd(r, luminance);
3482 p.cxform.r0 = r.mul;
3483 p.cxform.r1 = r.add;
3484 set = set | SF_CX_R;
3486 if(gstr[0] || luminancestr[0])
3490 g = parseMulAdd(gstr);
3493 g.add = p.cxform.g0;
3494 g.mul = p.cxform.g1;
3496 g = mergeMulAdd(g, luminance);
3497 p.cxform.g0 = g.mul;
3498 p.cxform.g1 = g.add;
3499 set = set | SF_CX_G;
3501 if(bstr[0] || luminancestr[0])
3505 b = parseMulAdd(bstr);
3508 b.add = p.cxform.b0;
3509 b.mul = p.cxform.b1;
3511 b = mergeMulAdd(b, luminance);
3512 p.cxform.b0 = b.mul;
3513 p.cxform.b1 = b.add;
3514 set = set | SF_CX_B;
3518 MULADD a = parseMulAdd(astr);
3519 p.cxform.a0 = a.mul;
3520 p.cxform.a1 = a.add;
3521 set = set | SF_CX_A;
3528 for(t = 0; blendModeNames[t]; t++)
3530 if(!strcmp(blendModeNames[t], blendmode))
3538 syntaxerror("unknown blend mode: '%s'", blendmode);
3540 p.blendmode = blend;
3541 set = set | SF_BLEND;
3546 p.filters = parseFilters((char*)filterstr);
3547 set = set | SF_FILTER;
3550 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3551 warning("As of version 0.8.2 using the .change command to modify an \
3552 object's position on the stage is considered deprecated. Future \
3553 versions may consider x and y parameters for the .change command \
3554 to be illegal; please use the .move command.");
3556 if (change_sets_all)
3563 s_put(instance, character, p);
3567 const char* interstr = lu(args, "interpolation");
3568 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3570 syntaxerror("unkown interpolation %s", interstr);
3571 s_change(instance, p, inter);
3576 const char* interstr = lu(args, "interpolation");
3577 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3579 syntaxerror("unkown interpolation %s", interstr);
3580 s_schange(instance, p, inter);
3584 s_jump(instance, p);
3587 s_startclip(instance, character, p);
3591 s_buttonput(character, as, p);
3593 s_buttonput(character, "shape", p);
3599 static int c_put(map_t*args)
3601 c_placement(args, PT_PUT);
3604 static int c_change(map_t*args)
3606 if (currentframe == 0)
3607 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3608 c_placement(args, PT_CHANGE);
3611 static int c_schange(map_t*args)
3613 c_placement(args, PT_SCHANGE);
3616 static int c_move(map_t* args)
3618 c_movement(args, PT_MOVE);
3621 static int c_smove(map_t* args)
3623 c_movement(args, PT_SMOVE);
3626 static int c_sweep(map_t* args)
3628 c_movement(args, PT_SWEEP);
3631 static int c_arcchange(map_t*args)
3633 c_placement(args, 0);
3636 static int c_jump(map_t*args)
3638 c_placement(args, PT_JUMP);
3641 static int c_startclip(map_t*args)
3643 c_placement(args, PT_STARTCLIP);
3646 static int c_show(map_t*args)
3648 c_placement(args, PT_BUTTON);
3651 static int c_toggle(map_t* args)
3653 const char*instance = lu(args, "name");
3654 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3655 const char* alignstr = lu(args, "fixed_alignment");
3656 if (!strcmp(alignstr, "on"))
3657 flagsOn += IF_FIXED_ALIGNMENT;
3659 if (!strcmp(alignstr, "off"))
3660 flagsOff -= IF_FIXED_ALIGNMENT;
3662 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3663 s_toggle(instance, flagsOn, flagsOff);
3666 static int c_del(map_t*args)
3668 const char*instance = lu(args, "name");
3669 s_delinstance(instance);
3672 static int c_end(map_t*args)
3677 static int c_sprite(map_t*args)
3679 const char* name = lu(args, "name");
3680 const char* scalinggrid = lu(args, "scalinggrid");
3682 if(scalinggrid && *scalinggrid) {
3683 SRECT r = parseBox(scalinggrid);
3690 static int c_frame(map_t*args)
3692 const char*framestr = lu(args, "n");
3693 const char*cutstr = lu(args, "cut");
3695 const char*name = lu(args, "name");
3696 const char*anchor = lu(args, "anchor");
3699 if(!strcmp(anchor, "anchor") && !*name)
3704 if(strcmp(cutstr, "no"))
3706 if(isRelative(framestr)) {
3707 frame = s_getframe();
3708 if(getSign(framestr)<0)
3709 syntaxerror("relative frame expressions must be positive");
3710 frame += parseInt(getOffset(framestr));
3713 frame = parseInt(framestr);
3714 if(s_getframe() >= frame
3715 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3716 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3718 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3721 static int c_primitive(map_t*args)
3723 const char*name = lu(args, "name");
3724 const char*command = lu(args, "commandname");
3725 int width=0, height=0, r=0;
3726 int linewidth = parseTwip(lu(args, "line"));
3727 const char*colorstr = lu(args, "color");
3728 RGBA color = parseColor(colorstr);
3729 const char*fillstr = lu(args, "fill");
3734 const char* outline=0;
3736 if(!strcmp(command, "circle"))
3738 else if(!strcmp(command, "filled"))
3742 width = parseTwip(lu(args, "width"));
3743 height = parseTwip(lu(args, "height"));
3744 } else if (type==1) {
3745 r = parseTwip(lu(args, "r"));
3746 } else if (type==2) {
3747 outline = lu(args, "outline");
3750 if(!strcmp(fillstr, "fill"))
3752 if(!strcmp(fillstr, "none"))
3754 if(width<0 || height<0 || linewidth<0 || r<0)
3755 syntaxerror("values width, height, line, r must be positive");
3757 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3758 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3759 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3763 static int c_textshape(map_t*args)
3765 const char*name = lu(args, "name");
3766 const char*text = lu(args, "text");
3767 const char*font = lu(args, "font");
3768 float size = parsePxOrPercent(font, lu(args, "size"));
3770 s_textshape(name, font, size, text);
3774 static int c_swf(map_t*args)
3776 const char*name = lu(args, "name");
3777 const char*filename = lu(args, "filename");
3778 const char*command = lu(args, "commandname");
3779 if(!strcmp(command, "shape"))
3780 warning("Please use .swf instead of .shape");
3781 s_includeswf(name, filename);
3785 static int c_font(map_t*args)
3787 const char*name = lu(args, "name");
3788 const char*filename = lu(args, "filename");
3789 s_font(name, filename);
3793 static int c_sound(map_t*args)
3795 const char*name = lu(args, "name");
3796 const char*filename = lu(args, "filename");
3797 s_sound(name, filename);
3801 static int c_text(map_t*args)
3803 const char*name = lu(args, "name");
3804 const char*text = lu(args, "text");
3805 const char*font = lu(args, "font");
3806 float size = parsePxOrPercent(font, lu(args, "size"));
3807 RGBA color = parseColor(lu(args, "color"));
3808 s_text(name, font, text, (int)(size*100), color);
3812 static int c_soundtrack(map_t*args)
3817 static int c_quicktime(map_t*args)
3819 const char*name = lu(args, "name");
3820 const char*url = lu(args, "url");
3821 s_quicktime(name, url);
3825 static int c_image(map_t*args)
3827 const char*command = lu(args, "commandname");
3828 const char*name = lu(args, "name");
3829 const char*filename = lu(args, "filename");
3830 if(!strcmp(command,"jpeg")) {
3831 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3832 s_image(name, "jpeg", filename, quality);
3834 s_image(name, "png", filename, 0);
3839 static int c_outline(map_t*args)
3841 const char*name = lu(args, "name");
3842 const char*format = lu(args, "format");
3846 syntaxerror("colon (:) expected");
3848 s_outline(name, format, text);
3852 int fakechar(map_t*args)
3854 const char*name = lu(args, "name");
3855 s_box(name, 0, 0, black, 20, 0);
3859 static int c_egon(map_t*args) {return fakechar(args);}
3860 static int c_button(map_t*args) {
3861 const char*name = lu(args, "name");
3865 static int current_button_flags = 0;
3866 static int c_on_press(map_t*args)
3868 const char*position = lu(args, "position");
3869 const char*action = "";
3870 if(!strcmp(position, "inside")) {
3871 current_button_flags |= BC_OVERUP_OVERDOWN;
3872 } else if(!strcmp(position, "outside")) {
3873 //current_button_flags |= BC_IDLE_OUTDOWN;
3874 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3875 } else if(!strcmp(position, "anywhere")) {
3876 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3879 if(type == RAWDATA) {
3881 s_buttonaction(current_button_flags, action);
3882 current_button_flags = 0;
3888 static int c_on_release(map_t*args)
3890 const char*position = lu(args, "position");
3891 const char*action = "";
3892 if(!strcmp(position, "inside")) {
3893 current_button_flags |= BC_OVERDOWN_OVERUP;
3894 } else if(!strcmp(position, "outside")) {
3895 current_button_flags |= BC_OUTDOWN_IDLE;
3896 } else if(!strcmp(position, "anywhere")) {
3897 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3900 if(type == RAWDATA) {
3902 s_buttonaction(current_button_flags, action);
3903 current_button_flags = 0;
3909 static int c_on_move_in(map_t*args)
3911 const char*position = lu(args, "state");
3912 const char*action = "";
3913 if(!strcmp(position, "pressed")) {
3914 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3915 } else if(!strcmp(position, "not_pressed")) {
3916 current_button_flags |= BC_IDLE_OVERUP;
3917 } else if(!strcmp(position, "any")) {
3918 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3921 if(type == RAWDATA) {
3923 s_buttonaction(current_button_flags, action);
3924 current_button_flags = 0;
3930 static int c_on_move_out(map_t*args)
3932 const char*position = lu(args, "state");
3933 const char*action = "";
3934 if(!strcmp(position, "pressed")) {
3935 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3936 } else if(!strcmp(position, "not_pressed")) {
3937 current_button_flags |= BC_OVERUP_IDLE;
3938 } else if(!strcmp(position, "any")) {
3939 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3942 if(type == RAWDATA) {
3944 s_buttonaction(current_button_flags, action);
3945 current_button_flags = 0;
3951 static int c_on_key(map_t*args)
3953 const char*key = lu(args, "key");
3954 const char*action = "";
3955 if(strlen(key)==1) {
3958 current_button_flags |= 0x4000 + (key[0]*0x200);
3960 syntaxerror("invalid character: %c"+key[0]);
3965 <ctrl-x> = 0x200*(x-'a')
3969 syntaxerror("invalid key: %s",key);
3972 if(type == RAWDATA) {
3974 s_buttonaction(current_button_flags, action);
3975 current_button_flags = 0;
3982 static int c_edittext(map_t*args)
3984 //"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"},
3985 const char*name = lu(args, "name");
3986 const char*font = lu(args, "font");
3987 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3988 int width = parseTwip(lu(args, "width"));
3989 int height = parseTwip(lu(args, "height"));
3990 const char*text = lu(args, "text");
3991 RGBA color = parseColor(lu(args, "color"));
3992 int maxlength = parseInt(lu(args, "maxlength"));
3993 const char*variable = lu(args, "variable");
3994 const char*passwordstr = lu(args, "password");
3995 const char*wordwrapstr = lu(args, "wordwrap");
3996 const char*multilinestr = lu(args, "multiline");
3997 const char*htmlstr = lu(args, "html");
3998 const char*noselectstr = lu(args, "noselect");
3999 const char*readonlystr = lu(args, "readonly");
4000 const char*borderstr = lu(args, "border");
4001 const char*autosizestr = lu(args, "autosize");
4002 const char*alignstr = lu(args, "align");
4006 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
4007 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
4008 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
4009 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
4010 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
4011 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
4012 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
4013 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
4014 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
4015 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
4016 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
4017 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
4018 else syntaxerror("Unknown alignment: %s", alignstr);
4020 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
4024 static int c_morphshape(map_t*args) {return fakechar(args);}
4025 static int c_movie(map_t*args) {return fakechar(args);}
4027 static char* readfile(char*filename)
4029 FILE*fi = fopen(filename, "rb");
4033 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
4034 fseek(fi, 0, SEEK_END);
4036 fseek(fi, 0, SEEK_SET);
4037 text = rfx_alloc(l+1);
4038 fread(text, l, 1, fi);
4044 static int c_action(map_t*args)
4046 const char* filename = map_lookup(args, "filename");
4047 if(!filename ||!*filename) {
4049 if(type != RAWDATA) {
4050 syntaxerror("colon (:) expected");
4054 s_action(readfile((char*)filename));
4060 static int c_initaction(map_t*args)
4062 const char* character = lu(args, "name");
4063 const char* filename = map_lookup(args, "filename");
4064 if(!filename ||!*filename) {
4066 if(type != RAWDATA) {
4067 syntaxerror("colon (:) expected");
4069 s_initaction(character, text);
4071 s_initaction(character, readfile((char*)filename));
4079 command_func_t* func;
4082 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1"},
4083 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
4084 // "import" type stuff
4085 {"swf", c_swf, "name filename"},
4086 {"shape", c_swf, "name filename"},
4087 {"jpeg", c_image, "name filename quality=80%"},
4088 {"png", c_image, "name filename"},
4089 {"movie", c_movie, "name filename"},
4090 {"sound", c_sound, "name filename"},
4091 {"font", c_font, "name filename glyphs="},
4092 {"soundtrack", c_soundtrack, "filename"},
4093 {"quicktime", c_quicktime, "url"},
4095 // generators of primitives
4097 {"define", c_define, "name value=0"},
4098 {"point", c_point, "name x=0 y=0"},
4099 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4100 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4101 {"outline", c_outline, "name format=simple"},
4102 {"textshape", c_textshape, "name font size=100% text"},
4105 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4106 {"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"},
4107 {"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"},
4108 {"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"},
4110 // character generators
4111 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4112 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4113 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4115 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4116 {"text", c_text, "name text font size=100% color=white"},
4117 {"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="},
4118 {"morphshape", c_morphshape, "name start end"},
4119 {"button", c_button, "name"},
4120 {"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="},
4121 {"on_press", c_on_press, "position=inside"},
4122 {"on_release", c_on_release, "position=anywhere"},
4123 {"on_move_in", c_on_move_in, "state=not_pressed"},
4124 {"on_move_out", c_on_move_out, "state=not_pressed"},
4125 {"on_key", c_on_key, "key=any"},
4128 {"play", c_play, "name loop=0 @nomultiple=0"},
4129 {"stop", c_stop, "name= "},
4130 {"nextframe", c_nextframe, "name"},
4131 {"previousframe", c_previousframe, "name"},
4133 // object placement tags
4134 {"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="},
4135 {"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="},
4136 {"move", c_move, "name x= y= interpolation=linear"},
4137 {"smove", c_smove, "name x= y= interpolation=linear"},
4138 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4139 {"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"},
4140 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4141 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4142 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4143 {"del", c_del, "name"},
4144 // virtual object placement
4145 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4147 {"toggle", c_toggle, "name fixed_alignment="},
4149 // commands which start a block
4150 //startclip (see above)
4151 {"sprite", c_sprite, "name scalinggrid="},
4152 {"action", c_action, "filename="},
4153 {"initaction", c_initaction, "name filename="},
4159 static map_t parseArguments(char*command, char*pattern)
4175 string_set(&t1, "commandname");
4176 string_set(&t2, command);
4177 map_put(&result, t1, t2);
4179 if(!pattern || !*pattern)
4186 if(!strncmp("<i> ", x, 3)) {
4188 if(type == COMMAND || type == RAWDATA) {
4190 syntaxerror("character name expected");
4192 name[pos].str = "instance";
4194 value[pos].str = text;
4195 value[pos].len = strlen(text);
4199 if(type == ASSIGNMENT)
4202 name[pos].str = "character";
4204 value[pos].str = text;
4205 value[pos].len = strlen(text);
4213 isboolean[pos] = (x[0] =='@');
4226 name[pos].len = d-x;
4231 name[pos].len = e-x;
4232 value[pos].str = e+1;
4233 value[pos].len = d-e-1;
4241 /* for(t=0;t<len;t++) {
4242 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4243 isboolean[t]?"(boolean)":"");
4248 if(type == RAWDATA || type == COMMAND) {
4253 // first, search for boolean arguments
4254 for(pos=0;pos<len;pos++)
4256 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4258 if(type == ASSIGNMENT)
4260 value[pos].str = text;
4261 value[pos].len = strlen(text);
4262 /*printf("setting boolean parameter %s (to %s)\n",
4263 strdup_n(name[pos], namelen[pos]),
4264 strdup_n(value[pos], valuelen[pos]));*/
4269 // second, search for normal arguments
4271 for(pos=0;pos<len;pos++)
4273 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4274 (type != ASSIGNMENT && !set[pos])) {
4276 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4278 if(type == ASSIGNMENT)
4281 value[pos].str = text;
4282 value[pos].len = strlen(text);
4284 printf("setting parameter %s (to %s)\n",
4285 strdup_n(name[pos].str, name[pos].len),
4286 strdup_n(value[pos].str, value[pos].len));
4292 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4296 for(t=0;t<len;t++) {
4297 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4300 for(t=0;t<len;t++) {
4301 if(value[t].str && value[t].str[0] == '*') {
4302 //relative default- take value from some other parameter
4304 for(s=0;s<len;s++) {
4305 if(value[s].len == value[t].len-1 &&
4306 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4307 value[t].str = value[s].str;
4310 if(value[t].str == 0) {
4312 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4316 /* ok, now construct the dictionary from the parameters */
4320 map_put(&result, name[t], value[t]);
4324 static void parseArgumentsForCommand(char*command)
4329 msg("<verbose> parse Command: %s (line %d)", command, line);
4331 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4332 if(!strcmp(arguments[t].command, command)) {
4334 /* ugly hack- will be removed soon (once documentation and .sc generating
4335 utilities have been changed) */
4336 if(!strcmp(command, "swf") && !stackpos) {
4337 warning("Please use .flash instead of .swf- this will be mandatory soon");
4342 args = parseArguments(command, arguments[t].arguments);
4348 syntaxerror("command %s not known", command);
4351 // catch missing .flash directives at the beginning of a file
4352 if(strcmp(command, "flash") && !stackpos)
4354 syntaxerror("No movie defined- use .flash first");
4359 printf(".%s\n", command);fflush(stdout);
4360 map_dump(&args, stdout, "\t");fflush(stdout);
4364 (*arguments[nr].func)(&args);
4366 if(!strcmp(command, "action") || !strcmp(command, "initaction") ||
4367 !strcmp(command, "outline") || !strcmp(command, "gradient")) {
4369 if(type != RAWDATA) {
4370 syntaxerror("colon (:) expected");
4379 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4380 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4381 * No syntax checking is done */
4382 static void analyseArgumentsForCommand(char*command)
4386 const char* fontfile;
4388 U8* glyphs_to_include;
4389 msg("<verbose> analyse Command: %s (line %d)", command, line);
4391 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4393 if(!strcmp(arguments[t].command, command))
4395 args = parseArguments(command, arguments[t].arguments);
4401 printf(".%s\n", command);fflush(stdout);
4402 map_dump(&args, stdout, "\t");fflush(stdout);
4404 const char* name = lu(&args, "name");
4405 if (!strcmp(command, "font"))
4407 if(dict_lookup(&fonts, name))
4408 syntaxerror("font %s defined twice", name);
4411 fontfile = lu(&args, "filename");
4412 font = swf_LoadFont(fontfile);
4414 warning("Couldn't open font file \"%s\"", fontfile);
4415 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4416 memset(font, 0, sizeof(SWFFONT));
4420 swf_FontPrepareForEditText(font);
4421 glyphs_to_include = (U8*)lu(&args, "glyphs");
4422 if (!strcmp(glyphs_to_include, "all"))
4424 swf_FontUseAll(font);
4425 font->use->glyphs_specified = 1;
4429 if (strcmp (glyphs_to_include, ""))
4431 swf_FontUseUTF8(font, glyphs_to_include);
4432 font->use->glyphs_specified = 1;
4435 swf_FontInitUsage(font);
4438 dict_put(&fonts, name, font);
4442 SWFFONT* font = dict_lookup(&fonts, lu(&args, "font"));
4444 //that's ok... it might be an edittext with a system font
4445 //syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4447 if (font->use && !font->use->glyphs_specified)
4449 if (!strcmp(command, "edittext"))
4451 swf_FontUseAll(font);
4452 font->use->glyphs_specified = 1;
4455 swf_FontUseUTF8(font, (U8*)lu(&args, "text"));
4462 void skipParameters()
4466 while (type != COMMAND);
4470 void findFontUsage()
4472 char* fontRelated = "font;text;textshape;edittext;";
4473 while(!noMoreTokens())
4477 syntaxerror("command expected");
4478 if (strstr(fontRelated, text))
4479 analyseArgumentsForCommand(text);
4481 if(strcmp(text, "end"))
4490 dict_init(&fonts, 16);
4491 cleanUp = &freeFontDictionary;
4495 int main (int argc,char ** argv)
4498 processargs(argc, argv);
4499 initLog(0,-1,0,0,-1,verbose);
4502 args_callback_usage(argv[0]);
4506 file = generateTokens(filename);
4508 fprintf(stderr, "parser returned error.\n");
4515 while(!noMoreTokens()) {
4518 syntaxerror("command expected");
4519 parseArgumentsForCommand(text);