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 if(!stackpos || !stack[stackpos-1].tag ||
770 stack[stackpos-1].tag->id != ST_DEFINEBUTTON2) {
771 syntaxerror("Need to be inside a button for .on_* commands");
773 setbuttonrecords(stack[stackpos-1].tag);
775 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
777 syntaxerror("Couldn't compile ActionScript");
780 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
781 swf_ActionSet(stack[stackpos-1].tag, a);
782 mybutton.nr_actions++;
787 static void setactionend(TAG*tag)
789 if(!mybutton.nr_actions) {
790 /* no actions means we didn't have an actionoffset,
791 which means we can't signal the end of the
792 buttonaction records, so, *sigh*, we have
793 to insert a dummy record */
794 swf_SetU16(tag, 0); //offset
795 swf_SetU16(tag, 0); //condition
796 swf_SetU8(tag, 0); //action
800 static void s_endButton()
803 setbuttonrecords(stack[stackpos-1].tag);
804 setactionend(stack[stackpos-1].tag);
807 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
811 tag = stack[stackpos].tag;
812 currentrect = stack[stackpos].oldrect;
814 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
815 free(stack[stackpos].name);
818 TAG* removeFromTo(TAG*from, TAG*to)
820 TAG*save = from->prev;
822 TAG*next = from->next;
823 if(swf_isAllowedSpriteTag(from))
824 swf_DeleteTag(0, from);
831 static int parametersChange(history_t* history, int frame)
835 willChange = willChange || history_change(history, frame, "x");
836 willChange = willChange || history_change(history, frame, "y");
837 willChange = willChange || history_change(history, frame, "scalex");
838 willChange = willChange || history_change(history, frame, "scaley");
839 willChange = willChange || history_change(history, frame, "cxform.r0");
840 willChange = willChange || history_change(history, frame, "cxform.g0");
841 willChange = willChange || history_change(history, frame, "cxform.b0");
842 willChange = willChange || history_change(history, frame, "cxform.a0");
843 willChange = willChange || history_change(history, frame, "cxform.r1");
844 willChange = willChange || history_change(history, frame, "cxform.g1");
845 willChange = willChange || history_change(history, frame, "cxform.b1");
846 willChange = willChange || history_change(history, frame, "cxform.a1");
847 willChange = willChange || history_change(history, frame, "rotate");
848 willChange = willChange || history_change(history, frame, "shear");
849 willChange = willChange || history_change(history, frame, "pivot.x");
850 willChange = willChange || history_change(history, frame, "pivot.y");
851 willChange = willChange || history_change(history, frame, "pin.x");
852 willChange = willChange || history_change(history, frame, "pin.y");
853 willChange = willChange || history_change(history, frame, "blendmode");
854 willChange = willChange || history_changeFilter(history, frame);
859 static void free_filterlist(FILTERLIST* f_list)
862 for (i = 0; i < f_list->num; i++)
864 if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
865 gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
866 free(f_list->filter[i]);
871 static void readParameters(history_t* history, parameters_t* p, int frame)
873 p->x = history_value(history, frame, "x");
874 p->y = history_value(history, frame, "y");
875 p->scalex = history_value(history, frame, "scalex");
876 p->scaley = history_value(history, frame, "scaley");
877 p->cxform.r0 = history_value(history, frame, "cxform.r0");
878 p->cxform.g0 = history_value(history, frame, "cxform.g0");
879 p->cxform.b0 = history_value(history, frame, "cxform.b0");
880 p->cxform.a0 = history_value(history, frame, "cxform.a0");
881 p->cxform.r1 = history_value(history, frame, "cxform.r1");
882 p->cxform.g1 = history_value(history, frame, "cxform.g1");
883 p->cxform.b1 = history_value(history, frame, "cxform.b1");
884 p->cxform.a1 = history_value(history, frame, "cxform.a1");
885 p->rotate = history_rotateValue(history, frame);
886 p->shear = history_value(history, frame, "shear");
887 p->pivot.x = history_value(history, frame, "pivot.x");
888 p->pivot.y = history_value(history, frame, "pivot.y");
889 p->pin.x = history_value(history, frame, "pin.x");
890 p->pin.y = history_value(history, frame, "pin.y");
891 p->blendmode = history_value(history, frame, "blendmode");
892 p->filters = history_filterValue(history, frame);
895 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
899 swf_GetPlaceObject(NULL, &po);
903 po.cxform = p->cxform;
909 po.blendmode = p->blendmode;
912 po.filters = p->filters;
913 swf_SetPlaceObject(tag, &po);
916 static void writeInstance(instance_t* i)
920 int frame = i->history->firstFrame;
921 TAG* tag = i->history->firstTag;
922 history_processFlags(i->history);
923 while (frame < currentframe)
926 while (tag->id != ST_SHOWFRAME)
928 if (parametersChange(i->history, frame))
930 readParameters(i->history, &p, frame);
931 m = s_instancepos(i->character->size, &p);
933 if(p.blendmode || p.filters)
934 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
936 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
937 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
939 free_filterlist(p.filters);
946 void dumpSWF(SWF*swf)
948 TAG* tag = swf->firstTag;
949 printf("vvvvvvvvvvvvvvvvvvvvv\n");
951 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
954 printf("^^^^^^^^^^^^^^^^^^^^^\n");
957 static void s_endSprite()
959 SRECT r = currentrect;
963 stringarray_t* index =dictionary_index(&instances);
965 for (num = 0; num < dictionary_count(&instances); num++)
967 char* name = stringarray_at(index, num);
970 i = dictionary_lookup(&instances, name);
975 if(stack[stackpos].cut)
976 tag = removeFromTo(stack[stackpos].cut, tag);
978 // the writeInstance loop above may have inserted tags after what used yo be the current tag,
979 // so let's make sure 'tag' point to the current tag again.
983 tag = swf_InsertTag(tag, ST_SHOWFRAME);
984 tag = swf_InsertTag(tag, ST_END);
986 tag = stack[stackpos].tag;
989 if(stack[stackpos].scalegrid.xmin | stack[stackpos].scalegrid.ymin |
990 stack[stackpos].scalegrid.xmax | stack[stackpos].scalegrid.ymax)
992 tag = swf_InsertTag(tag, ST_DEFINESCALINGGRID);
993 swf_SetU16(tag, stack[stackpos].id);
994 swf_SetRect(tag, &stack[stackpos].scalegrid);
998 syntaxerror("internal error(7)");
999 /* TODO: before clearing, prepend "<spritename>." to names and
1000 copy into old instances dict */
1001 dictionary_free_all(&instances, free_instance);
1003 currentframe = stack[stackpos].oldframe;
1004 currentrect = stack[stackpos].oldrect;
1005 currentdepth = stack[stackpos].olddepth;
1006 instances = stack[stackpos].oldinstances;
1008 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
1009 free(stack[stackpos].name);
1012 static void s_endSWF()
1019 stringarray_t* index = dictionary_index(&instances);
1021 for (num = 0; num < dictionary_count(&instances); num++)
1023 char* name = stringarray_at(index, num);
1026 i = dictionary_lookup(&instances, name);
1031 if(stack[stackpos].cut)
1032 tag = removeFromTo(stack[stackpos].cut, tag);
1036 swf = stack[stackpos].swf;
1037 filename = stack[stackpos].filename;
1039 // the writeInstance loop above may have inserted tags after what used yo be the current tag,
1040 // so let's make sure 'tag' point to the current tag again.
1044 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1045 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
1046 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1048 tag = swf_InsertTag(tag, ST_END);
1050 swf_OptimizeTagOrder(swf);
1056 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1057 swf->movieSize = currentrect; /* "autocrop" */
1060 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1061 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1062 swf->movieSize.ymax += 20;
1063 warning("Empty bounding box for movie");
1066 if(do_cgi || !strcmp(filename, "-"))
1067 fi = fileno(stdout);
1069 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1071 syntaxerror("couldn't create output file %s", filename);
1074 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1076 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1090 if(stack[stackpos-1].type == 0)
1091 syntaxerror("End of file encountered in .flash block");
1092 if(stack[stackpos-1].type == 1)
1093 syntaxerror("End of file encountered in .sprite block");
1094 if(stack[stackpos-1].type == 2)
1095 syntaxerror("End of file encountered in .clip block");
1101 return currentframe+1;
1104 void s_frame(int nr, int cut, char*name, char anchor)
1110 syntaxerror("Illegal frame number");
1111 nr--; // internally, frame 1 is frame 0
1113 for(t=currentframe;t<nr;t++) {
1114 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1115 if(t==nr-1 && name && *name) {
1116 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1117 swf_SetString(tag, name);
1119 swf_SetU8(tag, 1); //make this an anchor
1122 if(nr == 0 && currentframe == 0 && name && *name) {
1123 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1124 swf_SetString(tag, name);
1126 swf_SetU8(tag, 1); //make this an anchor
1131 syntaxerror("Can't cut, frame empty");
1133 stack[stackpos].cut = tag;
1139 int parseColor2(char*str, RGBA*color);
1141 int addFillStyle(SHAPE*s, SRECT*r, char*name)
1145 gradient_t*gradient;
1147 if(name[0] == '#') {
1148 parseColor2(name, &color);
1149 return swf_ShapeAddSolidFillStyle(s, &color);
1150 } else if ((texture = dictionary_lookup(&textures, name))) {
1151 return swf_ShapeAddFillStyle2(s, &texture->fs);
1152 } else if((image = dictionary_lookup(&images, name))) {
1154 swf_GetMatrix(0, &m);
1155 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1156 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1159 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1160 } else if ((gradient = dictionary_lookup(&gradients, name))) {
1164 swf_GetMatrix(0, &rot);
1165 ccos = cos(-gradient->rotate*2*M_PI/360);
1166 csin = sin(-gradient->rotate*2*M_PI/360);
1167 rot.sx = ccos*65536;
1168 rot.r1 = -csin*65536;
1169 rot.r0 = csin*65536;
1170 rot.sy = ccos*65536;
1171 r2 = swf_TurnRect(*r, &rot);
1172 swf_GetMatrix(0, &m);
1173 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1174 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1175 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1176 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1177 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1178 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1179 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1180 } else if (parseColor2(name, &color)) {
1181 return swf_ShapeAddSolidFillStyle(s, &color);
1183 syntaxerror("not a color/fillstyle: %s", name);
1188 RGBA black={r:0,g:0,b:0,a:0};
1189 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
1198 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1201 linewidth = linewidth>=20?linewidth-20:0;
1202 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1205 fs1 = addFillStyle(s, &r2, texture);
1208 r.xmin = r2.xmin-linewidth/2;
1209 r.ymin = r2.ymin-linewidth/2;
1210 r.xmax = r2.xmax+linewidth/2;
1211 r.ymax = r2.ymax+linewidth/2;
1212 swf_SetRect(tag,&r);
1213 swf_SetShapeHeader(tag,s);
1214 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1215 swf_ShapeSetLine(tag,s,width,0);
1216 swf_ShapeSetLine(tag,s,0,height);
1217 swf_ShapeSetLine(tag,s,-width,0);
1218 swf_ShapeSetLine(tag,s,0,-height);
1219 swf_ShapeSetEnd(tag);
1222 s_addcharacter(name, id, tag, r);
1226 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
1232 outline = dictionary_lookup(&outlines, outlinename);
1234 syntaxerror("outline %s not defined", outlinename);
1238 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1241 linewidth = linewidth>=20?linewidth-20:0;
1242 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1245 fs1 = addFillStyle(s, &r2, texture);
1248 rect.xmin = r2.xmin-linewidth/2;
1249 rect.ymin = r2.ymin-linewidth/2;
1250 rect.xmax = r2.xmax+linewidth/2;
1251 rect.ymax = r2.ymax+linewidth/2;
1253 swf_SetRect(tag,&rect);
1254 swf_SetShapeStyles(tag, s);
1255 swf_ShapeCountBits(s,0,0);
1256 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1257 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1258 swf_SetShapeBits(tag, s);
1259 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1262 s_addcharacter(name, id, tag, rect);
1266 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
1271 r2.xmin = r2.ymin = 0;
1275 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1278 linewidth = linewidth>=20?linewidth-20:0;
1279 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1282 fs1 = addFillStyle(s, &r2, texture);
1284 rect.xmin = r2.xmin-linewidth/2;
1285 rect.ymin = r2.ymin-linewidth/2;
1286 rect.xmax = r2.xmax+linewidth/2;
1287 rect.ymax = r2.ymax+linewidth/2;
1289 swf_SetRect(tag,&rect);
1290 swf_SetShapeHeader(tag,s);
1291 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1292 swf_ShapeSetCircle(tag, s, r,r,r,r);
1293 swf_ShapeSetEnd(tag);
1296 s_addcharacter(name, id, tag, rect);
1300 void s_textshape(char*name, char*fontname, float size, char*_text)
1303 U8*text = (U8*)_text;
1307 font = dictionary_lookup(&fonts, fontname);
1309 syntaxerror("font \"%s\" not known!", fontname);
1311 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1312 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1313 s_box(name, 0, 0, black, 20, 0);
1316 g = font->ascii2glyph[text[0]];
1318 outline = malloc(sizeof(outline_t));
1319 memset(outline, 0, sizeof(outline_t));
1320 outline->shape = font->glyph[g].shape;
1321 outline->bbox = font->layout->bounds[g];
1325 swf_Shape11DrawerInit(&draw, 0);
1326 swf_DrawText(&draw, font, (int)(size*100), _text);
1328 outline->shape = swf_ShapeDrawerToShape(&draw);
1329 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1330 draw.dealloc(&draw);
1333 if(dictionary_lookup(&outlines, name))
1334 syntaxerror("outline %s defined twice", name);
1335 dictionary_put2(&outlines, name, outline);
1338 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
1343 font = dictionary_lookup(&fonts, fontname);
1345 syntaxerror("font \"%s\" not known!", fontname);
1347 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1348 swf_SetU16(tag, id);
1349 if(!font->numchars) {
1350 s_box(name, 0, 0, black, 20, 0);
1353 r = swf_SetDefineText(tag, font, &color, text, size);
1355 if(stack[0].swf->fileVersion >= 8) {
1356 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1357 swf_SetU16(tag, id);
1358 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1359 swf_SetU32(tag, 0);//thickness
1360 swf_SetU32(tag, 0);//sharpness
1361 swf_SetU8(tag, 0);//reserved
1364 s_addcharacter(name, id, tag, r);
1368 void s_quicktime(char*name, char*url)
1373 memset(&r, 0, sizeof(r));
1375 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1376 swf_SetU16(tag, id);
1377 swf_SetString(tag, url);
1379 s_addcharacter(name, id, tag, r);
1383 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)
1386 EditTextLayout layout;
1389 if(fontname && *fontname) {
1390 flags |= ET_USEOUTLINES;
1391 font = dictionary_lookup(&fonts, fontname);
1393 syntaxerror("font \"%s\" not known!", fontname);
1395 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1396 swf_SetU16(tag, id);
1397 layout.align = align;
1398 layout.leftmargin = 0;
1399 layout.rightmargin = 0;
1407 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1409 s_addcharacter(name, id, tag, r);
1413 /* type: either "jpeg" or "png"
1415 void s_image(char*name, char*type, char*filename, int quality)
1417 /* an image is actually two folded: 1st bitmap, 2nd character.
1418 Both of them can be used separately */
1420 /* step 1: the bitmap */
1424 if(!strcmp(type,"jpeg")) {
1425 #ifndef HAVE_JPEGLIB
1426 warning("no jpeg support compiled in");
1427 s_box(name, 0, 0, black, 20, 0);
1430 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1431 swf_SetU16(tag, imageID);
1433 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1434 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1437 swf_GetJPEGSize(filename, &width, &height);
1444 s_addimage(name, id, tag, r);
1447 } else if(!strcmp(type,"png")) {
1449 swf_SetU16(tag, imageID);
1451 getPNG(filename, &width, &height, (unsigned char**)&data);
1454 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1457 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1458 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1459 swf_SetU16(tag, imageID);
1460 swf_SetLosslessImage(tag, data, width, height);
1467 s_addimage(name, id, tag, r);
1470 warning("image type \"%s\" not supported yet!", type);
1471 s_box(name, 0, 0, black, 20, 0);
1475 /* step 2: the character */
1476 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1477 swf_SetU16(tag, id);
1478 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1480 s_addcharacter(name, id, tag, r);
1484 void s_getBitmapSize(char*name, int*width, int*height)
1486 character_t* image = dictionary_lookup(&images, name);
1487 gradient_t* gradient = dictionary_lookup(&gradients,name);
1489 *width = image->size.xmax;
1490 *height = image->size.ymax;
1494 /* internal SWF gradient size */
1495 if(gradient->radial) {
1504 syntaxerror("No such bitmap/gradient: %s", name);
1507 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1509 if(dictionary_lookup(&textures, name))
1510 syntaxerror("texture %s defined twice", name);
1511 gradient_t* gradient = dictionary_lookup(&gradients, object);
1512 character_t* bitmap = dictionary_lookup(&images, object);
1513 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1515 FILLSTYLE*fs = &texture->fs;
1517 memset(&p, 0, sizeof(parameters_t));
1520 fs->type = FILL_TILED;
1521 fs->id_bitmap = bitmap->id;
1522 } else if(gradient) {
1523 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1524 fs->gradient = gradient->gradient;
1526 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1527 makeMatrix(&fs->m, &p);
1528 if(gradient && !gradient->radial) {
1535 p2 = swf_TurnPoint(p1, &m);
1544 dictionary_put2(&textures, name, texture);
1547 void s_font(char*name, char*filename)
1550 font = dictionary_lookup(&fonts, name);
1553 /* fix the layout. Only needed for old fonts */
1555 for(t=0;t<font->numchars;t++) {
1556 font->glyph[t].advance = 0;
1559 swf_FontCreateLayout(font);
1562 swf_FontReduce_swfc(font);
1563 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1564 swf_FontSetDefine2(tag, font);
1566 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1568 swf_SetU16(tag, id);
1569 swf_SetString(tag, name);
1577 typedef struct _sound_t
1583 void s_sound(char*name, char*filename)
1585 struct WAV wav, wav2;
1589 unsigned numsamples = 1;
1590 unsigned blocksize = 1152;
1593 if(dictionary_lookup(&sounds, name))
1594 syntaxerror("sound %s defined twice", name);
1596 if(wav_read(&wav, filename))
1599 wav_convert2mono(&wav, &wav2, 44100);
1600 samples = (U16*)wav2.data;
1601 numsamples = wav2.size/2;
1603 #ifdef WORDS_BIGENDIAN
1605 for(t=0;t<numsamples;t++)
1606 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1610 if(mp3_read(&mp3, filename))
1612 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1618 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1623 if(numsamples%blocksize != 0)
1625 // apply padding, so that block is a multiple of blocksize
1626 int numblocks = (numsamples+blocksize-1)/blocksize;
1629 numsamples2 = numblocks * blocksize;
1630 samples2 = malloc(sizeof(U16)*numsamples2);
1631 memcpy(samples2, samples, numsamples*sizeof(U16));
1632 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1633 numsamples = numsamples2;
1638 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1639 swf_SetU16(tag, id); //id
1642 swf_SetSoundDefineMP3(
1643 tag, mp3.data, mp3.size,
1650 swf_SetSoundDefine(tag, samples, numsamples);
1653 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1654 swf_SetU16(tag, id);
1655 swf_SetString(tag, name);
1656 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1658 swf_SetU16(tag, id);
1659 swf_SetString(tag, name);
1662 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1666 dictionary_put2(&sounds, name, sound);
1674 static char* gradient_getToken(const char**p)
1678 while(**p && strchr(" \t\n\r", **p)) {
1682 while(**p && !strchr(" \t\n\r", **p)) {
1685 result = malloc((*p)-start+1);
1686 memcpy(result,start,(*p)-start+1);
1687 result[(*p)-start] = 0;
1691 float parsePercent(char*str);
1692 RGBA parseColor(char*str);
1694 GRADIENT parseGradient(const char*str)
1698 const char* p = str;
1699 memset(&gradient, 0, sizeof(GRADIENT));
1700 gradient.ratios = rfx_calloc(16*sizeof(U8));
1701 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1705 char*posstr,*colorstr;
1708 posstr = gradient_getToken(&p);
1714 pos = (int)(parsePercent(posstr)*255.0);
1719 rfx_free(gradient.ratios);
1720 rfx_free(gradient.rgba);
1722 syntaxerror("Error in shape data: Color expected after %s", posstr);
1724 colorstr = gradient_getToken(&p);
1725 color = parseColor(colorstr);
1726 if(gradient.num == 16)
1728 warning("gradient record too big- max size is 16, rest ignored");
1731 gradient.ratios[gradient.num] = pos;
1732 gradient.rgba[gradient.num] = color;
1741 FILTERLIST* parseFilters(char* list)
1743 if (!strcmp(list, "no_filters"))
1746 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1748 char* f_start = list;
1752 f_end = strchr(f_start, ',');
1755 f = dictionary_lookup(&filters, f_start);
1759 syntaxerror("unknown filter %s", f_start);
1761 if (f_list->num == 8)
1763 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1766 f_list->filter[f_list->num] = f;
1771 f_start = f_end + 1;
1779 void s_gradient(char*name, const char*text, int radial, int rotate)
1781 gradient_t* gradient;
1782 gradient = malloc(sizeof(gradient_t));
1783 memset(gradient, 0, sizeof(gradient_t));
1784 gradient->gradient = parseGradient(text);
1785 gradient->radial = radial;
1786 gradient->rotate = rotate;
1788 dictionary_put2(&gradients, name, gradient);
1791 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1792 float angle, float distance, float strength, char innershadow,
1793 char knockout, char composite, char ontop, int passes)
1795 if(dictionary_lookup(&filters, name))
1796 syntaxerror("filter %s defined twice", name);
1798 gradient_t* g = dictionary_lookup(&gradients, gradient);
1800 syntaxerror("unknown gradient %s", gradient);
1804 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1805 filter->type = FILTERTYPE_GRADIENTGLOW;
1806 filter->gradient = &g->gradient;
1807 filter->blurx = blurx;
1808 filter->blury = blury;
1809 filter->strength = strength;
1810 filter->angle = angle;
1811 filter->distance = distance;
1812 filter->innershadow = innershadow;
1813 filter->knockout = knockout;
1814 filter->composite = composite;
1815 filter->ontop = ontop;
1816 filter->passes = passes;
1818 dictionary_put2(&filters, name, filter);
1821 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)
1823 if(dictionary_lookup(&filters, name))
1824 syntaxerror("filter %s defined twice", name);
1827 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1828 filter->type = FILTERTYPE_DROPSHADOW;
1829 filter->color= color;
1830 filter->blurx = blurx;
1831 filter->blury = blury;
1832 filter->strength = strength;
1833 filter->angle = angle;
1834 filter->distance = distance;
1835 filter->innershadow = innershadow;
1836 filter->knockout = knockout;
1837 filter->composite = composite;
1838 filter->passes = passes;
1840 dictionary_put2(&filters, name, filter);
1843 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)
1845 if(dictionary_lookup(&filters, name))
1846 syntaxerror("filter %s defined twice", name);
1849 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1850 filter->type = FILTERTYPE_BEVEL;
1851 filter->shadow = shadow;
1852 filter->highlight = highlight;
1853 filter->blurx = blurx;
1854 filter->blury = blury;
1855 filter->strength = strength;
1856 filter->angle = angle;
1857 filter->distance = distance;
1858 filter->innershadow = innershadow;
1859 filter->knockout = knockout;
1860 filter->composite = composite;
1861 filter->ontop = ontop;
1862 filter->passes = passes;
1864 dictionary_put2(&filters, name, filter);
1867 void s_blur(char*name, double blurx, double blury, int passes)
1869 if(dictionary_lookup(&filters, name))
1870 syntaxerror("filter %s defined twice", name);
1872 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1873 filter->type = FILTERTYPE_BLUR;
1874 filter->blurx = blurx;
1875 filter->blury = blury;
1876 filter->passes = passes;
1878 dictionary_put2(&filters, name, filter);
1881 void s_action(const char*text)
1884 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1888 syntaxerror("Couldn't compile ActionScript");
1891 tag = swf_InsertTag(tag, ST_DOACTION);
1893 swf_ActionSet(tag, a);
1898 void s_initaction(const char*character, const char*text)
1902 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1906 syntaxerror("Couldn't compile ActionScript");
1909 c = (character_t*)dictionary_lookup(&characters, character);
1911 tag = swf_InsertTag(tag, ST_DOINITACTION);
1912 swf_SetU16(tag, c->id);
1913 swf_ActionSet(tag, a);
1918 int s_swf3action(char*name, char*action)
1921 instance_t* object = 0;
1923 object = (instance_t*)dictionary_lookup(&instances, name);
1924 if(!object && name && *name) {
1925 /* we have a name, but couldn't find it. Abort. */
1928 a = action_SetTarget(0, name);
1929 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1930 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1931 else if(!strcmp(action, "stop")) a = action_Stop(a);
1932 else if(!strcmp(action, "play")) a = action_Play(a);
1933 a = action_SetTarget(a, "");
1936 tag = swf_InsertTag(tag, ST_DOACTION);
1937 swf_ActionSet(tag, a);
1942 void s_outline(char*name, char*format, char*source)
1944 if(dictionary_lookup(&outlines, name))
1945 syntaxerror("outline %s defined twice", name);
1954 //swf_Shape10DrawerInit(&draw, 0);
1955 swf_Shape11DrawerInit(&draw, 0);
1957 draw_string(&draw, source);
1959 shape = swf_ShapeDrawerToShape(&draw);
1960 bounds = swf_ShapeDrawerGetBBox(&draw);
1961 draw.dealloc(&draw);
1963 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1964 outline->shape = shape;
1965 outline->bbox = bounds;
1967 dictionary_put2(&outlines, name, outline);
1970 int s_playsound(char*name, int loops, int nomultiple, int stop)
1976 sound = dictionary_lookup(&sounds, name);
1980 tag = swf_InsertTag(tag, ST_STARTSOUND);
1981 swf_SetU16(tag, sound->id); //id
1982 memset(&info, 0, sizeof(info));
1985 info.nomultiple = nomultiple;
1986 swf_SetSoundInfo(tag, &info);
1990 void s_includeswf(char*name, char*filename)
1998 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1999 f = open(filename,O_RDONLY|O_BINARY);
2001 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
2002 s_box(name, 0, 0, black, 20, 0);
2005 if (swf_ReadSWF(f,&swf)<0) {
2006 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
2007 s_box(name, 0, 0, black, 20, 0);
2012 /* FIXME: The following sets the bounding Box for the character.
2013 It is wrong for two reasons:
2014 a) It may be too small (in case objects in the movie clip at the borders)
2015 b) it may be too big (because the poor movie never got autocropped)
2019 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2020 swf_SetU16(tag, id);
2021 swf_SetU16(tag, swf.frameCount);
2023 swf_Relocate(&swf, idmap);
2025 ftag = swf.firstTag;
2029 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2030 if(cutout[t] == ftag->id) {
2034 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2036 if(ftag->id == ST_END)
2041 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2042 /* We simply dump all tags right after the sprite
2043 header, relying on the fact that swf_OptimizeTagOrder() will
2044 sort things out for us later.
2045 We also rely on the fact that the imported SWF is well-formed.
2047 tag = swf_InsertTag(tag, ftag->id);
2048 swf_SetBlock(tag, ftag->data, ftag->len);
2054 syntaxerror("Included file %s contains errors", filename);
2055 tag = swf_InsertTag(tag, ST_END);
2059 s_addcharacter(name, id, tag, r);
2062 SRECT s_getCharBBox(char*name)
2064 character_t* c = dictionary_lookup(&characters, name);
2065 if(!c) syntaxerror("character '%s' unknown(2)", name);
2068 SRECT s_getInstanceBBox(char*name)
2070 instance_t * i = dictionary_lookup(&instances, name);
2072 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2074 if(!c) syntaxerror("internal error(5)");
2077 void s_getParameters(char*name, parameters_t* p)
2079 instance_t * i = dictionary_lookup(&instances, name);
2081 syntaxerror("instance '%s' unknown(10)", name);
2082 if (change_sets_all)
2083 readParameters(i->history, p, currentframe);
2088 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2090 history_begin(i->history, "x", currentframe, tag, p->x);
2091 history_begin(i->history, "y", currentframe, tag, p->y);
2092 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2093 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2094 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2095 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2096 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2097 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2098 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2099 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2100 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2101 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2102 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2103 history_begin(i->history, "shear", currentframe, tag, p->shear);
2104 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2105 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2106 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2107 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2108 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2109 history_beginFilter(i->history, currentframe, tag, p->filters);
2110 history_begin(i->history, "flags", currentframe, tag, 0);
2113 void s_startclip(char*instance, char*character, parameters_t p)
2115 character_t* c = dictionary_lookup(&characters, character);
2119 syntaxerror("character %s not known", character);
2121 i = s_addinstance(instance, c, currentdepth);
2123 m = s_instancepos(i->character->size, &p);
2125 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2126 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2127 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2129 stack[stackpos].tag = tag;
2130 stack[stackpos].type = 2;
2133 setStartparameters(i, &p, tag);
2140 swf_SetTagPos(stack[stackpos].tag, 0);
2141 swf_GetPlaceObject(stack[stackpos].tag, &p);
2142 p.clipdepth = currentdepth;
2144 swf_ClearTag(stack[stackpos].tag);
2145 swf_SetPlaceObject(stack[stackpos].tag, &p);
2149 void s_put(char*instance, char*character, parameters_t p)
2151 character_t* c = dictionary_lookup(&characters, character);
2155 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2157 i = s_addinstance(instance, c, currentdepth);
2159 m = s_instancepos(i->character->size, &p);
2161 if(p.blendmode || p.filters)
2163 if(stack[0].swf->fileVersion < 8)
2166 warning("blendmodes only supported for flash version>=8");
2168 warning("filters only supported for flash version>=8");
2170 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2173 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2174 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2175 setStartparameters(i, &p, tag);
2179 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2182 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2184 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2185 if (p.set & SF_SCALEX)
2186 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2187 if (p.set & SF_SCALEY)
2188 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2189 if (p.set & SF_CX_R)
2191 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2192 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2194 if (p.set & SF_CX_G)
2196 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2197 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2199 if (p.set & SF_CX_B)
2201 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2202 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2204 if (p.set & SF_CX_A)
2206 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2207 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2209 if (p.set & SF_ROTATE)
2210 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2211 if (p.set & SF_SHEAR)
2212 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2213 if (p.set & SF_PIVOT)
2215 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2216 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2220 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2221 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2223 if (p.set & SF_BLEND)
2224 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2225 if (p.set & SF_FILTER)
2226 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2229 void s_jump(char* instance, parameters_t p)
2231 instance_t* i = dictionary_lookup(&instances, instance);
2233 syntaxerror("instance %s not known", instance);
2234 recordChanges(i->history, p, CF_JUMP, 0);
2237 void s_change(char*instance, parameters_t p, interpolation_t* inter)
2239 instance_t* i = dictionary_lookup(&instances, instance);
2241 syntaxerror("instance %s not known", instance);
2242 recordChanges(i->history, p, CF_CHANGE, inter);
2245 void s_sweep(char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2247 instance_t* i = dictionary_lookup(&instances, instance);
2249 syntaxerror("instance %s not known", instance);
2250 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2253 void s_toggle(char* instance, U16 flagsOn, U16 flagsOff)
2255 instance_t* i = dictionary_lookup(&instances, instance);
2257 syntaxerror("instance %s not known", instance);
2258 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2261 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2264 void s_delinstance(char*instance)
2266 instance_t* i = dictionary_lookup(&instances, instance);
2268 syntaxerror("instance %s not known", instance);
2270 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2271 swf_SetU16(tag, i->depth);
2272 dictionary_del(&instances, instance);
2275 void s_schange(char*instance, parameters_t p, interpolation_t* inter)
2277 instance_t* i = dictionary_lookup(&instances, instance);
2279 syntaxerror("instance %s not known", instance);
2280 recordChanges(i->history, p, CF_SCHANGE, inter);
2286 syntaxerror(".end unexpected");
2287 switch (stack[stackpos-1].type)
2302 syntaxerror("internal error 1");
2306 // ------------------------------------------------------------------------
2308 typedef int command_func_t(map_t*args);
2310 SRECT parseBox(char*str)
2312 SRECT r = {0,0,0,0};
2313 float xmin, xmax, ymin, ymax;
2314 char*x = strchr(str, 'x');
2316 if(!strcmp(str, "autocrop")) {
2317 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2321 d1 = strchr(x+1, ':');
2323 d2 = strchr(d1+1, ':');
2325 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2329 else if(d1 && !d2) {
2330 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2336 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2341 r.xmin = (SCOORD)(xmin*20);
2342 r.ymin = (SCOORD)(ymin*20);
2343 r.xmax = (SCOORD)(xmax*20);
2344 r.ymax = (SCOORD)(ymax*20);
2347 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2350 float parseFloat(char*str)
2354 int parseInt(char*str)
2359 if(str[0]=='+' || str[0]=='-')
2363 if(str[t]<'0' || str[t]>'9')
2364 syntaxerror("Not an Integer: \"%s\"", str);
2367 static double parseRawTwip(char*str)
2371 if(str[0]=='+' || str[0]=='-') {
2376 dot = strchr(str, '.');
2380 return sign*parseInt(str);
2382 char* old = strdup(str);
2383 int l=strlen(dot+1);
2386 for(s=str;s<dot-1;s++) {
2387 if(*s<'0' || *s>'9')
2390 syntaxerror("Not a coordinate: \"%s\"", str);
2394 if(*s<'0' || *s>'9')
2397 syntaxerror("Not a coordinate: \"%s\"", str);
2400 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2401 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2404 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2408 return sign*(atoi(str));
2410 return sign*(atoi(str)+0.1*atoi(dot));
2412 return sign*(atoi(str)+0.01*atoi(dot));
2417 static dictionary_t defines;
2418 static int defines_initialized = 0;
2419 static mem_t define_values;
2421 static double parseNameOrTwip(char*s)
2425 if(defines_initialized) {
2426 l = (int)dictionary_lookup(&defines, s);
2429 return *(int*)&define_values.buffer[l-1];
2431 return parseRawTwip(s);
2435 /* automatically generated by yiyiyacc, http://www.quiss.org/yiyiyacc/ */
2436 static double parseExpression(char*s)
2439 memset(chr2index, -1, sizeof(chr2index));
2446 chr2index['\0'] = 7;
2454 int left[10]={11,8,8,8,8,9,9,9,10,10}; //production left side
2455 int plen[10]={1,3,2,3,1,3,3,1,1,3}; //production size
2456 int table[18][12] = {
2457 {0, 4, 0, 0, 5, 6, 0, 0, 1, 2, 3, 0},
2458 {7, 8, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0},
2459 {-4, -4, 9, 10, 0, 0, -4, -4, 0, 0, 0, 0},
2460 {-7, -7, -7, -7, 0, 0, -7, -7, 0, 0, 0, 0},
2461 {0, 0, 0, 0, 5, 6, 0, 0, 0, 11, 3, 0},
2462 {-8, -8, -8, -8, 0, 0, -8, -8, 0, 0, 0, 0},
2463 {0, 4, 0, 0, 5, 6, 0, 0, 12, 2, 3, 0},
2464 {0, 0, 0, 0, 5, 6, 0, 0, 0, 13, 3, 0},
2465 {0, 0, 0, 0, 5, 6, 0, 0, 0, 14, 3, 0},
2466 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 15, 0},
2467 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 16, 0},
2468 {-2, -2, 9, 10, 0, 0, -2, -2, 0, 0, 0, 0},
2469 {7, 8, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0},
2470 {-1, -1, 9, 10, 0, 0, -1, -1, 0, 0, 0, 0},
2471 {-3, -3, 9, 10, 0, 0, -3, -3, 0, 0, 0, 0},
2472 {-5, -5, -5, -5, 0, 0, -5, -5, 0, 0, 0, 0},
2473 {-6, -6, -6, -6, 0, 0, -6, -6, 0, 0, 0, 0},
2474 {-9, -9, -9, -9, 0, 0, -9, -9, 0, 0, 0, 0}};
2482 fprintf(stderr, "Error in expression\n");
2486 if(chr2index[*p]<0) {
2487 action = table[stack[stackpos-1]][4];
2489 while(chr2index[*pnext]<0)
2493 value = parseNameOrTwip(p);
2497 action = table[stack[stackpos-1]][chr2index[*p]];
2500 if(action == accept) {
2501 return values[stack[stackpos-1]];
2502 } else if(action>0) { // shift
2504 fprintf(stderr, "Stack overflow while parsing expression\n");
2507 values[stackpos]=value;
2508 stack[stackpos++]=action;
2510 } else if(action<0) { // reduce
2511 stackpos-=plen[-action];
2512 stack[stackpos] = table[stack[stackpos-1]][left[-action]];
2515 values[stackpos] = values[stackpos+0] + values[stackpos+2];
2518 values[stackpos] = 0 - values[stackpos+1];
2521 values[stackpos] = values[stackpos+0] - values[stackpos+2];
2524 values[stackpos] = values[stackpos+0] * values[stackpos+2];
2527 values[stackpos] = values[stackpos+0] / values[stackpos+2];
2530 values[stackpos] = values[stackpos+1];
2535 fprintf(stderr, "Syntax error in expression\n");
2541 int parseTwip(char*str)
2543 int v = (int)(parseExpression(str)*20);
2547 int parseArc(char* str)
2549 if (!strcmp(str, "short"))
2551 if (!strcmp(str, "long"))
2553 syntaxerror("invalid value for the arc parameter: %s", str);
2557 int parseDir(char* str)
2559 if (!strcmp(str, "clockwise"))
2561 if (!strcmp(str, "counterclockwise"))
2563 syntaxerror("invalid value for the dir parameter: %s", str);
2567 int isPoint(char*str)
2569 if(strchr(str, '('))
2575 SPOINT parsePoint(char*str)
2579 int l = strlen(str);
2580 char*comma = strchr(str, ',');
2581 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2582 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2583 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2584 p.x = parseTwip(tmp);
2585 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2586 p.y = parseTwip(tmp);
2590 int parseColor2(char*str, RGBA*color)
2592 int l = strlen(str);
2596 struct {unsigned char r,g,b;char*name;} colors[] =
2597 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2598 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2599 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2600 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2601 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2602 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2603 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2604 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2605 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2606 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2607 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2608 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2612 if(str[0]=='#' && (l==7 || l==9)) {
2613 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2615 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2617 color->r = r; color->g = g; color->b = b; color->a = a;
2620 int len=strlen(str);
2622 if(strchr(str, '/')) {
2623 len = strchr(str, '/')-str;
2624 sscanf(str+len+1,"%02x", &alpha);
2626 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2627 if(!strncmp(str, colors[t].name, len)) {
2632 color->r = r; color->g = g; color->b = b; color->a = a;
2638 RGBA parseColor(char*str)
2641 if(!parseColor2(str, &c))
2642 syntaxerror("Expression '%s' is not a color", str);
2646 typedef struct _muladd {
2651 MULADD parseMulAdd(char*str)
2654 char* str2 = (char*)malloc(strlen(str)+5);
2661 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2662 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2663 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2664 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2665 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2666 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2667 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2668 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2669 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2670 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2672 syntaxerror("'%s' is not a valid color transform expression", str);
2674 m.add = (int)(add*256);
2675 m.mul = (int)(mul*256);
2680 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2682 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2683 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2685 if(a<-32768) a=-32768;
2686 if(a>32767) a=32767;
2687 if(m<-32768) m=-32768;
2688 if(m>32767) m=32767;
2694 float parsePxOrPercent(char*fontname, char*str)
2696 int l = strlen(str);
2697 if(strchr(str, '%'))
2698 return parsePercent(str);
2699 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2700 float p = atof(str);
2701 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2703 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2707 float parsePercent(char*str)
2709 int l = strlen(str);
2713 return atoi(str)/100.0;
2715 syntaxerror("Expression '%s' is not a percentage", str);
2718 int isPercent(char*str)
2720 return str[strlen(str)-1]=='%';
2722 int parseNewSize(char*str, int size)
2725 return parsePercent(str)*size;
2727 return (int)(atof(str)*20);
2730 int isColor(char*str)
2733 return parseColor2(str, &c);
2736 static char* lu(map_t* args, char*name)
2738 char* value = map_lookup(args, name);
2740 map_dump(args, stdout, "");
2741 syntaxerror("internal error 2: value %s should be set", name);
2746 static int c_flash(map_t*args)
2748 char* filename = map_lookup(args, "filename");
2749 char* compressstr = lu(args, "compress");
2750 char* change_modestr = lu(args, "change-sets-all");
2751 char* exportstr = lu(args, "export");
2752 SRECT bbox = parseBox(lu(args, "bbox"));
2753 int version = parseInt(lu(args, "version"));
2754 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2755 RGBA color = parseColor(lu(args, "background"));
2758 if(!filename || !*filename) {
2759 /* for compatibility */
2760 filename = map_lookup(args, "name");
2761 if(!filename || !*filename) {
2764 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2765 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2769 if(!filename || override_outputname)
2770 filename = outputname;
2772 if(!strcmp(compressstr, "default"))
2773 compress = version>=6;
2774 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2776 else if(!strcmp(compressstr, "no"))
2778 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2780 if(!strcmp(change_modestr, "yes"))
2781 change_sets_all = 1;
2783 if(strcmp(change_modestr, "no"))
2784 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2786 do_exports=atoi(exportstr);
2788 s_swf(filename, bbox, version, fps, compress, color);
2791 int isRelative(char*str)
2793 return !strncmp(str, "<plus>", 6) ||
2794 !strncmp(str, "<minus>", 7);
2796 char* getOffset(char*str)
2798 if(!strncmp(str, "<plus>", 6))
2800 if(!strncmp(str, "<minus>", 7))
2802 syntaxerror("internal error (347)");
2805 int getSign(char*str)
2807 if(!strncmp(str, "<plus>", 6))
2809 if(!strncmp(str, "<minus>", 7))
2811 syntaxerror("internal error (348)");
2815 static dictionary_t points;
2816 static mem_t mpoints;
2817 static int points_initialized = 0;
2819 static int c_interpolation(map_t *args)
2822 char* name = lu(args, "name");
2823 if (dictionary_lookup(&interpolations, name))
2824 syntaxerror("interpolation %s defined twice", name);
2826 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2827 char* functionstr = lu(args, "function");
2828 inter->function = 0;
2829 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2830 if (!strcmp(functionstr,interpolationFunctions[i]))
2832 inter->function = i + 1;
2835 if (!inter->function)
2836 syntaxerror("unkown interpolation function %s", functionstr);
2837 inter->speed = parseFloat(lu(args, "speed"));
2838 inter->amplitude = parseTwip(lu(args, "amplitude"));
2839 inter->growth = parseFloat(lu(args, "growth"));
2840 inter->bounces = parseInt(lu(args, "bounces"));
2841 inter->damping = parseFloat(lu(args, "damping"));
2842 inter->slope = parseFloat(lu(args, "slope"));
2844 dictionary_put2(&interpolations, name, inter);
2848 SPOINT getPoint(SRECT r, char*name)
2851 if(!strcmp(name, "center")) {
2853 p.x = (r.xmin + r.xmax)/2;
2854 p.y = (r.ymin + r.ymax)/2;
2857 if (!strcmp(name, "bottom-center")) {
2859 p.x = (r.xmin + r.xmax)/2;
2863 if (!strcmp(name, "top-center")) {
2865 p.x = (r.xmin + r.xmax)/2;
2869 if (!strcmp(name, "top-left")) {
2875 if (!strcmp(name, "top-right")) {
2881 if (!strcmp(name, "bottom-right")) {
2887 if (!strcmp(name, "bottom-left")) {
2893 if (!strcmp(name, "left-center")) {
2896 p.y = (r.ymin + r.ymax)/2;
2899 if (!strcmp(name, "right-center")) {
2902 p.y = (r.ymin + r.ymax)/2;
2907 if(points_initialized)
2908 l = (int)dictionary_lookup(&points, name);
2910 syntaxerror("Invalid point: \"%s\".", name);
2912 return *(SPOINT*)&mpoints.buffer[l-1];
2916 static int texture2(char*name, char*object, map_t*args, int errors)
2919 char*xstr = map_lookup(args, "x");
2920 char*ystr = map_lookup(args, "y");
2921 char*widthstr = map_lookup(args, "width");
2922 char*heightstr = map_lookup(args, "height");
2923 char*scalestr = map_lookup(args, "scale");
2924 char*scalexstr = map_lookup(args, "scalex");
2925 char*scaleystr = map_lookup(args, "scaley");
2926 char*rotatestr = map_lookup(args, "rotate");
2927 char* shearstr = map_lookup(args, "shear");
2928 char* radiusstr = map_lookup(args, "r");
2930 float scalex = 1.0, scaley = 1.0;
2931 float rotate=0, shear=0;
2933 if(!*xstr && !*ystr) {
2935 syntaxerror("x and y must be set");
2938 if(*scalestr && (*scalexstr || *scaleystr)) {
2939 syntaxerror("scale and scalex/scaley can't both be set");
2942 if((*widthstr || *heightstr) && *radiusstr) {
2943 syntaxerror("width/height and radius can't both be set");
2946 widthstr = radiusstr;
2947 heightstr = radiusstr;
2949 if(!*xstr) xstr="0";
2950 if(!*ystr) ystr="0";
2951 if(!*rotatestr) rotatestr="0";
2952 if(!*shearstr) shearstr="0";
2955 scalex = scaley = parsePercent(scalestr);
2956 } else if(*scalexstr || *scaleystr) {
2957 if(scalexstr) scalex = parsePercent(scalexstr);
2958 if(scaleystr) scaley = parsePercent(scaleystr);
2959 } else if(*widthstr || *heightstr) {
2962 s_getBitmapSize(object, &width, &height);
2964 scalex = (float)parseTwip(widthstr)/(float)width;
2966 scaley = (float)parseTwip(heightstr)/(float)height;
2968 x = parseTwip(xstr);
2969 y = parseTwip(ystr);
2970 rotate = parseFloat(rotatestr);
2971 shear = parseFloat(shearstr);
2973 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2978 static int c_texture(map_t*args)
2980 char*name = lu(args, "instance");
2981 char*object = lu(args, "character");
2982 return texture2(name, object, args, 1);
2985 static int c_gradient(map_t*args)
2987 char*name = lu(args, "name");
2988 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2989 int rotate = parseInt(lu(args, "rotate"));
2993 syntaxerror("colon (:) expected");
2995 if(dictionary_lookup(&gradients, name))
2996 syntaxerror("gradient %s defined twice", name);
2998 s_gradient(name, text, radial, rotate);
3000 /* check whether we also have placement information,
3001 which would make this a positioned gradient.
3002 If there is placement information, texture2() will
3003 add a texture, which has priority over the gradient.
3005 texture2(name, name, args, 0);
3009 static char* checkFiltername(map_t* args)
3011 char* name = lu(args, "name");
3012 if (strchr(name, ','))
3013 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
3017 static int c_blur(map_t*args)
3019 char*name = checkFiltername(args);
3020 char*blurstr = lu(args, "blur");
3021 char*blurxstr = lu(args, "blurx");
3022 char*blurystr = lu(args, "blury");
3023 float blurx=1.0, blury=1.0;
3025 blurx = parseFloat(blurstr);
3026 blury = parseFloat(blurstr);
3029 blurx = parseFloat(blurxstr);
3031 blury = parseFloat(blurystr);
3032 int passes = parseInt(lu(args, "passes"));
3033 s_blur(name, blurx, blury, passes);
3037 static int c_gradientglow(map_t*args)
3039 char*name = checkFiltername(args);
3040 char*gradient = lu(args, "gradient");
3041 char*blurstr = lu(args, "blur");
3042 char*blurxstr = lu(args, "blurx");
3043 char*blurystr = lu(args, "blury");
3044 float blurx=1.0, blury=1.0;
3046 blurx = parseFloat(blurstr);
3047 blury = parseFloat(blurstr);
3050 blurx = parseFloat(blurxstr);
3052 blury = parseFloat(blurystr);
3054 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3055 float distance = parseFloat(lu(args, "distance"));
3056 float strength = parseFloat(lu(args, "strength"));
3057 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3058 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3059 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3060 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3061 int passes = parseInt(lu(args, "passes"));
3063 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3067 static int c_dropshadow(map_t*args)
3069 char*name = checkFiltername(args);
3070 RGBA color = parseColor(lu(args, "color"));
3071 char*blurstr = lu(args, "blur");
3072 char*blurxstr = lu(args, "blurx");
3073 char*blurystr = lu(args, "blury");
3074 float blurx=1.0, blury=1.0;
3076 blurx = parseFloat(blurstr);
3077 blury = parseFloat(blurstr);
3080 blurx = parseFloat(blurxstr);
3082 blury = parseFloat(blurystr);
3084 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3085 float distance = parseFloat(lu(args, "distance"));
3086 float strength = parseFloat(lu(args, "strength"));
3087 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3088 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3089 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3090 int passes = parseInt(lu(args, "passes"));
3092 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3096 static int c_bevel(map_t*args)
3098 char*name = checkFiltername(args);
3099 RGBA shadow = parseColor(lu(args, "shadow"));
3100 RGBA highlight = parseColor(lu(args, "highlight"));
3101 char*blurstr = lu(args, "blur");
3102 char*blurxstr = lu(args, "blurx");
3103 char*blurystr = lu(args, "blury");
3104 float blurx=1.0, blury=1.0;
3106 blurx = parseFloat(blurstr);
3107 blury = parseFloat(blurstr);
3110 blurx = parseFloat(blurxstr);
3112 blury = parseFloat(blurystr);
3114 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3115 float distance = parseFloat(lu(args, "distance"));
3116 float strength = parseFloat(lu(args, "strength"));
3117 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3118 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3119 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3120 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3121 int passes = parseInt(lu(args, "passes"));
3123 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3127 static int c_define(map_t*args)
3129 char*name = lu(args, "name");
3130 char*value = lu(args, "value");
3132 if(!defines_initialized) {
3133 dictionary_init(&defines);
3134 mem_init(&define_values);
3135 defines_initialized = 1;
3137 int val = parseTwip(value);
3138 int pos = mem_put(&define_values, &val, sizeof(val));
3140 string_set(&s, name);
3141 dictionary_put(&defines, s, (void*)(pos+1));
3144 static int c_point(map_t*args)
3146 char*name = lu(args, "name");
3150 if(!points_initialized) {
3151 dictionary_init(&points);
3153 points_initialized = 1;
3155 p.x = parseTwip(lu(args, "x"));
3156 p.y = parseTwip(lu(args, "y"));
3157 pos = mem_put(&mpoints, &p, sizeof(p));
3158 string_set(&s1, name);
3159 dictionary_put(&points, s1, (void*)(pos+1));
3162 static int c_play(map_t*args)
3164 char*name = lu(args, "name");
3165 char*loop = lu(args, "loop");
3166 char*nomultiple = lu(args, "nomultiple");
3168 if(!strcmp(nomultiple, "nomultiple"))
3171 nm = parseInt(nomultiple);
3173 if(s_playsound(name, parseInt(loop), nm, 0)) {
3175 } else if(s_swf3action(name, "play")) {
3181 static int c_stop(map_t*args)
3183 char*name = map_lookup(args, "name");
3185 if(s_playsound(name, 0,0,1))
3187 else if(s_swf3action(name, "stop"))
3189 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3193 static int c_nextframe(map_t*args)
3195 char*name = lu(args, "name");
3197 if(s_swf3action(name, "nextframe")) {
3200 syntaxerror("I don't know anything about movie \"%s\"", name);
3204 static int c_previousframe(map_t*args)
3206 char*name = lu(args, "name");
3208 if(s_swf3action(name, "previousframe")) {
3211 syntaxerror("I don't know anything about movie \"%s\"", name);
3215 static int c_movement(map_t*args, int type)
3217 char*instance = lu(args, "name");
3225 xstr = lu(args, "x");
3226 ystr = lu(args, "y");
3228 s_getParameters(instance, &p);
3233 if(isRelative(xstr))
3235 if(type == PT_PUT || type == PT_STARTCLIP)
3236 syntaxerror("relative x values not allowed for initial put or startclip");
3237 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3241 p.x = parseTwip(xstr);
3247 if(isRelative(ystr))
3249 if(type == PT_PUT || type == PT_STARTCLIP)
3250 syntaxerror("relative y values not allowed for initial put or startclip");
3251 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3255 p.y = parseTwip(ystr);
3260 if (change_sets_all)
3268 char* interstr = lu(args, "interpolation");
3269 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3271 syntaxerror("unkown interpolation %s", interstr);
3272 s_change(instance, p, inter);
3277 char* interstr = lu(args, "interpolation");
3278 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3280 syntaxerror("unkown interpolation %s", interstr);
3281 s_schange(instance, p, inter);
3286 char* rstr = lu(args, "r");
3287 int radius = parseTwip(rstr);
3289 syntaxerror("sweep not possible: radius must be greater than 0.");
3290 char* dirstr = lu(args, "dir");
3291 int clockwise = parseDir(dirstr);
3292 char* arcstr = lu(args, "arc");
3293 int short_arc = parseArc(arcstr);
3294 char* interstr = lu(args, "interpolation");
3295 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3297 syntaxerror("unkown interpolation %s", interstr);
3298 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3305 static int c_placement(map_t*args, int type)
3307 char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3310 char* luminancestr = lu(args, "luminance");
3311 char* scalestr = lu(args, "scale");
3312 char* scalexstr = lu(args, "scalex");
3313 char* scaleystr = lu(args, "scaley");
3314 char* rotatestr = lu(args, "rotate");
3315 char* shearstr = lu(args, "shear");
3316 char* xstr="", *pivotstr="";
3317 char* ystr="", *anglestr="";
3318 char*above = lu(args, "above"); /*FIXME*/
3319 char*below = lu(args, "below");
3320 char* rstr = lu(args, "red");
3321 char* gstr = lu(args, "green");
3322 char* bstr = lu(args, "blue");
3323 char* astr = lu(args, "alpha");
3324 char* pinstr = lu(args, "pin");
3325 char* as = map_lookup(args, "as");
3326 char* blendmode = lu(args, "blend");
3327 char* filterstr = lu(args, "filter");
3338 { // (?) .rotate or .arcchange
3339 pivotstr = lu(args, "pivot");
3340 anglestr = lu(args, "angle");
3344 xstr = lu(args, "x");
3345 ystr = lu(args, "y");
3349 luminance = parseMulAdd(luminancestr);
3353 luminance.mul = 256;
3358 if(scalexstr[0]||scaleystr[0])
3359 syntaxerror("scalex/scaley and scale cannot both be set");
3360 scalexstr = scaleystr = scalestr;
3363 if(type == PT_PUT || type == PT_STARTCLIP) {
3365 character = lu(args, "character");
3366 parameters_clear(&p);
3367 } else if (type == PT_BUTTON) {
3368 character = lu(args, "name");
3369 parameters_clear(&p);
3372 s_getParameters(instance, &p);
3378 if(isRelative(xstr))
3380 if(type == PT_PUT || type == PT_STARTCLIP)
3381 syntaxerror("relative x values not allowed for initial put or startclip");
3382 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3386 p.x = parseTwip(xstr);
3392 if(isRelative(ystr))
3394 if(type == PT_PUT || type == PT_STARTCLIP)
3395 syntaxerror("relative y values not allowed for initial put or startclip");
3396 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3400 p.y = parseTwip(ystr);
3405 /* scale, scalex, scaley */
3407 oldbbox = s_getCharBBox(character);
3409 oldbbox = s_getInstanceBBox(instance);
3410 oldwidth = oldbbox.xmax - oldbbox.xmin;
3411 oldheight = oldbbox.ymax - oldbbox.ymin;
3418 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3419 set = set | SF_SCALEX;
3427 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3428 set = set | SF_SCALEY;
3434 if(isRelative(rotatestr))
3435 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3437 p.rotate = parseFloat(rotatestr);
3438 set = set | SF_ROTATE;
3444 if(isRelative(shearstr))
3445 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3447 p.shear = parseFloat(shearstr);
3448 set = set | SF_SHEAR;
3453 if(isPoint(pivotstr))
3454 p.pivot = parsePoint(pivotstr);
3456 p.pivot = getPoint(oldbbox, pivotstr);
3457 set = set | SF_PIVOT;
3463 p.pin = parsePoint(pinstr);
3465 p.pin = getPoint(oldbbox, pinstr);
3469 /* color transform */
3471 if(rstr[0] || luminancestr[0])
3475 r = parseMulAdd(rstr);
3478 r.add = p.cxform.r0;
3479 r.mul = p.cxform.r1;
3481 r = mergeMulAdd(r, luminance);
3482 p.cxform.r0 = r.mul;
3483 p.cxform.r1 = r.add;
3484 set = set | SF_CX_R;
3486 if(gstr[0] || luminancestr[0])
3490 g = parseMulAdd(gstr);
3493 g.add = p.cxform.g0;
3494 g.mul = p.cxform.g1;
3496 g = mergeMulAdd(g, luminance);
3497 p.cxform.g0 = g.mul;
3498 p.cxform.g1 = g.add;
3499 set = set | SF_CX_G;
3501 if(bstr[0] || luminancestr[0])
3505 b = parseMulAdd(bstr);
3508 b.add = p.cxform.b0;
3509 b.mul = p.cxform.b1;
3511 b = mergeMulAdd(b, luminance);
3512 p.cxform.b0 = b.mul;
3513 p.cxform.b1 = b.add;
3514 set = set | SF_CX_B;
3518 MULADD a = parseMulAdd(astr);
3519 p.cxform.a0 = a.mul;
3520 p.cxform.a1 = a.add;
3521 set = set | SF_CX_A;
3528 for(t = 0; blendModeNames[t]; t++)
3530 if(!strcmp(blendModeNames[t], blendmode))
3538 syntaxerror("unknown blend mode: '%s'", blendmode);
3540 p.blendmode = blend;
3541 set = set | SF_BLEND;
3546 p.filters = parseFilters(filterstr);
3547 set = set | SF_FILTER;
3550 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3551 warning("As of version 0.8.2 using the .change command to modify an \
3552 object's position on the stage is considered deprecated. Future \
3553 versions may consider x and y parameters for the .change command \
3554 to be illegal; please use the .move command.");
3556 if (change_sets_all)
3563 s_put(instance, character, p);
3567 char* interstr = lu(args, "interpolation");
3568 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3570 syntaxerror("unkown interpolation %s", interstr);
3571 s_change(instance, p, inter);
3576 char* interstr = lu(args, "interpolation");
3577 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3579 syntaxerror("unkown interpolation %s", interstr);
3580 s_schange(instance, p, inter);
3584 s_jump(instance, p);
3587 s_startclip(instance, character, p);
3591 s_buttonput(character, as, p);
3593 s_buttonput(character, "shape", p);
3599 static int c_put(map_t*args)
3601 c_placement(args, PT_PUT);
3604 static int c_change(map_t*args)
3606 if (currentframe == 0)
3607 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3608 c_placement(args, PT_CHANGE);
3611 static int c_schange(map_t*args)
3613 c_placement(args, PT_SCHANGE);
3616 static int c_move(map_t* args)
3618 c_movement(args, PT_MOVE);
3621 static int c_smove(map_t* args)
3623 c_movement(args, PT_SMOVE);
3626 static int c_sweep(map_t* args)
3628 c_movement(args, PT_SWEEP);
3631 static int c_arcchange(map_t*args)
3633 c_placement(args, 0);
3636 static int c_jump(map_t*args)
3638 c_placement(args, PT_JUMP);
3641 static int c_startclip(map_t*args)
3643 c_placement(args, PT_STARTCLIP);
3646 static int c_show(map_t*args)
3648 c_placement(args, PT_BUTTON);
3651 static int c_toggle(map_t* args)
3653 char*instance = lu(args, "name");
3654 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3655 char* alignstr = lu(args, "fixed_alignment");
3656 if (!strcmp(alignstr, "on"))
3657 flagsOn += IF_FIXED_ALIGNMENT;
3659 if (!strcmp(alignstr, "off"))
3660 flagsOff -= IF_FIXED_ALIGNMENT;
3662 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3663 s_toggle(instance, flagsOn, flagsOff);
3666 static int c_del(map_t*args)
3668 char*instance = lu(args, "name");
3669 s_delinstance(instance);
3672 static int c_end(map_t*args)
3677 static int c_sprite(map_t*args)
3679 char* name = lu(args, "name");
3680 char* scalinggrid = lu(args, "scalinggrid");
3682 if(scalinggrid && *scalinggrid) {
3683 SRECT r = parseBox(scalinggrid);
3690 static int c_frame(map_t*args)
3692 char*framestr = lu(args, "n");
3693 char*cutstr = lu(args, "cut");
3695 char*name = lu(args, "name");
3696 char*anchor = lu(args, "anchor");
3699 if(!strcmp(anchor, "anchor") && !*name)
3704 if(strcmp(cutstr, "no"))
3706 if(isRelative(framestr)) {
3707 frame = s_getframe();
3708 if(getSign(framestr)<0)
3709 syntaxerror("relative frame expressions must be positive");
3710 frame += parseInt(getOffset(framestr));
3713 frame = parseInt(framestr);
3714 if(s_getframe() >= frame
3715 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3716 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3718 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3721 static int c_primitive(map_t*args)
3723 char*name = lu(args, "name");
3724 char*command = lu(args, "commandname");
3725 int width=0, height=0, r=0;
3726 int linewidth = parseTwip(lu(args, "line"));
3727 char*colorstr = lu(args, "color");
3728 RGBA color = parseColor(colorstr);
3729 char*fillstr = lu(args, "fill");
3736 if(!strcmp(command, "circle"))
3738 else if(!strcmp(command, "filled"))
3742 width = parseTwip(lu(args, "width"));
3743 height = parseTwip(lu(args, "height"));
3744 } else if (type==1) {
3745 r = parseTwip(lu(args, "r"));
3746 } else if (type==2) {
3747 outline = lu(args, "outline");
3750 if(!strcmp(fillstr, "fill"))
3752 if(!strcmp(fillstr, "none"))
3754 if(width<0 || height<0 || linewidth<0 || r<0)
3755 syntaxerror("values width, height, line, r must be positive");
3757 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3758 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3759 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3763 static int c_textshape(map_t*args)
3765 char*name = lu(args, "name");
3766 char*text = lu(args, "text");
3767 char*font = lu(args, "font");
3768 float size = parsePxOrPercent(font, lu(args, "size"));
3770 s_textshape(name, font, size, text);
3774 static int c_swf(map_t*args)
3776 char*name = lu(args, "name");
3777 char*filename = lu(args, "filename");
3778 char*command = lu(args, "commandname");
3779 if(!strcmp(command, "shape"))
3780 warning("Please use .swf instead of .shape");
3781 s_includeswf(name, filename);
3785 static int c_font(map_t*args)
3787 char*name = lu(args, "name");
3788 char*filename = lu(args, "filename");
3789 s_font(name, filename);
3793 static int c_sound(map_t*args)
3795 char*name = lu(args, "name");
3796 char*filename = lu(args, "filename");
3797 s_sound(name, filename);
3801 static int c_text(map_t*args)
3803 char*name = lu(args, "name");
3804 char*text = lu(args, "text");
3805 char*font = lu(args, "font");
3806 float size = parsePxOrPercent(font, lu(args, "size"));
3807 RGBA color = parseColor(lu(args, "color"));
3808 s_text(name, font, text, (int)(size*100), color);
3812 static int c_soundtrack(map_t*args)
3817 static int c_quicktime(map_t*args)
3819 char*name = lu(args, "name");
3820 char*url = lu(args, "url");
3821 s_quicktime(name, url);
3825 static int c_image(map_t*args)
3827 char*command = lu(args, "commandname");
3828 char*name = lu(args, "name");
3829 char*filename = lu(args, "filename");
3830 if(!strcmp(command,"jpeg")) {
3831 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3832 s_image(name, "jpeg", filename, quality);
3834 s_image(name, "png", filename, 0);
3839 static int c_outline(map_t*args)
3841 char*name = lu(args, "name");
3842 char*format = lu(args, "format");
3846 syntaxerror("colon (:) expected");
3848 s_outline(name, format, text);
3852 int fakechar(map_t*args)
3854 char*name = lu(args, "name");
3855 s_box(name, 0, 0, black, 20, 0);
3859 static int c_egon(map_t*args) {return fakechar(args);}
3860 static int c_button(map_t*args) {
3861 char*name = lu(args, "name");
3865 static int current_button_flags = 0;
3866 static int c_on_press(map_t*args)
3868 char*position = lu(args, "position");
3870 if(!strcmp(position, "inside")) {
3871 current_button_flags |= BC_OVERUP_OVERDOWN;
3872 } else if(!strcmp(position, "outside")) {
3873 //current_button_flags |= BC_IDLE_OUTDOWN;
3874 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3875 } else if(!strcmp(position, "anywhere")) {
3876 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3879 if(type == RAWDATA) {
3881 s_buttonaction(current_button_flags, action);
3882 current_button_flags = 0;
3888 static int c_on_release(map_t*args)
3890 char*position = lu(args, "position");
3892 if(!strcmp(position, "inside")) {
3893 current_button_flags |= BC_OVERDOWN_OVERUP;
3894 } else if(!strcmp(position, "outside")) {
3895 current_button_flags |= BC_OUTDOWN_IDLE;
3896 } else if(!strcmp(position, "anywhere")) {
3897 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3900 if(type == RAWDATA) {
3902 s_buttonaction(current_button_flags, action);
3903 current_button_flags = 0;
3909 static int c_on_move_in(map_t*args)
3911 char*position = lu(args, "state");
3913 if(!strcmp(position, "pressed")) {
3914 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3915 } else if(!strcmp(position, "not_pressed")) {
3916 current_button_flags |= BC_IDLE_OVERUP;
3917 } else if(!strcmp(position, "any")) {
3918 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3921 if(type == RAWDATA) {
3923 s_buttonaction(current_button_flags, action);
3924 current_button_flags = 0;
3930 static int c_on_move_out(map_t*args)
3932 char*position = lu(args, "state");
3934 if(!strcmp(position, "pressed")) {
3935 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3936 } else if(!strcmp(position, "not_pressed")) {
3937 current_button_flags |= BC_OVERUP_IDLE;
3938 } else if(!strcmp(position, "any")) {
3939 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3942 if(type == RAWDATA) {
3944 s_buttonaction(current_button_flags, action);
3945 current_button_flags = 0;
3951 static int c_on_key(map_t*args)
3953 char*key = lu(args, "key");
3955 if(strlen(key)==1) {
3958 current_button_flags |= 0x4000 + (key[0]*0x200);
3960 syntaxerror("invalid character: %c"+key[0]);
3965 <ctrl-x> = 0x200*(x-'a')
3969 syntaxerror("invalid key: %s",key);
3972 if(type == RAWDATA) {
3974 s_buttonaction(current_button_flags, action);
3975 current_button_flags = 0;
3982 static int c_edittext(map_t*args)
3984 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @autosize=0"},
3985 char*name = lu(args, "name");
3986 char*font = lu(args, "font");
3987 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3988 int width = parseTwip(lu(args, "width"));
3989 int height = parseTwip(lu(args, "height"));
3990 char*text = lu(args, "text");
3991 RGBA color = parseColor(lu(args, "color"));
3992 int maxlength = parseInt(lu(args, "maxlength"));
3993 char*variable = lu(args, "variable");
3994 char*passwordstr = lu(args, "password");
3995 char*wordwrapstr = lu(args, "wordwrap");
3996 char*multilinestr = lu(args, "multiline");
3997 char*htmlstr = lu(args, "html");
3998 char*noselectstr = lu(args, "noselect");
3999 char*readonlystr = lu(args, "readonly");
4000 char*borderstr = lu(args, "border");
4001 char*autosizestr = lu(args, "autosize");
4002 char*alignstr = lu(args, "align");
4006 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
4007 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
4008 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
4009 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
4010 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
4011 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
4012 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
4013 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
4014 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
4015 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
4016 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
4017 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
4018 else syntaxerror("Unknown alignment: %s", alignstr);
4020 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
4024 static int c_morphshape(map_t*args) {return fakechar(args);}
4025 static int c_movie(map_t*args) {return fakechar(args);}
4027 static char* readfile(const char*filename)
4029 FILE*fi = fopen(filename, "rb");
4033 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
4034 fseek(fi, 0, SEEK_END);
4036 fseek(fi, 0, SEEK_SET);
4037 text = rfx_alloc(l+1);
4038 fread(text, l, 1, fi);
4044 static int c_action(map_t*args)
4046 char* filename = map_lookup(args, "filename");
4047 if(!filename ||!*filename) {
4049 if(type != RAWDATA) {
4050 syntaxerror("colon (:) expected");
4054 s_action(readfile(filename));
4060 static int c_initaction(map_t*args)
4062 char* character = lu(args, "name");
4063 char* filename = map_lookup(args, "filename");
4064 if(!filename ||!*filename) {
4066 if(type != RAWDATA) {
4067 syntaxerror("colon (:) expected");
4069 s_initaction(character, text);
4071 s_initaction(character, readfile(filename));
4079 command_func_t* func;
4082 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1"},
4083 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
4084 // "import" type stuff
4085 {"swf", c_swf, "name filename"},
4086 {"shape", c_swf, "name filename"},
4087 {"jpeg", c_image, "name filename quality=80%"},
4088 {"png", c_image, "name filename"},
4089 {"movie", c_movie, "name filename"},
4090 {"sound", c_sound, "name filename"},
4091 {"font", c_font, "name filename glyphs="},
4092 {"soundtrack", c_soundtrack, "filename"},
4093 {"quicktime", c_quicktime, "url"},
4095 // generators of primitives
4097 {"define", c_define, "name value=0"},
4098 {"point", c_point, "name x=0 y=0"},
4099 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4100 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4101 {"outline", c_outline, "name format=simple"},
4102 {"textshape", c_textshape, "name font size=100% text"},
4105 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4106 {"gradientglow", c_gradientglow, "name gradient blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 @ontop=0 passes=1"},
4107 {"dropshadow", c_dropshadow, "name color blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 passes=1"},
4108 {"bevel", c_bevel, "name shadow highlight blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 @ontop=0 passes=1"},
4110 // character generators
4111 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4112 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4113 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4115 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4116 {"text", c_text, "name text font size=100% color=white"},
4117 {"edittext", c_edittext, "name font= size=100% width height text="" color=white maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @border=0 @autosize=0 align="},
4118 {"morphshape", c_morphshape, "name start end"},
4119 {"button", c_button, "name"},
4120 {"show", c_show, "name x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= as="},
4121 {"on_press", c_on_press, "position=inside"},
4122 {"on_release", c_on_release, "position=anywhere"},
4123 {"on_move_in", c_on_move_in, "state=not_pressed"},
4124 {"on_move_out", c_on_move_out, "state=not_pressed"},
4125 {"on_key", c_on_key, "key=any"},
4128 {"play", c_play, "name loop=0 @nomultiple=0"},
4129 {"stop", c_stop, "name= "},
4130 {"nextframe", c_nextframe, "name"},
4131 {"previousframe", c_previousframe, "name"},
4133 // object placement tags
4134 {"put", c_put, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4135 {"startclip", c_startclip, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4136 {"move", c_move, "name x= y= interpolation=linear"},
4137 {"smove", c_smove, "name x= y= interpolation=linear"},
4138 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4139 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4140 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4141 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4142 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4143 {"del", c_del, "name"},
4144 // virtual object placement
4145 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4147 {"toggle", c_toggle, "name fixed_alignment="},
4149 // commands which start a block
4150 //startclip (see above)
4151 {"sprite", c_sprite, "name scalinggrid="},
4152 {"action", c_action, "filename="},
4153 {"initaction", c_initaction, "name filename="},
4159 static map_t parseArguments(char*command, char*pattern)
4175 string_set(&t1, "commandname");
4176 string_set(&t2, command);
4177 map_put(&result, t1, t2);
4179 if(!pattern || !*pattern)
4186 if(!strncmp("<i> ", x, 3)) {
4188 if(type == COMMAND || type == RAWDATA) {
4190 syntaxerror("character name expected");
4192 name[pos].str = "instance";
4194 value[pos].str = text;
4195 value[pos].len = strlen(text);
4199 if(type == ASSIGNMENT)
4202 name[pos].str = "character";
4204 value[pos].str = text;
4205 value[pos].len = strlen(text);
4213 isboolean[pos] = (x[0] =='@');
4226 name[pos].len = d-x;
4231 name[pos].len = e-x;
4232 value[pos].str = e+1;
4233 value[pos].len = d-e-1;
4241 /* for(t=0;t<len;t++) {
4242 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4243 isboolean[t]?"(boolean)":"");
4248 if(type == RAWDATA || type == COMMAND) {
4253 // first, search for boolean arguments
4254 for(pos=0;pos<len;pos++)
4256 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4258 if(type == ASSIGNMENT)
4260 value[pos].str = text;
4261 value[pos].len = strlen(text);
4262 /*printf("setting boolean parameter %s (to %s)\n",
4263 strdup_n(name[pos], namelen[pos]),
4264 strdup_n(value[pos], valuelen[pos]));*/
4269 // second, search for normal arguments
4271 for(pos=0;pos<len;pos++)
4273 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4274 (type != ASSIGNMENT && !set[pos])) {
4276 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4278 if(type == ASSIGNMENT)
4281 value[pos].str = text;
4282 value[pos].len = strlen(text);
4284 printf("setting parameter %s (to %s)\n",
4285 strdup_n(name[pos].str, name[pos].len),
4286 strdup_n(value[pos].str, value[pos].len));
4292 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4296 for(t=0;t<len;t++) {
4297 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4300 for(t=0;t<len;t++) {
4301 if(value[t].str && value[t].str[0] == '*') {
4302 //relative default- take value from some other parameter
4304 for(s=0;s<len;s++) {
4305 if(value[s].len == value[t].len-1 &&
4306 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4307 value[t].str = value[s].str;
4310 if(value[t].str == 0) {
4312 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4316 /* ok, now construct the dictionary from the parameters */
4320 map_put(&result, name[t], value[t]);
4324 static void parseArgumentsForCommand(char*command)
4329 msg("<verbose> parse Command: %s (line %d)", command, line);
4331 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4332 if(!strcmp(arguments[t].command, command)) {
4334 /* ugly hack- will be removed soon (once documentation and .sc generating
4335 utilities have been changed) */
4336 if(!strcmp(command, "swf") && !stackpos) {
4337 warning("Please use .flash instead of .swf- this will be mandatory soon");
4342 args = parseArguments(command, arguments[t].arguments);
4348 syntaxerror("command %s not known", command);
4350 // catch missing .flash directives at the beginning of a file
4351 if(strcmp(command, "flash") && !stackpos)
4353 syntaxerror("No movie defined- use .flash first");
4357 printf(".%s\n", command);fflush(stdout);
4358 map_dump(&args, stdout, "\t");fflush(stdout);
4361 (*arguments[nr].func)(&args);
4363 /*if(!strcmp(command, "button") ||
4364 !strcmp(command, "action")) {
4367 if(type == COMMAND) {
4368 if(!strcmp(text, "end"))
4383 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4384 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4385 * No syntax checking is done */
4386 static void analyseArgumentsForCommand(char*command)
4392 U8* glyphs_to_include;
4393 msg("<verbose> analyse Command: %s (line %d)", command, line);
4395 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4397 if(!strcmp(arguments[t].command, command))
4399 args = parseArguments(command, arguments[t].arguments);
4405 printf(".%s\n", command);fflush(stdout);
4406 map_dump(&args, stdout, "\t");fflush(stdout);
4408 char* name = lu(&args, "name");
4409 if (!strcmp(command, "font"))
4411 if(dictionary_lookup(&fonts, name))
4412 syntaxerror("font %s defined twice", name);
4415 fontfile = lu(&args, "filename");
4416 font = swf_LoadFont(fontfile);
4418 warning("Couldn't open font file \"%s\"", fontfile);
4419 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4420 memset(font, 0, sizeof(SWFFONT));
4424 swf_FontPrepareForEditText(font);
4425 glyphs_to_include = lu(&args, "glyphs");
4426 if (!strcmp(glyphs_to_include, "all"))
4428 swf_FontUseAll(font);
4429 font->use->glyphs_specified = 1;
4433 if (strcmp (glyphs_to_include, ""))
4435 swf_FontUseUTF8(font, glyphs_to_include);
4436 font->use->glyphs_specified = 1;
4439 swf_FontInitUsage(font);
4442 dictionary_put2(&fonts, name, font);
4446 SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "font"));
4448 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4450 if (font->use && !font->use->glyphs_specified)
4452 if (!strcmp(command, "edittext"))
4454 swf_FontUseAll(font);
4455 font->use->glyphs_specified = 1;
4458 swf_FontUseUTF8(font, lu(&args, "text"));
4465 void skipParameters()
4469 while (type != COMMAND);
4473 void findFontUsage()
4475 char* fontRelated = "font;text;textshape;edittext;";
4476 while(!noMoreTokens())
4480 syntaxerror("command expected");
4481 if (strstr(fontRelated, text))
4482 analyseArgumentsForCommand(text);
4484 if(strcmp(text, "end"))
4493 dictionary_init(&fonts);
4494 cleanUp = &freeFontDictionary;
4498 int main (int argc,char ** argv)
4501 processargs(argc, argv);
4502 initLog(0,-1,0,0,-1,verbose);
4505 args_callback_usage(argv[0]);
4509 file = generateTokens(filename);
4511 fprintf(stderr, "parser returned error.\n");
4518 while(!noMoreTokens()) {
4521 syntaxerror("command expected");
4522 parseArgumentsForCommand(text);