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
181 /* for sprites (1): */
187 dictionary_t oldinstances;
194 static int stackpos = 0;
196 static dictionary_t characters;
197 static dictionary_t images;
198 static dictionary_t textures;
199 static dictionary_t outlines;
200 static dictionary_t gradients;
201 static dictionary_t filters;
202 static dictionary_t interpolations;
203 static char idmap[65536];
204 static TAG*tag = 0; //current tag
206 static int id; //current character id
207 static int currentframe; //current frame in current level
208 static SRECT currentrect; //current bounding box in current level
209 static U16 currentdepth;
210 static dictionary_t instances;
211 static dictionary_t fonts;
212 static dictionary_t sounds;
213 static dictionary_t fontUsage;
215 typedef struct _parameters {
217 float scalex, scaley;
223 U8 blendmode; //not interpolated
225 U16 set; // bits indicating wether a parameter was set in the c_placement function
226 U16 flags; // bits to toggle anything you may care to implement as a toggle
229 typedef struct _character {
235 typedef struct _instance {
236 character_t*character;
238 parameters_t parameters;
242 typedef struct _outline {
247 typedef struct _gradient {
253 typedef struct _filter {
257 typedef struct _texture {
261 char* interpolationFunctions[] = {"linear", \
262 "quadIn", "quadOut", "quadInOut", \
263 "cubicIn", "cubicOut", "cubicInOut", \
264 "quartIn", "quartOut", "quartInOut", \
265 "quintIn", "quintOut", "quintInOut", \
266 "circleIn", "circleOut", "circleInOut", \
267 "exponentialIn", "exponentialOut", "exponentialInOut", \
268 "sineIn", "sineOut", "sineInOut", \
269 "elasticIn", "elasticOut", "elasticInOut", \
270 "backIn", "backOut", "backInOut", \
271 "bounceIn", "bounceOut", "bounceInOut", \
272 "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
274 static void character_init(character_t*c)
276 memset(c, 0, sizeof(character_t));
279 static character_t* character_new()
282 c = (character_t*)malloc(sizeof(character_t));
287 static void instance_init(instance_t*i)
289 memset(i, 0, sizeof(instance_t));
290 i->history = history_new();
293 static void instance_free(instance_t* i)
295 history_free(i->history);
299 static instance_t* instance_new()
302 c = (instance_t*)malloc(sizeof(instance_t));
307 static void free_instance(void* i)
309 instance_free((instance_t*)i);
312 static void free_font(void* f)
314 swf_FontFree((SWFFONT*)f);
317 static void gradient_free(GRADIENT* grad)
324 static void free_gradient(void* grad)
326 gradient_free((GRADIENT*) grad);
329 static void outline_free(outline_t* o)
331 free(o->shape->data);
336 static void free_outline(void* o)
338 outline_free((outline_t*)o);
341 static void freeDictionaries()
343 dictionary_free_all(&instances, free_instance);
344 dictionary_free_all(&characters, free);
345 dictionary_free_all(&images, free);
346 dictionary_free_all(&textures, free);
347 dictionary_free_all(&outlines, free_outline);
348 dictionary_free_all(&gradients, free_gradient);
349 dictionary_free_all(&filters, free);
350 dictionary_free_all(&fonts, free_font);
351 dictionary_free_all(&sounds, free);
352 dictionary_free_all(&interpolations, free);
356 static void freeFontDictionary()
358 dictionary_free_all(&fonts, free_font);
361 static void incrementid()
365 syntaxerror("Out of character ids.");
370 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
372 if(dictionary_lookup(&characters, name))
373 syntaxerror("character %s defined twice", name);
374 character_t* c = character_new();
376 c->definingTag = ctag;
379 dictionary_put2(&characters, name, c);
382 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
384 swf_SetString(tag, name);
385 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
388 swf_SetString(tag, name);
391 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
393 if(dictionary_lookup(&images, name))
394 syntaxerror("image %s defined twice", name);
396 character_t* c = character_new();
397 c->definingTag = ctag;
400 dictionary_put2(&images, name, c);
402 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
404 if(dictionary_lookup(&instances, name))
405 syntaxerror("object %s defined twice", name);
406 instance_t* i = instance_new();
409 //swf_GetMatrix(0, &i->matrix);
410 dictionary_put2(&instances, name, i);
414 static void parameters_clear(parameters_t*p)
417 p->scalex = 1.0; p->scaley = 1.0;
420 p->pivot.x = 0; p->pivot.y = 0;
425 swf_GetCXForm(0, &p->cxform, 1);
428 static void makeMatrix(MATRIX*m, parameters_t*p)
437 sx = p->scalex*cos(p->rotate/360*2*M_PI);
438 r1 = -p->scalex*sin(p->rotate/360*2*M_PI)+sx*p->shear;
439 r0 = p->scaley*sin(p->rotate/360*2*M_PI);
440 sy = p->scaley*cos(p->rotate/360*2*M_PI)+r0*p->shear;
442 m->sx = (int)(sx*65536+0.5);
443 m->r1 = (int)(r1*65536+0.5);
444 m->r0 = (int)(r0*65536+0.5);
445 m->sy = (int)(sy*65536+0.5);
449 h = swf_TurnPoint(p->pin, m);
454 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
459 r = swf_TurnRect(rect, &m);
460 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
461 currentrect.xmax == 0 && currentrect.ymax == 0)
464 swf_ExpandRect2(¤trect, &r);
470 interpolation_t* new;
471 new = (interpolation_t*)malloc(sizeof(interpolation_t));
472 new->function = IF_LINEAR;
473 dictionary_put2(&interpolations, "linear", new);
475 new = (interpolation_t*)malloc(sizeof(interpolation_t));
476 new->function = IF_QUAD_IN;
478 dictionary_put2(&interpolations, "quadIn", new);
479 new = (interpolation_t*)malloc(sizeof(interpolation_t));
480 new->function = IF_QUAD_OUT;
482 dictionary_put2(&interpolations, "quadOut", new);
483 new = (interpolation_t*)malloc(sizeof(interpolation_t));
484 new->function = IF_QUAD_IN_OUT;
486 dictionary_put2(&interpolations, "quadInOut", new);
488 new = (interpolation_t*)malloc(sizeof(interpolation_t));
489 new->function = IF_CUBIC_IN;
491 dictionary_put2(&interpolations, "cubicIn", new);
492 new = (interpolation_t*)malloc(sizeof(interpolation_t));
493 new->function = IF_CUBIC_OUT;
495 dictionary_put2(&interpolations, "cubicOut", new);
496 new = (interpolation_t*)malloc(sizeof(interpolation_t));
497 new->function = IF_CUBIC_IN_OUT;
499 dictionary_put2(&interpolations, "cubicInOut", new);
501 new = (interpolation_t*)malloc(sizeof(interpolation_t));
502 new->function = IF_QUART_IN;
504 dictionary_put2(&interpolations, "quartIn", new);
505 new = (interpolation_t*)malloc(sizeof(interpolation_t));
506 new->function = IF_QUART_OUT;
508 dictionary_put2(&interpolations, "quartOut", new);
509 new = (interpolation_t*)malloc(sizeof(interpolation_t));
510 new->function = IF_QUART_IN_OUT;
512 dictionary_put2(&interpolations, "quartInOut", new);
514 new = (interpolation_t*)malloc(sizeof(interpolation_t));
515 new->function = IF_QUINT_IN;
517 dictionary_put2(&interpolations, "quintIn", new);
518 new = (interpolation_t*)malloc(sizeof(interpolation_t));
519 new->function = IF_QUINT_OUT;
521 dictionary_put2(&interpolations, "quintOut", new);
522 new = (interpolation_t*)malloc(sizeof(interpolation_t));
523 new->function = IF_QUINT_IN_OUT;
525 dictionary_put2(&interpolations, "quintInOut", new);
527 new = (interpolation_t*)malloc(sizeof(interpolation_t));
528 new->function = IF_CIRCLE_IN;
529 dictionary_put2(&interpolations, "circleIn", new);
530 new = (interpolation_t*)malloc(sizeof(interpolation_t));
531 new->function = IF_CIRCLE_OUT;
532 dictionary_put2(&interpolations, "circleOut", new);
533 new = (interpolation_t*)malloc(sizeof(interpolation_t));
534 new->function = IF_CIRCLE_IN_OUT;
535 dictionary_put2(&interpolations, "circleInOut", new);
537 new = (interpolation_t*)malloc(sizeof(interpolation_t));
538 new->function = IF_EXPONENTIAL_IN;
539 dictionary_put2(&interpolations, "exponentialIn", new);
540 new = (interpolation_t*)malloc(sizeof(interpolation_t));
541 new->function = IF_EXPONENTIAL_OUT;
542 dictionary_put2(&interpolations, "exponentialOut", new);
543 new = (interpolation_t*)malloc(sizeof(interpolation_t));
544 new->function = IF_EXPONENTIAL_IN_OUT;
545 dictionary_put2(&interpolations, "exponentialInOut", new);
547 new = (interpolation_t*)malloc(sizeof(interpolation_t));
548 new->function = IF_SINE_IN;
549 dictionary_put2(&interpolations, "sineIn", new);
550 new = (interpolation_t*)malloc(sizeof(interpolation_t));
551 new->function = IF_SINE_OUT;
552 dictionary_put2(&interpolations, "sineOut", new);
553 new = (interpolation_t*)malloc(sizeof(interpolation_t));
554 new->function = IF_SINE_IN_OUT;
555 dictionary_put2(&interpolations, "sineInOut", new);
558 memset(&c, 0, sizeof(RGBA));
559 gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
560 noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
561 noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
562 noGradient->gradient.num = 2;
563 noGradient->gradient.rgba[0] = c;
564 noGradient->gradient.ratios[0] = 0;
565 noGradient->gradient.rgba[1] = c;
566 noGradient->gradient.ratios[1] = 255;
567 noGradient->radial = 0;
568 noGradient->rotate = 0;
569 dictionary_put2(&gradients, "no_gradient", noGradient);
572 // put a no_filters entry in the filters dictionary to provoce a message when a user tries
573 // to define a no_filters filter. The real filter=no_filters case is handled in parseFilters.
574 FILTER* dummy = (FILTER*)malloc(sizeof(FILTER));
575 dictionary_put2(&filters, "no_filters", dummy);
576 noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
578 dictionary_put2(&filters, "no_blur", noBlur);
579 noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
581 noBevel->composite = 1;
582 dictionary_put2(&filters, "no_bevel", noBevel);
583 noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
584 noDropshadow->passes = 1;
585 noDropshadow->composite = 1;
586 dictionary_put2(&filters, "no_dropshadow", noDropshadow);
587 noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
588 noGradientGlow->passes = 1;
589 noGradientGlow->composite = 1;
590 noGradientGlow->gradient = &noGradient->gradient;
591 dictionary_put2(&filters, "no_gradientglow", noGradientGlow);
594 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
597 syntaxerror(".swf blocks can't be nested");
598 if(stackpos==sizeof(stack)/sizeof(stack[0]))
599 syntaxerror("too many levels of recursion");
601 SWF*swf = (SWF*)malloc(sizeof(SWF));
603 memset(swf, 0, sizeof(swf));
604 swf->fileVersion = version;
606 swf->frameRate = fps;
607 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
608 swf->compressed = compress;
609 swf_SetRGB(tag,&background);
611 dictionary_init(&characters);
612 dictionary_init(&images);
613 dictionary_init(&textures);
614 dictionary_init(&outlines);
615 dictionary_init(&gradients);
616 dictionary_init(&filters);
617 dictionary_init(&instances);
618 dictionary_init(&sounds);
619 dictionary_init(&interpolations);
621 cleanUp = &freeDictionaries;
623 memset(&stack[stackpos], 0, sizeof(stack[0]));
624 stack[stackpos].type = 0;
625 stack[stackpos].filename = strdup(name);
626 stack[stackpos].swf = swf;
627 stack[stackpos].oldframe = -1;
631 memset(¤trect, 0, sizeof(currentrect));
634 memset(idmap, 0, sizeof(idmap));
638 void s_sprite(char*name, SRECT*scalegrid)
640 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
641 swf_SetU16(tag, id); //id
642 swf_SetU16(tag, 0); //frames
644 memset(&stack[stackpos], 0, sizeof(stack[0]));
645 stack[stackpos].type = 1;
646 stack[stackpos].oldframe = currentframe;
647 stack[stackpos].olddepth = currentdepth;
648 stack[stackpos].oldrect = currentrect;
649 stack[stackpos].oldinstances = instances;
650 stack[stackpos].tag = tag;
651 stack[stackpos].id = id;
652 stack[stackpos].name = strdup(name);
654 stack[stackpos].scalegrid = *scalegrid;
656 memset(&stack[stackpos].scalegrid, 0, sizeof(SRECT));
659 /* FIXME: those four fields should be bundled together */
660 dictionary_init(&instances);
663 memset(¤trect, 0, sizeof(currentrect));
669 typedef struct _buttonrecord
677 typedef struct _button
681 buttonrecord_t records[4];
684 static button_t mybutton;
686 void s_button(char*name)
688 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
689 swf_SetU16(tag, id); //id
690 swf_ButtonSetFlags(tag, 0); //menu=no
692 memset(&mybutton, 0, sizeof(mybutton));
694 memset(&stack[stackpos], 0, sizeof(stack[0]));
695 stack[stackpos].type = 3;
696 stack[stackpos].tag = tag;
697 stack[stackpos].id = id;
698 stack[stackpos].name = strdup(name);
699 stack[stackpos].oldrect = currentrect;
700 memset(¤trect, 0, sizeof(currentrect));
705 void s_buttonput(char*character, char*as, parameters_t p)
707 character_t* c = dictionary_lookup(&characters, character);
712 if(!stackpos || (stack[stackpos-1].type != 3)) {
713 syntaxerror(".show may only appear in .button");
716 syntaxerror("character %s not known (in .shape %s)", character, character);
718 if(mybutton.endofshapes) {
719 syntaxerror("a .do may not precede a .show", character, character);
722 m = s_instancepos(c->size, &p);
730 if(*s==',' || *s==0) {
731 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
732 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
733 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
734 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
735 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
736 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
743 static void setbuttonrecords(TAG*tag)
745 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
746 if(!mybutton.endofshapes) {
749 if(!mybutton.records[3].set) {
750 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
754 if(mybutton.records[t].set) {
755 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
758 swf_SetU8(tag,0); // end of button records
759 mybutton.endofshapes = 1;
763 void s_buttonaction(int flags, char*action)
769 setbuttonrecords(stack[stackpos-1].tag);
771 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
773 syntaxerror("Couldn't compile ActionScript");
776 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
777 swf_ActionSet(stack[stackpos-1].tag, a);
778 mybutton.nr_actions++;
783 static void setactionend(TAG*tag)
785 if(!mybutton.nr_actions) {
786 /* no actions means we didn't have an actionoffset,
787 which means we can't signal the end of the
788 buttonaction records, so, *sigh*, we have
789 to insert a dummy record */
790 swf_SetU16(tag, 0); //offset
791 swf_SetU16(tag, 0); //condition
792 swf_SetU8(tag, 0); //action
796 static void s_endButton()
799 setbuttonrecords(stack[stackpos-1].tag);
800 setactionend(stack[stackpos-1].tag);
803 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
807 tag = stack[stackpos].tag;
808 currentrect = stack[stackpos].oldrect;
810 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
811 free(stack[stackpos].name);
814 TAG* removeFromTo(TAG*from, TAG*to)
816 TAG*save = from->prev;
818 TAG*next = from->next;
819 if(swf_isAllowedSpriteTag(from))
820 swf_DeleteTag(0, from);
827 static int parametersChange(history_t* history, int frame)
831 willChange = willChange || history_change(history, frame, "x");
832 willChange = willChange || history_change(history, frame, "y");
833 willChange = willChange || history_change(history, frame, "scalex");
834 willChange = willChange || history_change(history, frame, "scaley");
835 willChange = willChange || history_change(history, frame, "cxform.r0");
836 willChange = willChange || history_change(history, frame, "cxform.g0");
837 willChange = willChange || history_change(history, frame, "cxform.b0");
838 willChange = willChange || history_change(history, frame, "cxform.a0");
839 willChange = willChange || history_change(history, frame, "cxform.r1");
840 willChange = willChange || history_change(history, frame, "cxform.g1");
841 willChange = willChange || history_change(history, frame, "cxform.b1");
842 willChange = willChange || history_change(history, frame, "cxform.a1");
843 willChange = willChange || history_change(history, frame, "rotate");
844 willChange = willChange || history_change(history, frame, "shear");
845 willChange = willChange || history_change(history, frame, "pivot.x");
846 willChange = willChange || history_change(history, frame, "pivot.y");
847 willChange = willChange || history_change(history, frame, "pin.x");
848 willChange = willChange || history_change(history, frame, "pin.y");
849 willChange = willChange || history_change(history, frame, "blendmode");
850 willChange = willChange || history_changeFilter(history, frame);
855 static void free_filterlist(FILTERLIST* f_list)
858 for (i = 0; i < f_list->num; i++)
860 if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
861 gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
862 free(f_list->filter[i]);
867 static void readParameters(history_t* history, parameters_t* p, int frame)
869 p->x = history_value(history, frame, "x");
870 p->y = history_value(history, frame, "y");
871 p->scalex = history_value(history, frame, "scalex");
872 p->scaley = history_value(history, frame, "scaley");
873 p->cxform.r0 = history_value(history, frame, "cxform.r0");
874 p->cxform.g0 = history_value(history, frame, "cxform.g0");
875 p->cxform.b0 = history_value(history, frame, "cxform.b0");
876 p->cxform.a0 = history_value(history, frame, "cxform.a0");
877 p->cxform.r1 = history_value(history, frame, "cxform.r1");
878 p->cxform.g1 = history_value(history, frame, "cxform.g1");
879 p->cxform.b1 = history_value(history, frame, "cxform.b1");
880 p->cxform.a1 = history_value(history, frame, "cxform.a1");
881 p->rotate = history_rotateValue(history, frame);
882 p->shear = history_value(history, frame, "shear");
883 p->pivot.x = history_value(history, frame, "pivot.x");
884 p->pivot.y = history_value(history, frame, "pivot.y");
885 p->pin.x = history_value(history, frame, "pin.x");
886 p->pin.y = history_value(history, frame, "pin.y");
887 p->blendmode = history_value(history, frame, "blendmode");
888 p->filters = history_filterValue(history, frame);
891 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
895 swf_GetPlaceObject(NULL, &po);
899 po.cxform = p->cxform;
905 po.blendmode = p->blendmode;
908 po.filters = p->filters;
909 swf_SetPlaceObject(tag, &po);
912 static void writeInstance(instance_t* i)
916 int frame = i->history->firstFrame;
917 TAG* tag = i->history->firstTag;
918 history_processFlags(i->history);
919 while (frame < currentframe)
922 while (tag->id != ST_SHOWFRAME)
924 if (parametersChange(i->history, frame))
926 readParameters(i->history, &p, frame);
927 m = s_instancepos(i->character->size, &p);
929 if(p.blendmode || p.filters)
930 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
932 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
933 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
935 free_filterlist(p.filters);
942 void dumpSWF(SWF*swf)
944 TAG* tag = swf->firstTag;
945 printf("vvvvvvvvvvvvvvvvvvvvv\n");
947 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
950 printf("^^^^^^^^^^^^^^^^^^^^^\n");
953 static void s_endSprite()
955 SRECT r = currentrect;
959 stringarray_t* index =dictionary_index(&instances);
961 for (num = 0; num < dictionary_count(&instances); num++)
963 char* name = stringarray_at(index, num);
966 i = dictionary_lookup(&instances, name);
971 if(stack[stackpos].cut)
972 tag = removeFromTo(stack[stackpos].cut, tag);
974 // the writeInstance loop above may have inserted tags after what used yo 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 dictionary_free_all(&instances, 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()
1015 stringarray_t* index = dictionary_index(&instances);
1017 for (num = 0; num < dictionary_count(&instances); num++)
1019 char* name = stringarray_at(index, num);
1022 i = dictionary_lookup(&instances, name);
1027 if(stack[stackpos].cut)
1028 tag = removeFromTo(stack[stackpos].cut, tag);
1032 swf = stack[stackpos].swf;
1033 filename = stack[stackpos].filename;
1035 // the writeInstance loop above may have inserted tags after what used yo be the current tag,
1036 // so let's make sure 'tag' point to the current tag again.
1040 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1041 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
1042 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1044 tag = swf_InsertTag(tag, ST_END);
1046 swf_OptimizeTagOrder(swf);
1052 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1053 swf->movieSize = currentrect; /* "autocrop" */
1056 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1057 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1058 swf->movieSize.ymax += 20;
1059 warning("Empty bounding box for movie");
1062 if(do_cgi || !strcmp(filename, "-"))
1063 fi = fileno(stdout);
1065 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1067 syntaxerror("couldn't create output file %s", filename);
1070 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1072 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1086 if(stack[stackpos-1].type == 0)
1087 syntaxerror("End of file encountered in .flash block");
1088 if(stack[stackpos-1].type == 1)
1089 syntaxerror("End of file encountered in .sprite block");
1090 if(stack[stackpos-1].type == 2)
1091 syntaxerror("End of file encountered in .clip block");
1097 return currentframe+1;
1100 void s_frame(int nr, int cut, char*name, char anchor)
1106 syntaxerror("Illegal frame number");
1107 nr--; // internally, frame 1 is frame 0
1109 for(t=currentframe;t<nr;t++) {
1110 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1111 if(t==nr-1 && name && *name) {
1112 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1113 swf_SetString(tag, name);
1115 swf_SetU8(tag, 1); //make this an anchor
1118 if(nr == 0 && currentframe == 0 && name && *name) {
1119 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1120 swf_SetString(tag, name);
1122 swf_SetU8(tag, 1); //make this an anchor
1127 syntaxerror("Can't cut, frame empty");
1129 stack[stackpos].cut = tag;
1135 int parseColor2(char*str, RGBA*color);
1137 int addFillStyle(SHAPE*s, SRECT*r, char*name)
1141 gradient_t*gradient;
1143 if(name[0] == '#') {
1144 parseColor2(name, &color);
1145 return swf_ShapeAddSolidFillStyle(s, &color);
1146 } else if ((texture = dictionary_lookup(&textures, name))) {
1147 return swf_ShapeAddFillStyle2(s, &texture->fs);
1148 } else if((image = dictionary_lookup(&images, name))) {
1150 swf_GetMatrix(0, &m);
1151 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1152 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1155 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1156 } else if ((gradient = dictionary_lookup(&gradients, name))) {
1160 swf_GetMatrix(0, &rot);
1161 ccos = cos(-gradient->rotate*2*M_PI/360);
1162 csin = sin(-gradient->rotate*2*M_PI/360);
1163 rot.sx = ccos*65536;
1164 rot.r1 = -csin*65536;
1165 rot.r0 = csin*65536;
1166 rot.sy = ccos*65536;
1167 r2 = swf_TurnRect(*r, &rot);
1168 swf_GetMatrix(0, &m);
1169 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1170 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1171 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1172 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1173 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1174 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1175 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1176 } else if (parseColor2(name, &color)) {
1177 return swf_ShapeAddSolidFillStyle(s, &color);
1179 syntaxerror("not a color/fillstyle: %s", name);
1184 RGBA black={r:0,g:0,b:0,a:0};
1185 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
1194 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1197 linewidth = linewidth>=20?linewidth-20:0;
1198 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1201 fs1 = addFillStyle(s, &r2, texture);
1204 r.xmin = r2.xmin-linewidth/2;
1205 r.ymin = r2.ymin-linewidth/2;
1206 r.xmax = r2.xmax+linewidth/2;
1207 r.ymax = r2.ymax+linewidth/2;
1208 swf_SetRect(tag,&r);
1209 swf_SetShapeHeader(tag,s);
1210 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1211 swf_ShapeSetLine(tag,s,width,0);
1212 swf_ShapeSetLine(tag,s,0,height);
1213 swf_ShapeSetLine(tag,s,-width,0);
1214 swf_ShapeSetLine(tag,s,0,-height);
1215 swf_ShapeSetEnd(tag);
1218 s_addcharacter(name, id, tag, r);
1222 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
1228 outline = dictionary_lookup(&outlines, outlinename);
1230 syntaxerror("outline %s not defined", outlinename);
1234 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1237 linewidth = linewidth>=20?linewidth-20:0;
1238 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1241 fs1 = addFillStyle(s, &r2, texture);
1244 rect.xmin = r2.xmin-linewidth/2;
1245 rect.ymin = r2.ymin-linewidth/2;
1246 rect.xmax = r2.xmax+linewidth/2;
1247 rect.ymax = r2.ymax+linewidth/2;
1249 swf_SetRect(tag,&rect);
1250 swf_SetShapeStyles(tag, s);
1251 swf_ShapeCountBits(s,0,0);
1252 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1253 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1254 swf_SetShapeBits(tag, s);
1255 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1258 s_addcharacter(name, id, tag, rect);
1262 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
1267 r2.xmin = r2.ymin = 0;
1271 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1274 linewidth = linewidth>=20?linewidth-20:0;
1275 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1278 fs1 = addFillStyle(s, &r2, texture);
1280 rect.xmin = r2.xmin-linewidth/2;
1281 rect.ymin = r2.ymin-linewidth/2;
1282 rect.xmax = r2.xmax+linewidth/2;
1283 rect.ymax = r2.ymax+linewidth/2;
1285 swf_SetRect(tag,&rect);
1286 swf_SetShapeHeader(tag,s);
1287 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1288 swf_ShapeSetCircle(tag, s, r,r,r,r);
1289 swf_ShapeSetEnd(tag);
1292 s_addcharacter(name, id, tag, rect);
1296 void s_textshape(char*name, char*fontname, float size, char*_text)
1299 U8*text = (U8*)_text;
1303 font = dictionary_lookup(&fonts, fontname);
1305 syntaxerror("font \"%s\" not known!", fontname);
1307 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1308 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1309 s_box(name, 0, 0, black, 20, 0);
1312 g = font->ascii2glyph[text[0]];
1314 outline = malloc(sizeof(outline_t));
1315 memset(outline, 0, sizeof(outline_t));
1316 outline->shape = font->glyph[g].shape;
1317 outline->bbox = font->layout->bounds[g];
1321 swf_Shape11DrawerInit(&draw, 0);
1322 swf_DrawText(&draw, font, (int)(size*100), _text);
1324 outline->shape = swf_ShapeDrawerToShape(&draw);
1325 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1326 draw.dealloc(&draw);
1329 if(dictionary_lookup(&outlines, name))
1330 syntaxerror("outline %s defined twice", name);
1331 dictionary_put2(&outlines, name, outline);
1334 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
1339 font = dictionary_lookup(&fonts, fontname);
1341 syntaxerror("font \"%s\" not known!", fontname);
1343 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1344 swf_SetU16(tag, id);
1345 if(!font->numchars) {
1346 s_box(name, 0, 0, black, 20, 0);
1349 r = swf_SetDefineText(tag, font, &color, text, size);
1351 if(stack[0].swf->fileVersion >= 8) {
1352 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1353 swf_SetU16(tag, id);
1354 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1355 swf_SetU32(tag, 0);//thickness
1356 swf_SetU32(tag, 0);//sharpness
1357 swf_SetU8(tag, 0);//reserved
1360 s_addcharacter(name, id, tag, r);
1364 void s_quicktime(char*name, char*url)
1369 memset(&r, 0, sizeof(r));
1371 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1372 swf_SetU16(tag, id);
1373 swf_SetString(tag, url);
1375 s_addcharacter(name, id, tag, r);
1379 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags, int align)
1382 EditTextLayout layout;
1385 if(fontname && *fontname) {
1386 flags |= ET_USEOUTLINES;
1387 font = dictionary_lookup(&fonts, fontname);
1389 syntaxerror("font \"%s\" not known!", fontname);
1391 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1392 swf_SetU16(tag, id);
1393 layout.align = align;
1394 layout.leftmargin = 0;
1395 layout.rightmargin = 0;
1403 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1405 s_addcharacter(name, id, tag, r);
1409 /* type: either "jpeg" or "png"
1411 void s_image(char*name, char*type, char*filename, int quality)
1413 /* an image is actually two folded: 1st bitmap, 2nd character.
1414 Both of them can be used separately */
1416 /* step 1: the bitmap */
1420 if(!strcmp(type,"jpeg")) {
1421 #ifndef HAVE_JPEGLIB
1422 warning("no jpeg support compiled in");
1423 s_box(name, 0, 0, black, 20, 0);
1426 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1427 swf_SetU16(tag, imageID);
1429 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1430 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1433 swf_GetJPEGSize(filename, &width, &height);
1440 s_addimage(name, id, tag, r);
1443 } else if(!strcmp(type,"png")) {
1445 swf_SetU16(tag, imageID);
1447 getPNG(filename, &width, &height, (unsigned char**)&data);
1450 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1453 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1454 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1455 swf_SetU16(tag, imageID);
1456 swf_SetLosslessImage(tag, data, width, height);
1463 s_addimage(name, id, tag, r);
1466 warning("image type \"%s\" not supported yet!", type);
1467 s_box(name, 0, 0, black, 20, 0);
1471 /* step 2: the character */
1472 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1473 swf_SetU16(tag, id);
1474 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1476 s_addcharacter(name, id, tag, r);
1480 void s_getBitmapSize(char*name, int*width, int*height)
1482 character_t* image = dictionary_lookup(&images, name);
1483 gradient_t* gradient = dictionary_lookup(&gradients,name);
1485 *width = image->size.xmax;
1486 *height = image->size.ymax;
1490 /* internal SWF gradient size */
1491 if(gradient->radial) {
1500 syntaxerror("No such bitmap/gradient: %s", name);
1503 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1505 if(dictionary_lookup(&textures, name))
1506 syntaxerror("texture %s defined twice", name);
1507 gradient_t* gradient = dictionary_lookup(&gradients, object);
1508 character_t* bitmap = dictionary_lookup(&images, object);
1509 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1511 FILLSTYLE*fs = &texture->fs;
1513 memset(&p, 0, sizeof(parameters_t));
1516 fs->type = FILL_TILED;
1517 fs->id_bitmap = bitmap->id;
1518 } else if(gradient) {
1519 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1520 fs->gradient = gradient->gradient;
1522 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1523 makeMatrix(&fs->m, &p);
1524 if(gradient && !gradient->radial) {
1531 p2 = swf_TurnPoint(p1, &m);
1540 dictionary_put2(&textures, name, texture);
1543 void s_font(char*name, char*filename)
1546 font = dictionary_lookup(&fonts, name);
1549 /* fix the layout. Only needed for old fonts */
1551 for(t=0;t<font->numchars;t++) {
1552 font->glyph[t].advance = 0;
1555 swf_FontCreateLayout(font);
1558 swf_FontReduce_swfc(font);
1559 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1560 swf_FontSetDefine2(tag, font);
1562 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1564 swf_SetU16(tag, id);
1565 swf_SetString(tag, name);
1573 typedef struct _sound_t
1579 void s_sound(char*name, char*filename)
1581 struct WAV wav, wav2;
1585 unsigned numsamples = 1;
1586 unsigned blocksize = 1152;
1589 if(dictionary_lookup(&sounds, name))
1590 syntaxerror("sound %s defined twice", name);
1592 if(wav_read(&wav, filename))
1595 wav_convert2mono(&wav, &wav2, 44100);
1596 samples = (U16*)wav2.data;
1597 numsamples = wav2.size/2;
1599 #ifdef WORDS_BIGENDIAN
1601 for(t=0;t<numsamples;t++)
1602 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1606 if(mp3_read(&mp3, filename))
1608 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1614 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1619 if(numsamples%blocksize != 0)
1621 // apply padding, so that block is a multiple of blocksize
1622 int numblocks = (numsamples+blocksize-1)/blocksize;
1625 numsamples2 = numblocks * blocksize;
1626 samples2 = malloc(sizeof(U16)*numsamples2);
1627 memcpy(samples2, samples, numsamples*sizeof(U16));
1628 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1629 numsamples = numsamples2;
1634 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1635 swf_SetU16(tag, id); //id
1638 swf_SetSoundDefineMP3(
1639 tag, mp3.data, mp3.size,
1646 swf_SetSoundDefine(tag, samples, numsamples);
1649 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1650 swf_SetU16(tag, id);
1651 swf_SetString(tag, name);
1652 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1654 swf_SetU16(tag, id);
1655 swf_SetString(tag, name);
1658 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1662 dictionary_put2(&sounds, name, sound);
1670 static char* gradient_getToken(const char**p)
1674 while(**p && strchr(" \t\n\r", **p)) {
1678 while(**p && !strchr(" \t\n\r", **p)) {
1681 result = malloc((*p)-start+1);
1682 memcpy(result,start,(*p)-start+1);
1683 result[(*p)-start] = 0;
1687 float parsePercent(char*str);
1688 RGBA parseColor(char*str);
1690 GRADIENT parseGradient(const char*str)
1694 const char* p = str;
1695 memset(&gradient, 0, sizeof(GRADIENT));
1696 gradient.ratios = rfx_calloc(16*sizeof(U8));
1697 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1701 char*posstr,*colorstr;
1704 posstr = gradient_getToken(&p);
1710 pos = (int)(parsePercent(posstr)*255.0);
1715 rfx_free(gradient.ratios);
1716 rfx_free(gradient.rgba);
1718 syntaxerror("Error in shape data: Color expected after %s", posstr);
1720 colorstr = gradient_getToken(&p);
1721 color = parseColor(colorstr);
1722 if(gradient.num == 16)
1724 warning("gradient record too big- max size is 16, rest ignored");
1727 gradient.ratios[gradient.num] = pos;
1728 gradient.rgba[gradient.num] = color;
1737 FILTERLIST* parseFilters(char* list)
1739 if (!strcmp(list, "no_filters"))
1742 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1744 char* f_start = list;
1748 f_end = strchr(f_start, ',');
1751 f = dictionary_lookup(&filters, f_start);
1755 syntaxerror("unknown filter %s", f_start);
1757 if (f_list->num == 8)
1759 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1762 f_list->filter[f_list->num] = f;
1767 f_start = f_end + 1;
1775 void s_gradient(char*name, const char*text, int radial, int rotate)
1777 gradient_t* gradient;
1778 gradient = malloc(sizeof(gradient_t));
1779 memset(gradient, 0, sizeof(gradient_t));
1780 gradient->gradient = parseGradient(text);
1781 gradient->radial = radial;
1782 gradient->rotate = rotate;
1784 dictionary_put2(&gradients, name, gradient);
1787 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1788 float angle, float distance, float strength, char innershadow,
1789 char knockout, char composite, char ontop, int passes)
1791 if(dictionary_lookup(&filters, name))
1792 syntaxerror("filter %s defined twice", name);
1794 gradient_t* g = dictionary_lookup(&gradients, gradient);
1796 syntaxerror("unknown gradient %s", gradient);
1800 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1801 filter->type = FILTERTYPE_GRADIENTGLOW;
1802 filter->gradient = &g->gradient;
1803 filter->blurx = blurx;
1804 filter->blury = blury;
1805 filter->strength = strength;
1806 filter->angle = angle;
1807 filter->distance = distance;
1808 filter->innershadow = innershadow;
1809 filter->knockout = knockout;
1810 filter->composite = composite;
1811 filter->ontop = ontop;
1812 filter->passes = passes;
1814 dictionary_put2(&filters, name, filter);
1817 void s_dropshadow(char*name, RGBA color, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, int passes)
1819 if(dictionary_lookup(&filters, name))
1820 syntaxerror("filter %s defined twice", name);
1823 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1824 filter->type = FILTERTYPE_DROPSHADOW;
1825 filter->color= color;
1826 filter->blurx = blurx;
1827 filter->blury = blury;
1828 filter->strength = strength;
1829 filter->angle = angle;
1830 filter->distance = distance;
1831 filter->innershadow = innershadow;
1832 filter->knockout = knockout;
1833 filter->composite = composite;
1834 filter->passes = passes;
1836 dictionary_put2(&filters, name, filter);
1839 void s_bevel(char*name, RGBA shadow, RGBA highlight, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, char ontop, int passes)
1841 if(dictionary_lookup(&filters, name))
1842 syntaxerror("filter %s defined twice", name);
1845 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1846 filter->type = FILTERTYPE_BEVEL;
1847 filter->shadow = shadow;
1848 filter->highlight = highlight;
1849 filter->blurx = blurx;
1850 filter->blury = blury;
1851 filter->strength = strength;
1852 filter->angle = angle;
1853 filter->distance = distance;
1854 filter->innershadow = innershadow;
1855 filter->knockout = knockout;
1856 filter->composite = composite;
1857 filter->ontop = ontop;
1858 filter->passes = passes;
1860 dictionary_put2(&filters, name, filter);
1863 void s_blur(char*name, double blurx, double blury, int passes)
1865 if(dictionary_lookup(&filters, name))
1866 syntaxerror("filter %s defined twice", name);
1868 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1869 filter->type = FILTERTYPE_BLUR;
1870 filter->blurx = blurx;
1871 filter->blury = blury;
1872 filter->passes = passes;
1874 dictionary_put2(&filters, name, filter);
1877 void s_action(const char*text)
1880 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1884 syntaxerror("Couldn't compile ActionScript");
1887 tag = swf_InsertTag(tag, ST_DOACTION);
1889 swf_ActionSet(tag, a);
1894 void s_initaction(const char*character, const char*text)
1898 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1902 syntaxerror("Couldn't compile ActionScript");
1905 c = (character_t*)dictionary_lookup(&characters, character);
1907 tag = swf_InsertTag(tag, ST_DOINITACTION);
1908 swf_SetU16(tag, c->id);
1909 swf_ActionSet(tag, a);
1914 int s_swf3action(char*name, char*action)
1917 instance_t* object = 0;
1919 object = (instance_t*)dictionary_lookup(&instances, name);
1920 if(!object && name && *name) {
1921 /* we have a name, but couldn't find it. Abort. */
1924 a = action_SetTarget(0, name);
1925 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1926 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1927 else if(!strcmp(action, "stop")) a = action_Stop(a);
1928 else if(!strcmp(action, "play")) a = action_Play(a);
1929 a = action_SetTarget(a, "");
1932 tag = swf_InsertTag(tag, ST_DOACTION);
1933 swf_ActionSet(tag, a);
1938 void s_outline(char*name, char*format, char*source)
1940 if(dictionary_lookup(&outlines, name))
1941 syntaxerror("outline %s defined twice", name);
1950 //swf_Shape10DrawerInit(&draw, 0);
1951 swf_Shape11DrawerInit(&draw, 0);
1953 draw_string(&draw, source);
1955 shape = swf_ShapeDrawerToShape(&draw);
1956 bounds = swf_ShapeDrawerGetBBox(&draw);
1957 draw.dealloc(&draw);
1959 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1960 outline->shape = shape;
1961 outline->bbox = bounds;
1963 dictionary_put2(&outlines, name, outline);
1966 int s_playsound(char*name, int loops, int nomultiple, int stop)
1972 sound = dictionary_lookup(&sounds, name);
1976 tag = swf_InsertTag(tag, ST_STARTSOUND);
1977 swf_SetU16(tag, sound->id); //id
1978 memset(&info, 0, sizeof(info));
1981 info.nomultiple = nomultiple;
1982 swf_SetSoundInfo(tag, &info);
1986 void s_includeswf(char*name, char*filename)
1994 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1995 f = open(filename,O_RDONLY|O_BINARY);
1997 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1998 s_box(name, 0, 0, black, 20, 0);
2001 if (swf_ReadSWF(f,&swf)<0) {
2002 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
2003 s_box(name, 0, 0, black, 20, 0);
2008 /* FIXME: The following sets the bounding Box for the character.
2009 It is wrong for two reasons:
2010 a) It may be too small (in case objects in the movie clip at the borders)
2011 b) it may be too big (because the poor movie never got autocropped)
2015 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2016 swf_SetU16(tag, id);
2017 swf_SetU16(tag, swf.frameCount);
2019 swf_Relocate(&swf, idmap);
2021 ftag = swf.firstTag;
2025 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2026 if(cutout[t] == ftag->id) {
2030 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2032 if(ftag->id == ST_END)
2037 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2038 /* We simply dump all tags right after the sprite
2039 header, relying on the fact that swf_OptimizeTagOrder() will
2040 sort things out for us later.
2041 We also rely on the fact that the imported SWF is well-formed.
2043 tag = swf_InsertTag(tag, ftag->id);
2044 swf_SetBlock(tag, ftag->data, ftag->len);
2050 syntaxerror("Included file %s contains errors", filename);
2051 tag = swf_InsertTag(tag, ST_END);
2055 s_addcharacter(name, id, tag, r);
2058 SRECT s_getCharBBox(char*name)
2060 character_t* c = dictionary_lookup(&characters, name);
2061 if(!c) syntaxerror("character '%s' unknown(2)", name);
2064 SRECT s_getInstanceBBox(char*name)
2066 instance_t * i = dictionary_lookup(&instances, name);
2068 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2070 if(!c) syntaxerror("internal error(5)");
2073 void s_getParameters(char*name, parameters_t* p)
2075 instance_t * i = dictionary_lookup(&instances, name);
2077 syntaxerror("instance '%s' unknown(10)", name);
2078 if (change_sets_all)
2079 readParameters(i->history, p, currentframe);
2084 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2086 history_begin(i->history, "x", currentframe, tag, p->x);
2087 history_begin(i->history, "y", currentframe, tag, p->y);
2088 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2089 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2090 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2091 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2092 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2093 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2094 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2095 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2096 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2097 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2098 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2099 history_begin(i->history, "shear", currentframe, tag, p->shear);
2100 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2101 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2102 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2103 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2104 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2105 history_beginFilter(i->history, currentframe, tag, p->filters);
2106 history_begin(i->history, "flags", currentframe, tag, 0);
2109 void s_startclip(char*instance, char*character, parameters_t p)
2111 character_t* c = dictionary_lookup(&characters, character);
2115 syntaxerror("character %s not known", character);
2117 i = s_addinstance(instance, c, currentdepth);
2119 m = s_instancepos(i->character->size, &p);
2121 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2122 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2123 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2125 stack[stackpos].tag = tag;
2126 stack[stackpos].type = 2;
2129 setStartparameters(i, &p, tag);
2136 swf_SetTagPos(stack[stackpos].tag, 0);
2137 swf_GetPlaceObject(stack[stackpos].tag, &p);
2138 p.clipdepth = currentdepth;
2140 swf_ClearTag(stack[stackpos].tag);
2141 swf_SetPlaceObject(stack[stackpos].tag, &p);
2145 void s_put(char*instance, char*character, parameters_t p)
2147 character_t* c = dictionary_lookup(&characters, character);
2151 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2153 i = s_addinstance(instance, c, currentdepth);
2155 m = s_instancepos(i->character->size, &p);
2157 if(p.blendmode || p.filters)
2159 if(stack[0].swf->fileVersion < 8)
2162 warning("blendmodes only supported for flash version>=8");
2164 warning("filters only supported for flash version>=8");
2166 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2169 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2170 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2171 setStartparameters(i, &p, tag);
2175 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2178 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2180 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2181 if (p.set & SF_SCALEX)
2182 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2183 if (p.set & SF_SCALEY)
2184 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2185 if (p.set & SF_CX_R)
2187 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2188 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2190 if (p.set & SF_CX_G)
2192 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2193 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2195 if (p.set & SF_CX_B)
2197 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2198 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2200 if (p.set & SF_CX_A)
2202 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2203 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2205 if (p.set & SF_ROTATE)
2206 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2207 if (p.set & SF_SHEAR)
2208 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2209 if (p.set & SF_PIVOT)
2211 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2212 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2216 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2217 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2219 if (p.set & SF_BLEND)
2220 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2221 if (p.set & SF_FILTER)
2222 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2225 void s_jump(char* instance, parameters_t p)
2227 instance_t* i = dictionary_lookup(&instances, instance);
2229 syntaxerror("instance %s not known", instance);
2230 recordChanges(i->history, p, CF_JUMP, 0);
2233 void s_change(char*instance, parameters_t p, interpolation_t* inter)
2235 instance_t* i = dictionary_lookup(&instances, instance);
2237 syntaxerror("instance %s not known", instance);
2238 recordChanges(i->history, p, CF_CHANGE, inter);
2241 void s_sweep(char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2243 instance_t* i = dictionary_lookup(&instances, instance);
2245 syntaxerror("instance %s not known", instance);
2246 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2249 void s_toggle(char* instance, U16 flagsOn, U16 flagsOff)
2251 instance_t* i = dictionary_lookup(&instances, instance);
2253 syntaxerror("instance %s not known", instance);
2254 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2257 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2260 void s_delinstance(char*instance)
2262 instance_t* i = dictionary_lookup(&instances, instance);
2264 syntaxerror("instance %s not known", instance);
2266 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2267 swf_SetU16(tag, i->depth);
2268 dictionary_del(&instances, instance);
2271 void s_schange(char*instance, parameters_t p, interpolation_t* inter)
2273 instance_t* i = dictionary_lookup(&instances, instance);
2275 syntaxerror("instance %s not known", instance);
2276 recordChanges(i->history, p, CF_SCHANGE, inter);
2282 syntaxerror(".end unexpected");
2283 switch (stack[stackpos-1].type)
2298 syntaxerror("internal error 1");
2302 // ------------------------------------------------------------------------
2304 typedef int command_func_t(map_t*args);
2306 SRECT parseBox(char*str)
2308 SRECT r = {0,0,0,0};
2309 float xmin, xmax, ymin, ymax;
2310 char*x = strchr(str, 'x');
2312 if(!strcmp(str, "autocrop")) {
2313 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2317 d1 = strchr(x+1, ':');
2319 d2 = strchr(d1+1, ':');
2321 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2325 else if(d1 && !d2) {
2326 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2332 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2337 r.xmin = (SCOORD)(xmin*20);
2338 r.ymin = (SCOORD)(ymin*20);
2339 r.xmax = (SCOORD)(xmax*20);
2340 r.ymax = (SCOORD)(ymax*20);
2343 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2346 float parseFloat(char*str)
2350 int parseInt(char*str)
2355 if(str[0]=='+' || str[0]=='-')
2359 if(str[t]<'0' || str[t]>'9')
2360 syntaxerror("Not an Integer: \"%s\"", str);
2363 static double parseRawTwip(char*str)
2367 if(str[0]=='+' || str[0]=='-') {
2372 dot = strchr(str, '.');
2376 return sign*parseInt(str);
2378 char* old = strdup(str);
2379 int l=strlen(dot+1);
2382 for(s=str;s<dot-1;s++) {
2383 if(*s<'0' || *s>'9')
2386 syntaxerror("Not a coordinate: \"%s\"", str);
2390 if(*s<'0' || *s>'9')
2393 syntaxerror("Not a coordinate: \"%s\"", str);
2396 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2397 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2400 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2404 return sign*(atoi(str));
2406 return sign*(atoi(str)+0.1*atoi(dot));
2408 return sign*(atoi(str)+0.01*atoi(dot));
2413 static dictionary_t defines;
2414 static int defines_initialized = 0;
2415 static mem_t define_values;
2417 static double parseNameOrTwip(char*s)
2421 if(defines_initialized) {
2422 l = (int)dictionary_lookup(&defines, s);
2425 return *(int*)&define_values.buffer[l-1];
2427 return parseRawTwip(s);
2431 /* automatically generated by yiyiyacc, http://www.quiss.org/yiyiyacc/ */
2432 static double parseExpression(char*s)
2435 memset(chr2index, -1, sizeof(chr2index));
2442 chr2index['\0'] = 7;
2450 int left[10]={11,8,8,8,8,9,9,9,10,10}; //production left side
2451 int plen[10]={1,3,2,3,1,3,3,1,1,3}; //production size
2452 int table[18][12] = {
2453 {0, 4, 0, 0, 5, 6, 0, 0, 1, 2, 3, 0},
2454 {7, 8, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0},
2455 {-4, -4, 9, 10, 0, 0, -4, -4, 0, 0, 0, 0},
2456 {-7, -7, -7, -7, 0, 0, -7, -7, 0, 0, 0, 0},
2457 {0, 0, 0, 0, 5, 6, 0, 0, 0, 11, 3, 0},
2458 {-8, -8, -8, -8, 0, 0, -8, -8, 0, 0, 0, 0},
2459 {0, 4, 0, 0, 5, 6, 0, 0, 12, 2, 3, 0},
2460 {0, 0, 0, 0, 5, 6, 0, 0, 0, 13, 3, 0},
2461 {0, 0, 0, 0, 5, 6, 0, 0, 0, 14, 3, 0},
2462 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 15, 0},
2463 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 16, 0},
2464 {-2, -2, 9, 10, 0, 0, -2, -2, 0, 0, 0, 0},
2465 {7, 8, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0},
2466 {-1, -1, 9, 10, 0, 0, -1, -1, 0, 0, 0, 0},
2467 {-3, -3, 9, 10, 0, 0, -3, -3, 0, 0, 0, 0},
2468 {-5, -5, -5, -5, 0, 0, -5, -5, 0, 0, 0, 0},
2469 {-6, -6, -6, -6, 0, 0, -6, -6, 0, 0, 0, 0},
2470 {-9, -9, -9, -9, 0, 0, -9, -9, 0, 0, 0, 0}};
2478 fprintf(stderr, "Error in expression\n");
2482 if(chr2index[*p]<0) {
2483 action = table[stack[stackpos-1]][4];
2485 while(chr2index[*pnext]<0)
2489 value = parseNameOrTwip(p);
2493 action = table[stack[stackpos-1]][chr2index[*p]];
2496 if(action == accept) {
2497 return values[stack[stackpos-1]];
2498 } else if(action>0) { // shift
2500 fprintf(stderr, "Stack overflow while parsing expression\n");
2503 values[stackpos]=value;
2504 stack[stackpos++]=action;
2506 } else if(action<0) { // reduce
2507 stackpos-=plen[-action];
2508 stack[stackpos] = table[stack[stackpos-1]][left[-action]];
2511 values[stackpos] = values[stackpos+0] + values[stackpos+2];
2514 values[stackpos] = 0 - values[stackpos+1];
2517 values[stackpos] = values[stackpos+0] - values[stackpos+2];
2520 values[stackpos] = values[stackpos+0] * values[stackpos+2];
2523 values[stackpos] = values[stackpos+0] / values[stackpos+2];
2526 values[stackpos] = values[stackpos+1];
2531 fprintf(stderr, "Syntax error in expression\n");
2537 int parseTwip(char*str)
2539 int v = (int)(parseExpression(str)*20);
2540 printf("%s = %.2f\n", str, v/20.0);
2544 int parseArc(char* str)
2546 if (!strcmp(str, "short"))
2548 if (!strcmp(str, "long"))
2550 syntaxerror("invalid value for the arc parameter: %s", str);
2554 int parseDir(char* str)
2556 if (!strcmp(str, "clockwise"))
2558 if (!strcmp(str, "counterclockwise"))
2560 syntaxerror("invalid value for the dir parameter: %s", str);
2564 int isPoint(char*str)
2566 if(strchr(str, '('))
2572 SPOINT parsePoint(char*str)
2576 int l = strlen(str);
2577 char*comma = strchr(str, ',');
2578 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2579 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2580 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2581 p.x = parseTwip(tmp);
2582 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2583 p.y = parseTwip(tmp);
2587 int parseColor2(char*str, RGBA*color)
2589 int l = strlen(str);
2593 struct {unsigned char r,g,b;char*name;} colors[] =
2594 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2595 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2596 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2597 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2598 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2599 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2600 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2601 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2602 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2603 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2604 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2605 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2609 if(str[0]=='#' && (l==7 || l==9)) {
2610 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2612 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2614 color->r = r; color->g = g; color->b = b; color->a = a;
2617 int len=strlen(str);
2619 if(strchr(str, '/')) {
2620 len = strchr(str, '/')-str;
2621 sscanf(str+len+1,"%02x", &alpha);
2623 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2624 if(!strncmp(str, colors[t].name, len)) {
2629 color->r = r; color->g = g; color->b = b; color->a = a;
2635 RGBA parseColor(char*str)
2638 if(!parseColor2(str, &c))
2639 syntaxerror("Expression '%s' is not a color", str);
2643 typedef struct _muladd {
2648 MULADD parseMulAdd(char*str)
2651 char* str2 = (char*)malloc(strlen(str)+5);
2658 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2659 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2660 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2661 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2662 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2663 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2664 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2665 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2666 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2667 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2669 syntaxerror("'%s' is not a valid color transform expression", str);
2671 m.add = (int)(add*256);
2672 m.mul = (int)(mul*256);
2677 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2679 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2680 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2682 if(a<-32768) a=-32768;
2683 if(a>32767) a=32767;
2684 if(m<-32768) m=-32768;
2685 if(m>32767) m=32767;
2691 float parsePxOrPercent(char*fontname, char*str)
2693 int l = strlen(str);
2694 if(strchr(str, '%'))
2695 return parsePercent(str);
2696 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2697 float p = atof(str);
2698 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2700 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2704 float parsePercent(char*str)
2706 int l = strlen(str);
2710 return atoi(str)/100.0;
2712 syntaxerror("Expression '%s' is not a percentage", str);
2715 int isPercent(char*str)
2717 return str[strlen(str)-1]=='%';
2719 int parseNewSize(char*str, int size)
2722 return parsePercent(str)*size;
2724 return (int)(atof(str)*20);
2727 int isColor(char*str)
2730 return parseColor2(str, &c);
2733 static char* lu(map_t* args, char*name)
2735 char* value = map_lookup(args, name);
2737 map_dump(args, stdout, "");
2738 syntaxerror("internal error 2: value %s should be set", name);
2743 static int c_flash(map_t*args)
2745 char* filename = map_lookup(args, "filename");
2746 char* compressstr = lu(args, "compress");
2747 char* change_modestr = lu(args, "change-sets-all");
2748 char* exportstr = lu(args, "export");
2749 SRECT bbox = parseBox(lu(args, "bbox"));
2750 int version = parseInt(lu(args, "version"));
2751 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2752 RGBA color = parseColor(lu(args, "background"));
2755 if(!filename || !*filename) {
2756 /* for compatibility */
2757 filename = map_lookup(args, "name");
2758 if(!filename || !*filename) {
2761 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2762 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2766 if(!filename || override_outputname)
2767 filename = outputname;
2769 if(!strcmp(compressstr, "default"))
2770 compress = version>=6;
2771 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2773 else if(!strcmp(compressstr, "no"))
2775 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2777 if(!strcmp(change_modestr, "yes"))
2778 change_sets_all = 1;
2780 if(strcmp(change_modestr, "no"))
2781 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2783 do_exports=atoi(exportstr);
2785 s_swf(filename, bbox, version, fps, compress, color);
2788 int isRelative(char*str)
2790 return !strncmp(str, "<plus>", 6) ||
2791 !strncmp(str, "<minus>", 7);
2793 char* getOffset(char*str)
2795 if(!strncmp(str, "<plus>", 6))
2797 if(!strncmp(str, "<minus>", 7))
2799 syntaxerror("internal error (347)");
2802 int getSign(char*str)
2804 if(!strncmp(str, "<plus>", 6))
2806 if(!strncmp(str, "<minus>", 7))
2808 syntaxerror("internal error (348)");
2812 static dictionary_t points;
2813 static mem_t mpoints;
2814 static int points_initialized = 0;
2816 static int c_interpolation(map_t *args)
2819 char* name = lu(args, "name");
2820 if (dictionary_lookup(&interpolations, name))
2821 syntaxerror("interpolation %s defined twice", name);
2823 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2824 char* functionstr = lu(args, "function");
2825 inter->function = 0;
2826 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2827 if (!strcmp(functionstr,interpolationFunctions[i]))
2829 inter->function = i + 1;
2832 if (!inter->function)
2833 syntaxerror("unkown interpolation function %s", functionstr);
2834 inter->speed = parseFloat(lu(args, "speed"));
2835 inter->amplitude = parseTwip(lu(args, "amplitude"));
2836 inter->growth = parseFloat(lu(args, "growth"));
2837 inter->bounces = parseInt(lu(args, "bounces"));
2838 inter->damping = parseFloat(lu(args, "damping"));
2839 inter->slope = parseFloat(lu(args, "slope"));
2841 dictionary_put2(&interpolations, name, inter);
2845 SPOINT getPoint(SRECT r, char*name)
2848 if(!strcmp(name, "center")) {
2850 p.x = (r.xmin + r.xmax)/2;
2851 p.y = (r.ymin + r.ymax)/2;
2854 if (!strcmp(name, "bottom-center")) {
2856 p.x = (r.xmin + r.xmax)/2;
2860 if (!strcmp(name, "top-center")) {
2862 p.x = (r.xmin + r.xmax)/2;
2866 if (!strcmp(name, "top-left")) {
2872 if (!strcmp(name, "top-right")) {
2878 if (!strcmp(name, "bottom-right")) {
2884 if (!strcmp(name, "bottom-left")) {
2890 if (!strcmp(name, "left-center")) {
2893 p.y = (r.ymin + r.ymax)/2;
2896 if (!strcmp(name, "right-center")) {
2899 p.y = (r.ymin + r.ymax)/2;
2904 if(points_initialized)
2905 l = (int)dictionary_lookup(&points, name);
2907 syntaxerror("Invalid point: \"%s\".", name);
2909 return *(SPOINT*)&mpoints.buffer[l-1];
2913 static int texture2(char*name, char*object, map_t*args, int errors)
2916 char*xstr = map_lookup(args, "x");
2917 char*ystr = map_lookup(args, "y");
2918 char*widthstr = map_lookup(args, "width");
2919 char*heightstr = map_lookup(args, "height");
2920 char*scalestr = map_lookup(args, "scale");
2921 char*scalexstr = map_lookup(args, "scalex");
2922 char*scaleystr = map_lookup(args, "scaley");
2923 char*rotatestr = map_lookup(args, "rotate");
2924 char* shearstr = map_lookup(args, "shear");
2925 char* radiusstr = map_lookup(args, "r");
2927 float scalex = 1.0, scaley = 1.0;
2928 float rotate=0, shear=0;
2930 if(!*xstr && !*ystr) {
2932 syntaxerror("x and y must be set");
2935 if(*scalestr && (*scalexstr || *scaleystr)) {
2936 syntaxerror("scale and scalex/scaley can't both be set");
2939 if((*widthstr || *heightstr) && *radiusstr) {
2940 syntaxerror("width/height and radius can't both be set");
2943 widthstr = radiusstr;
2944 heightstr = radiusstr;
2946 if(!*xstr) xstr="0";
2947 if(!*ystr) ystr="0";
2948 if(!*rotatestr) rotatestr="0";
2949 if(!*shearstr) shearstr="0";
2952 scalex = scaley = parsePercent(scalestr);
2953 } else if(*scalexstr || *scaleystr) {
2954 if(scalexstr) scalex = parsePercent(scalexstr);
2955 if(scaleystr) scaley = parsePercent(scaleystr);
2956 } else if(*widthstr || *heightstr) {
2959 s_getBitmapSize(object, &width, &height);
2961 scalex = (float)parseTwip(widthstr)/(float)width;
2963 scaley = (float)parseTwip(heightstr)/(float)height;
2965 x = parseTwip(xstr);
2966 y = parseTwip(ystr);
2967 rotate = parseFloat(rotatestr);
2968 shear = parseFloat(shearstr);
2970 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2975 static int c_texture(map_t*args)
2977 char*name = lu(args, "instance");
2978 char*object = lu(args, "character");
2979 return texture2(name, object, args, 1);
2982 static int c_gradient(map_t*args)
2984 char*name = lu(args, "name");
2985 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2986 int rotate = parseInt(lu(args, "rotate"));
2990 syntaxerror("colon (:) expected");
2992 if(dictionary_lookup(&gradients, name))
2993 syntaxerror("gradient %s defined twice", name);
2995 s_gradient(name, text, radial, rotate);
2997 /* check whether we also have placement information,
2998 which would make this a positioned gradient.
2999 If there is placement information, texture2() will
3000 add a texture, which has priority over the gradient.
3002 texture2(name, name, args, 0);
3006 static char* checkFiltername(map_t* args)
3008 char* name = lu(args, "name");
3009 if (strchr(name, ','))
3010 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
3014 static int c_blur(map_t*args)
3016 char*name = checkFiltername(args);
3017 char*blurstr = lu(args, "blur");
3018 char*blurxstr = lu(args, "blurx");
3019 char*blurystr = lu(args, "blury");
3020 float blurx=1.0, blury=1.0;
3022 blurx = parseFloat(blurstr);
3023 blury = parseFloat(blurstr);
3026 blurx = parseFloat(blurxstr);
3028 blury = parseFloat(blurystr);
3029 int passes = parseInt(lu(args, "passes"));
3030 s_blur(name, blurx, blury, passes);
3034 static int c_gradientglow(map_t*args)
3036 char*name = checkFiltername(args);
3037 char*gradient = lu(args, "gradient");
3038 char*blurstr = lu(args, "blur");
3039 char*blurxstr = lu(args, "blurx");
3040 char*blurystr = lu(args, "blury");
3041 float blurx=1.0, blury=1.0;
3043 blurx = parseFloat(blurstr);
3044 blury = parseFloat(blurstr);
3047 blurx = parseFloat(blurxstr);
3049 blury = parseFloat(blurystr);
3051 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3052 float distance = parseFloat(lu(args, "distance"));
3053 float strength = parseFloat(lu(args, "strength"));
3054 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3055 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3056 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3057 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3058 int passes = parseInt(lu(args, "passes"));
3060 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3064 static int c_dropshadow(map_t*args)
3066 char*name = checkFiltername(args);
3067 RGBA color = parseColor(lu(args, "color"));
3068 char*blurstr = lu(args, "blur");
3069 char*blurxstr = lu(args, "blurx");
3070 char*blurystr = lu(args, "blury");
3071 float blurx=1.0, blury=1.0;
3073 blurx = parseFloat(blurstr);
3074 blury = parseFloat(blurstr);
3077 blurx = parseFloat(blurxstr);
3079 blury = parseFloat(blurystr);
3081 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3082 float distance = parseFloat(lu(args, "distance"));
3083 float strength = parseFloat(lu(args, "strength"));
3084 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3085 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3086 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3087 int passes = parseInt(lu(args, "passes"));
3089 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3093 static int c_bevel(map_t*args)
3095 char*name = checkFiltername(args);
3096 RGBA shadow = parseColor(lu(args, "shadow"));
3097 RGBA highlight = parseColor(lu(args, "highlight"));
3098 char*blurstr = lu(args, "blur");
3099 char*blurxstr = lu(args, "blurx");
3100 char*blurystr = lu(args, "blury");
3101 float blurx=1.0, blury=1.0;
3103 blurx = parseFloat(blurstr);
3104 blury = parseFloat(blurstr);
3107 blurx = parseFloat(blurxstr);
3109 blury = parseFloat(blurystr);
3111 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3112 float distance = parseFloat(lu(args, "distance"));
3113 float strength = parseFloat(lu(args, "strength"));
3114 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3115 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3116 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3117 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3118 int passes = parseInt(lu(args, "passes"));
3120 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3124 static int c_define(map_t*args)
3126 char*name = lu(args, "name");
3127 char*value = lu(args, "value");
3129 if(!defines_initialized) {
3130 dictionary_init(&defines);
3131 mem_init(&define_values);
3132 defines_initialized = 1;
3134 int val = parseTwip(value);
3135 int pos = mem_put(&define_values, &val, sizeof(val));
3137 string_set(&s, name);
3138 dictionary_put(&defines, s, (void*)(pos+1));
3141 static int c_point(map_t*args)
3143 char*name = lu(args, "name");
3147 if(!points_initialized) {
3148 dictionary_init(&points);
3150 points_initialized = 1;
3152 p.x = parseTwip(lu(args, "x"));
3153 p.y = parseTwip(lu(args, "y"));
3154 pos = mem_put(&mpoints, &p, sizeof(p));
3155 string_set(&s1, name);
3156 dictionary_put(&points, s1, (void*)(pos+1));
3159 static int c_play(map_t*args)
3161 char*name = lu(args, "name");
3162 char*loop = lu(args, "loop");
3163 char*nomultiple = lu(args, "nomultiple");
3165 if(!strcmp(nomultiple, "nomultiple"))
3168 nm = parseInt(nomultiple);
3170 if(s_playsound(name, parseInt(loop), nm, 0)) {
3172 } else if(s_swf3action(name, "play")) {
3178 static int c_stop(map_t*args)
3180 char*name = map_lookup(args, "name");
3182 if(s_playsound(name, 0,0,1))
3184 else if(s_swf3action(name, "stop"))
3186 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3190 static int c_nextframe(map_t*args)
3192 char*name = lu(args, "name");
3194 if(s_swf3action(name, "nextframe")) {
3197 syntaxerror("I don't know anything about movie \"%s\"", name);
3201 static int c_previousframe(map_t*args)
3203 char*name = lu(args, "name");
3205 if(s_swf3action(name, "previousframe")) {
3208 syntaxerror("I don't know anything about movie \"%s\"", name);
3212 static int c_movement(map_t*args, int type)
3214 char*instance = lu(args, "name");
3222 xstr = lu(args, "x");
3223 ystr = lu(args, "y");
3225 s_getParameters(instance, &p);
3230 if(isRelative(xstr))
3232 if(type == PT_PUT || type == PT_STARTCLIP)
3233 syntaxerror("relative x values not allowed for initial put or startclip");
3234 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3238 p.x = parseTwip(xstr);
3244 if(isRelative(ystr))
3246 if(type == PT_PUT || type == PT_STARTCLIP)
3247 syntaxerror("relative y values not allowed for initial put or startclip");
3248 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3252 p.y = parseTwip(ystr);
3257 if (change_sets_all)
3265 char* interstr = lu(args, "interpolation");
3266 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3268 syntaxerror("unkown interpolation %s", interstr);
3269 s_change(instance, p, inter);
3274 char* interstr = lu(args, "interpolation");
3275 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3277 syntaxerror("unkown interpolation %s", interstr);
3278 s_schange(instance, p, inter);
3283 char* rstr = lu(args, "r");
3284 int radius = parseTwip(rstr);
3286 syntaxerror("sweep not possible: radius must be greater than 0.");
3287 char* dirstr = lu(args, "dir");
3288 int clockwise = parseDir(dirstr);
3289 char* arcstr = lu(args, "arc");
3290 int short_arc = parseArc(arcstr);
3291 char* interstr = lu(args, "interpolation");
3292 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3294 syntaxerror("unkown interpolation %s", interstr);
3295 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3302 static int c_placement(map_t*args, int type)
3304 char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3307 char* luminancestr = lu(args, "luminance");
3308 char* scalestr = lu(args, "scale");
3309 char* scalexstr = lu(args, "scalex");
3310 char* scaleystr = lu(args, "scaley");
3311 char* rotatestr = lu(args, "rotate");
3312 char* shearstr = lu(args, "shear");
3313 char* xstr="", *pivotstr="";
3314 char* ystr="", *anglestr="";
3315 char*above = lu(args, "above"); /*FIXME*/
3316 char*below = lu(args, "below");
3317 char* rstr = lu(args, "red");
3318 char* gstr = lu(args, "green");
3319 char* bstr = lu(args, "blue");
3320 char* astr = lu(args, "alpha");
3321 char* pinstr = lu(args, "pin");
3322 char* as = map_lookup(args, "as");
3323 char* blendmode = lu(args, "blend");
3324 char* filterstr = lu(args, "filter");
3335 { // (?) .rotate or .arcchange
3336 pivotstr = lu(args, "pivot");
3337 anglestr = lu(args, "angle");
3341 xstr = lu(args, "x");
3342 ystr = lu(args, "y");
3346 luminance = parseMulAdd(luminancestr);
3350 luminance.mul = 256;
3355 if(scalexstr[0]||scaleystr[0])
3356 syntaxerror("scalex/scaley and scale cannot both be set");
3357 scalexstr = scaleystr = scalestr;
3360 if(type == PT_PUT || type == PT_STARTCLIP) {
3362 character = lu(args, "character");
3363 parameters_clear(&p);
3364 } else if (type == PT_BUTTON) {
3365 character = lu(args, "name");
3366 parameters_clear(&p);
3369 s_getParameters(instance, &p);
3375 if(isRelative(xstr))
3377 if(type == PT_PUT || type == PT_STARTCLIP)
3378 syntaxerror("relative x values not allowed for initial put or startclip");
3379 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3383 p.x = parseTwip(xstr);
3389 if(isRelative(ystr))
3391 if(type == PT_PUT || type == PT_STARTCLIP)
3392 syntaxerror("relative y values not allowed for initial put or startclip");
3393 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3397 p.y = parseTwip(ystr);
3402 /* scale, scalex, scaley */
3404 oldbbox = s_getCharBBox(character);
3406 oldbbox = s_getInstanceBBox(instance);
3407 oldwidth = oldbbox.xmax - oldbbox.xmin;
3408 oldheight = oldbbox.ymax - oldbbox.ymin;
3415 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3416 set = set | SF_SCALEX;
3424 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3425 set = set | SF_SCALEY;
3431 if(isRelative(rotatestr))
3432 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3434 p.rotate = parseFloat(rotatestr);
3435 set = set | SF_ROTATE;
3441 if(isRelative(shearstr))
3442 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3444 p.shear = parseFloat(shearstr);
3445 set = set | SF_SHEAR;
3450 if(isPoint(pivotstr))
3451 p.pivot = parsePoint(pivotstr);
3453 p.pivot = getPoint(oldbbox, pivotstr);
3454 set = set | SF_PIVOT;
3460 p.pin = parsePoint(pinstr);
3462 p.pin = getPoint(oldbbox, pinstr);
3466 /* color transform */
3468 if(rstr[0] || luminancestr[0])
3472 r = parseMulAdd(rstr);
3475 r.add = p.cxform.r0;
3476 r.mul = p.cxform.r1;
3478 r = mergeMulAdd(r, luminance);
3479 p.cxform.r0 = r.mul;
3480 p.cxform.r1 = r.add;
3481 set = set | SF_CX_R;
3483 if(gstr[0] || luminancestr[0])
3487 g = parseMulAdd(gstr);
3490 g.add = p.cxform.g0;
3491 g.mul = p.cxform.g1;
3493 g = mergeMulAdd(g, luminance);
3494 p.cxform.g0 = g.mul;
3495 p.cxform.g1 = g.add;
3496 set = set | SF_CX_G;
3498 if(bstr[0] || luminancestr[0])
3502 b = parseMulAdd(bstr);
3505 b.add = p.cxform.b0;
3506 b.mul = p.cxform.b1;
3508 b = mergeMulAdd(b, luminance);
3509 p.cxform.b0 = b.mul;
3510 p.cxform.b1 = b.add;
3511 set = set | SF_CX_B;
3515 MULADD a = parseMulAdd(astr);
3516 p.cxform.a0 = a.mul;
3517 p.cxform.a1 = a.add;
3518 set = set | SF_CX_A;
3525 for(t = 0; blendModeNames[t]; t++)
3527 if(!strcmp(blendModeNames[t], blendmode))
3535 syntaxerror("unknown blend mode: '%s'", blendmode);
3537 p.blendmode = blend;
3538 set = set | SF_BLEND;
3543 p.filters = parseFilters(filterstr);
3544 set = set | SF_FILTER;
3547 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3548 warning("As of version 0.8.2 using the .change command to modify an \
3549 object's position on the stage is considered deprecated. Future \
3550 versions may consider x and y parameters for the .change command \
3551 to be illegal; please use the .move command.");
3553 if (change_sets_all)
3560 s_put(instance, character, p);
3564 char* interstr = lu(args, "interpolation");
3565 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3567 syntaxerror("unkown interpolation %s", interstr);
3568 s_change(instance, p, inter);
3573 char* interstr = lu(args, "interpolation");
3574 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3576 syntaxerror("unkown interpolation %s", interstr);
3577 s_schange(instance, p, inter);
3581 s_jump(instance, p);
3584 s_startclip(instance, character, p);
3588 s_buttonput(character, as, p);
3590 s_buttonput(character, "shape", p);
3596 static int c_put(map_t*args)
3598 c_placement(args, PT_PUT);
3601 static int c_change(map_t*args)
3603 if (currentframe == 0)
3604 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3605 c_placement(args, PT_CHANGE);
3608 static int c_schange(map_t*args)
3610 c_placement(args, PT_SCHANGE);
3613 static int c_move(map_t* args)
3615 c_movement(args, PT_MOVE);
3618 static int c_smove(map_t* args)
3620 c_movement(args, PT_SMOVE);
3623 static int c_sweep(map_t* args)
3625 c_movement(args, PT_SWEEP);
3628 static int c_arcchange(map_t*args)
3630 c_placement(args, 0);
3633 static int c_jump(map_t*args)
3635 c_placement(args, PT_JUMP);
3638 static int c_startclip(map_t*args)
3640 c_placement(args, PT_STARTCLIP);
3643 static int c_show(map_t*args)
3645 c_placement(args, PT_BUTTON);
3648 static int c_toggle(map_t* args)
3650 char*instance = lu(args, "name");
3651 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3652 char* alignstr = lu(args, "fixed_alignment");
3653 if (!strcmp(alignstr, "on"))
3654 flagsOn += IF_FIXED_ALIGNMENT;
3656 if (!strcmp(alignstr, "off"))
3657 flagsOff -= IF_FIXED_ALIGNMENT;
3659 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3660 s_toggle(instance, flagsOn, flagsOff);
3663 static int c_del(map_t*args)
3665 char*instance = lu(args, "name");
3666 s_delinstance(instance);
3669 static int c_end(map_t*args)
3674 static int c_sprite(map_t*args)
3676 char* name = lu(args, "name");
3677 char* scalinggrid = lu(args, "scalinggrid");
3679 if(scalinggrid && *scalinggrid) {
3680 SRECT r = parseBox(scalinggrid);
3687 static int c_frame(map_t*args)
3689 char*framestr = lu(args, "n");
3690 char*cutstr = lu(args, "cut");
3692 char*name = lu(args, "name");
3693 char*anchor = lu(args, "anchor");
3696 if(!strcmp(anchor, "anchor") && !*name)
3701 if(strcmp(cutstr, "no"))
3703 if(isRelative(framestr)) {
3704 frame = s_getframe();
3705 if(getSign(framestr)<0)
3706 syntaxerror("relative frame expressions must be positive");
3707 frame += parseInt(getOffset(framestr));
3710 frame = parseInt(framestr);
3711 if(s_getframe() >= frame
3712 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3713 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3715 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3718 static int c_primitive(map_t*args)
3720 char*name = lu(args, "name");
3721 char*command = lu(args, "commandname");
3722 int width=0, height=0, r=0;
3723 int linewidth = parseTwip(lu(args, "line"));
3724 char*colorstr = lu(args, "color");
3725 RGBA color = parseColor(colorstr);
3726 char*fillstr = lu(args, "fill");
3733 if(!strcmp(command, "circle"))
3735 else if(!strcmp(command, "filled"))
3739 width = parseTwip(lu(args, "width"));
3740 height = parseTwip(lu(args, "height"));
3741 } else if (type==1) {
3742 r = parseTwip(lu(args, "r"));
3743 } else if (type==2) {
3744 outline = lu(args, "outline");
3747 if(!strcmp(fillstr, "fill"))
3749 if(!strcmp(fillstr, "none"))
3751 if(width<0 || height<0 || linewidth<0 || r<0)
3752 syntaxerror("values width, height, line, r must be positive");
3754 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3755 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3756 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3760 static int c_textshape(map_t*args)
3762 char*name = lu(args, "name");
3763 char*text = lu(args, "text");
3764 char*font = lu(args, "font");
3765 float size = parsePxOrPercent(font, lu(args, "size"));
3767 s_textshape(name, font, size, text);
3771 static int c_swf(map_t*args)
3773 char*name = lu(args, "name");
3774 char*filename = lu(args, "filename");
3775 char*command = lu(args, "commandname");
3776 if(!strcmp(command, "shape"))
3777 warning("Please use .swf instead of .shape");
3778 s_includeswf(name, filename);
3782 static int c_font(map_t*args)
3784 char*name = lu(args, "name");
3785 char*filename = lu(args, "filename");
3786 s_font(name, filename);
3790 static int c_sound(map_t*args)
3792 char*name = lu(args, "name");
3793 char*filename = lu(args, "filename");
3794 s_sound(name, filename);
3798 static int c_text(map_t*args)
3800 char*name = lu(args, "name");
3801 char*text = lu(args, "text");
3802 char*font = lu(args, "font");
3803 float size = parsePxOrPercent(font, lu(args, "size"));
3804 RGBA color = parseColor(lu(args, "color"));
3805 s_text(name, font, text, (int)(size*100), color);
3809 static int c_soundtrack(map_t*args)
3814 static int c_quicktime(map_t*args)
3816 char*name = lu(args, "name");
3817 char*url = lu(args, "url");
3818 s_quicktime(name, url);
3822 static int c_image(map_t*args)
3824 char*command = lu(args, "commandname");
3825 char*name = lu(args, "name");
3826 char*filename = lu(args, "filename");
3827 if(!strcmp(command,"jpeg")) {
3828 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3829 s_image(name, "jpeg", filename, quality);
3831 s_image(name, "png", filename, 0);
3836 static int c_outline(map_t*args)
3838 char*name = lu(args, "name");
3839 char*format = lu(args, "format");
3843 syntaxerror("colon (:) expected");
3845 s_outline(name, format, text);
3849 int fakechar(map_t*args)
3851 char*name = lu(args, "name");
3852 s_box(name, 0, 0, black, 20, 0);
3856 static int c_egon(map_t*args) {return fakechar(args);}
3857 static int c_button(map_t*args) {
3858 char*name = lu(args, "name");
3862 static int current_button_flags = 0;
3863 static int c_on_press(map_t*args)
3865 char*position = lu(args, "position");
3867 if(!strcmp(position, "inside")) {
3868 current_button_flags |= BC_OVERUP_OVERDOWN;
3869 } else if(!strcmp(position, "outside")) {
3870 //current_button_flags |= BC_IDLE_OUTDOWN;
3871 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3872 } else if(!strcmp(position, "anywhere")) {
3873 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3876 if(type == RAWDATA) {
3878 s_buttonaction(current_button_flags, action);
3879 current_button_flags = 0;
3885 static int c_on_release(map_t*args)
3887 char*position = lu(args, "position");
3889 if(!strcmp(position, "inside")) {
3890 current_button_flags |= BC_OVERDOWN_OVERUP;
3891 } else if(!strcmp(position, "outside")) {
3892 current_button_flags |= BC_OUTDOWN_IDLE;
3893 } else if(!strcmp(position, "anywhere")) {
3894 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3897 if(type == RAWDATA) {
3899 s_buttonaction(current_button_flags, action);
3900 current_button_flags = 0;
3906 static int c_on_move_in(map_t*args)
3908 char*position = lu(args, "state");
3910 if(!strcmp(position, "pressed")) {
3911 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3912 } else if(!strcmp(position, "not_pressed")) {
3913 current_button_flags |= BC_IDLE_OVERUP;
3914 } else if(!strcmp(position, "any")) {
3915 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3918 if(type == RAWDATA) {
3920 s_buttonaction(current_button_flags, action);
3921 current_button_flags = 0;
3927 static int c_on_move_out(map_t*args)
3929 char*position = lu(args, "state");
3931 if(!strcmp(position, "pressed")) {
3932 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3933 } else if(!strcmp(position, "not_pressed")) {
3934 current_button_flags |= BC_OVERUP_IDLE;
3935 } else if(!strcmp(position, "any")) {
3936 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3939 if(type == RAWDATA) {
3941 s_buttonaction(current_button_flags, action);
3942 current_button_flags = 0;
3948 static int c_on_key(map_t*args)
3950 char*key = lu(args, "key");
3952 if(strlen(key)==1) {
3955 current_button_flags |= 0x4000 + (key[0]*0x200);
3957 syntaxerror("invalid character: %c"+key[0]);
3962 <ctrl-x> = 0x200*(x-'a')
3966 syntaxerror("invalid key: %s",key);
3969 if(type == RAWDATA) {
3971 s_buttonaction(current_button_flags, action);
3972 current_button_flags = 0;
3979 static int c_edittext(map_t*args)
3981 //"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"},
3982 char*name = lu(args, "name");
3983 char*font = lu(args, "font");
3984 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3985 int width = parseTwip(lu(args, "width"));
3986 int height = parseTwip(lu(args, "height"));
3987 char*text = lu(args, "text");
3988 RGBA color = parseColor(lu(args, "color"));
3989 int maxlength = parseInt(lu(args, "maxlength"));
3990 char*variable = lu(args, "variable");
3991 char*passwordstr = lu(args, "password");
3992 char*wordwrapstr = lu(args, "wordwrap");
3993 char*multilinestr = lu(args, "multiline");
3994 char*htmlstr = lu(args, "html");
3995 char*noselectstr = lu(args, "noselect");
3996 char*readonlystr = lu(args, "readonly");
3997 char*borderstr = lu(args, "border");
3998 char*autosizestr = lu(args, "autosize");
3999 char*alignstr = lu(args, "align");
4003 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
4004 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
4005 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
4006 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
4007 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
4008 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
4009 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
4010 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
4011 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
4012 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
4013 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
4014 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
4015 else syntaxerror("Unknown alignment: %s", alignstr);
4017 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
4021 static int c_morphshape(map_t*args) {return fakechar(args);}
4022 static int c_movie(map_t*args) {return fakechar(args);}
4024 static char* readfile(const char*filename)
4026 FILE*fi = fopen(filename, "rb");
4030 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
4031 fseek(fi, 0, SEEK_END);
4033 fseek(fi, 0, SEEK_SET);
4034 text = rfx_alloc(l+1);
4035 fread(text, l, 1, fi);
4041 static int c_action(map_t*args)
4043 char* filename = map_lookup(args, "filename");
4044 if(!filename ||!*filename) {
4046 if(type != RAWDATA) {
4047 syntaxerror("colon (:) expected");
4051 s_action(readfile(filename));
4057 static int c_initaction(map_t*args)
4059 char* character = lu(args, "name");
4060 char* filename = map_lookup(args, "filename");
4061 if(!filename ||!*filename) {
4063 if(type != RAWDATA) {
4064 syntaxerror("colon (:) expected");
4066 s_initaction(character, text);
4068 s_initaction(character, readfile(filename));
4076 command_func_t* func;
4079 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1"},
4080 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
4081 // "import" type stuff
4082 {"swf", c_swf, "name filename"},
4083 {"shape", c_swf, "name filename"},
4084 {"jpeg", c_image, "name filename quality=80%"},
4085 {"png", c_image, "name filename"},
4086 {"movie", c_movie, "name filename"},
4087 {"sound", c_sound, "name filename"},
4088 {"font", c_font, "name filename glyphs="},
4089 {"soundtrack", c_soundtrack, "filename"},
4090 {"quicktime", c_quicktime, "url"},
4092 // generators of primitives
4094 {"define", c_define, "name value=0"},
4095 {"point", c_point, "name x=0 y=0"},
4096 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4097 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4098 {"outline", c_outline, "name format=simple"},
4099 {"textshape", c_textshape, "name font size=100% text"},
4102 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4103 {"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"},
4104 {"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"},
4105 {"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"},
4107 // character generators
4108 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4109 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4110 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4112 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4113 {"text", c_text, "name text font size=100% color=white"},
4114 {"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="},
4115 {"morphshape", c_morphshape, "name start end"},
4116 {"button", c_button, "name"},
4117 {"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="},
4118 {"on_press", c_on_press, "position=inside"},
4119 {"on_release", c_on_release, "position=anywhere"},
4120 {"on_move_in", c_on_move_in, "state=not_pressed"},
4121 {"on_move_out", c_on_move_out, "state=not_pressed"},
4122 {"on_key", c_on_key, "key=any"},
4125 {"play", c_play, "name loop=0 @nomultiple=0"},
4126 {"stop", c_stop, "name= "},
4127 {"nextframe", c_nextframe, "name"},
4128 {"previousframe", c_previousframe, "name"},
4130 // object placement tags
4131 {"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="},
4132 {"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="},
4133 {"move", c_move, "name x= y= interpolation=linear"},
4134 {"smove", c_smove, "name x= y= interpolation=linear"},
4135 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4136 {"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"},
4137 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4138 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4139 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4140 {"del", c_del, "name"},
4141 // virtual object placement
4142 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4144 {"toggle", c_toggle, "name fixed_alignment="},
4146 // commands which start a block
4147 //startclip (see above)
4148 {"sprite", c_sprite, "name scalinggrid="},
4149 {"action", c_action, "filename="},
4150 {"initaction", c_initaction, "name filename="},
4156 static map_t parseArguments(char*command, char*pattern)
4172 string_set(&t1, "commandname");
4173 string_set(&t2, command);
4174 map_put(&result, t1, t2);
4176 if(!pattern || !*pattern)
4183 if(!strncmp("<i> ", x, 3)) {
4185 if(type == COMMAND || type == RAWDATA) {
4187 syntaxerror("character name expected");
4189 name[pos].str = "instance";
4191 value[pos].str = text;
4192 value[pos].len = strlen(text);
4196 if(type == ASSIGNMENT)
4199 name[pos].str = "character";
4201 value[pos].str = text;
4202 value[pos].len = strlen(text);
4210 isboolean[pos] = (x[0] =='@');
4223 name[pos].len = d-x;
4228 name[pos].len = e-x;
4229 value[pos].str = e+1;
4230 value[pos].len = d-e-1;
4238 /* for(t=0;t<len;t++) {
4239 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4240 isboolean[t]?"(boolean)":"");
4245 if(type == RAWDATA || type == COMMAND) {
4250 // first, search for boolean arguments
4251 for(pos=0;pos<len;pos++)
4253 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4255 if(type == ASSIGNMENT)
4257 value[pos].str = text;
4258 value[pos].len = strlen(text);
4259 /*printf("setting boolean parameter %s (to %s)\n",
4260 strdup_n(name[pos], namelen[pos]),
4261 strdup_n(value[pos], valuelen[pos]));*/
4266 // second, search for normal arguments
4268 for(pos=0;pos<len;pos++)
4270 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4271 (type != ASSIGNMENT && !set[pos])) {
4273 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4275 if(type == ASSIGNMENT)
4278 value[pos].str = text;
4279 value[pos].len = strlen(text);
4281 printf("setting parameter %s (to %s)\n",
4282 strdup_n(name[pos].str, name[pos].len),
4283 strdup_n(value[pos].str, value[pos].len));
4289 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4293 for(t=0;t<len;t++) {
4294 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4297 for(t=0;t<len;t++) {
4298 if(value[t].str && value[t].str[0] == '*') {
4299 //relative default- take value from some other parameter
4301 for(s=0;s<len;s++) {
4302 if(value[s].len == value[t].len-1 &&
4303 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4304 value[t].str = value[s].str;
4307 if(value[t].str == 0) {
4309 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4313 /* ok, now construct the dictionary from the parameters */
4317 map_put(&result, name[t], value[t]);
4321 static void parseArgumentsForCommand(char*command)
4326 msg("<verbose> parse Command: %s (line %d)", command, line);
4328 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4329 if(!strcmp(arguments[t].command, command)) {
4331 /* ugly hack- will be removed soon (once documentation and .sc generating
4332 utilities have been changed) */
4333 if(!strcmp(command, "swf") && !stackpos) {
4334 warning("Please use .flash instead of .swf- this will be mandatory soon");
4339 args = parseArguments(command, arguments[t].arguments);
4345 syntaxerror("command %s not known", command);
4347 // catch missing .flash directives at the beginning of a file
4348 if(strcmp(command, "flash") && !stackpos)
4350 syntaxerror("No movie defined- use .flash first");
4354 printf(".%s\n", command);fflush(stdout);
4355 map_dump(&args, stdout, "\t");fflush(stdout);
4358 (*arguments[nr].func)(&args);
4360 /*if(!strcmp(command, "button") ||
4361 !strcmp(command, "action")) {
4364 if(type == COMMAND) {
4365 if(!strcmp(text, "end"))
4380 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4381 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4382 * No syntax checking is done */
4383 static void analyseArgumentsForCommand(char*command)
4389 U8* glyphs_to_include;
4390 msg("<verbose> analyse Command: %s (line %d)", command, line);
4392 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4394 if(!strcmp(arguments[t].command, command))
4396 args = parseArguments(command, arguments[t].arguments);
4402 printf(".%s\n", command);fflush(stdout);
4403 map_dump(&args, stdout, "\t");fflush(stdout);
4405 char* name = lu(&args, "name");
4406 if (!strcmp(command, "font"))
4408 if(dictionary_lookup(&fonts, name))
4409 syntaxerror("font %s defined twice", name);
4412 fontfile = lu(&args, "filename");
4413 font = swf_LoadFont(fontfile);
4415 warning("Couldn't open font file \"%s\"", fontfile);
4416 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4417 memset(font, 0, sizeof(SWFFONT));
4421 swf_FontPrepareForEditText(font);
4422 glyphs_to_include = lu(&args, "glyphs");
4423 if (!strcmp(glyphs_to_include, "all"))
4425 swf_FontUseAll(font);
4426 font->use->glyphs_specified = 1;
4430 if (strcmp (glyphs_to_include, ""))
4432 swf_FontUseUTF8(font, glyphs_to_include);
4433 font->use->glyphs_specified = 1;
4436 swf_FontInitUsage(font);
4439 dictionary_put2(&fonts, name, font);
4443 SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "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, 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 dictionary_init(&fonts);
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);