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): */
194 static int stackpos = 0;
196 static dict_t characters;
197 static dict_t images;
198 static dict_t textures;
199 static dict_t outlines;
200 static dict_t gradients;
201 static dict_t filters;
202 static dict_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 dict_t instances;
212 static dict_t sounds;
213 static dict_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 dict_free_all(&instances, free_instance);
344 dict_free_all(&characters, free);
345 dict_free_all(&images, free);
346 dict_free_all(&textures, free);
347 dict_free_all(&outlines, free_outline);
348 dict_free_all(&gradients, free_gradient);
349 dict_free_all(&filters, free);
350 dict_free_all(&fonts, free_font);
351 dict_free_all(&sounds, free);
352 dict_free_all(&interpolations, free);
356 static void freeFontDictionary()
358 dict_free_all(&fonts, free_font);
361 static void incrementid()
365 syntaxerror("Out of character ids.");
370 static void s_addcharacter(const char*name, U16 id, TAG*ctag, SRECT r)
372 if(dict_lookup(&characters, name))
373 syntaxerror("character %s defined twice", name);
374 character_t* c = character_new();
376 c->definingTag = ctag;
379 dict_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(const char*name, U16 id, TAG*ctag, SRECT r)
393 if(dict_lookup(&images, name))
394 syntaxerror("image %s defined twice", name);
396 character_t* c = character_new();
397 c->definingTag = ctag;
400 dict_put2(&images, name, c);
402 static instance_t* s_addinstance(const char*name, character_t*c, U16 depth)
404 if(dict_lookup(&instances, name))
405 syntaxerror("object %s defined twice", name);
406 instance_t* i = instance_new();
409 //swf_GetMatrix(0, &i->matrix);
410 dict_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 dict_put2(&interpolations, "linear", new);
475 new = (interpolation_t*)malloc(sizeof(interpolation_t));
476 new->function = IF_QUAD_IN;
478 dict_put2(&interpolations, "quadIn", new);
479 new = (interpolation_t*)malloc(sizeof(interpolation_t));
480 new->function = IF_QUAD_OUT;
482 dict_put2(&interpolations, "quadOut", new);
483 new = (interpolation_t*)malloc(sizeof(interpolation_t));
484 new->function = IF_QUAD_IN_OUT;
486 dict_put2(&interpolations, "quadInOut", new);
488 new = (interpolation_t*)malloc(sizeof(interpolation_t));
489 new->function = IF_CUBIC_IN;
491 dict_put2(&interpolations, "cubicIn", new);
492 new = (interpolation_t*)malloc(sizeof(interpolation_t));
493 new->function = IF_CUBIC_OUT;
495 dict_put2(&interpolations, "cubicOut", new);
496 new = (interpolation_t*)malloc(sizeof(interpolation_t));
497 new->function = IF_CUBIC_IN_OUT;
499 dict_put2(&interpolations, "cubicInOut", new);
501 new = (interpolation_t*)malloc(sizeof(interpolation_t));
502 new->function = IF_QUART_IN;
504 dict_put2(&interpolations, "quartIn", new);
505 new = (interpolation_t*)malloc(sizeof(interpolation_t));
506 new->function = IF_QUART_OUT;
508 dict_put2(&interpolations, "quartOut", new);
509 new = (interpolation_t*)malloc(sizeof(interpolation_t));
510 new->function = IF_QUART_IN_OUT;
512 dict_put2(&interpolations, "quartInOut", new);
514 new = (interpolation_t*)malloc(sizeof(interpolation_t));
515 new->function = IF_QUINT_IN;
517 dict_put2(&interpolations, "quintIn", new);
518 new = (interpolation_t*)malloc(sizeof(interpolation_t));
519 new->function = IF_QUINT_OUT;
521 dict_put2(&interpolations, "quintOut", new);
522 new = (interpolation_t*)malloc(sizeof(interpolation_t));
523 new->function = IF_QUINT_IN_OUT;
525 dict_put2(&interpolations, "quintInOut", new);
527 new = (interpolation_t*)malloc(sizeof(interpolation_t));
528 new->function = IF_CIRCLE_IN;
529 dict_put2(&interpolations, "circleIn", new);
530 new = (interpolation_t*)malloc(sizeof(interpolation_t));
531 new->function = IF_CIRCLE_OUT;
532 dict_put2(&interpolations, "circleOut", new);
533 new = (interpolation_t*)malloc(sizeof(interpolation_t));
534 new->function = IF_CIRCLE_IN_OUT;
535 dict_put2(&interpolations, "circleInOut", new);
537 new = (interpolation_t*)malloc(sizeof(interpolation_t));
538 new->function = IF_EXPONENTIAL_IN;
539 dict_put2(&interpolations, "exponentialIn", new);
540 new = (interpolation_t*)malloc(sizeof(interpolation_t));
541 new->function = IF_EXPONENTIAL_OUT;
542 dict_put2(&interpolations, "exponentialOut", new);
543 new = (interpolation_t*)malloc(sizeof(interpolation_t));
544 new->function = IF_EXPONENTIAL_IN_OUT;
545 dict_put2(&interpolations, "exponentialInOut", new);
547 new = (interpolation_t*)malloc(sizeof(interpolation_t));
548 new->function = IF_SINE_IN;
549 dict_put2(&interpolations, "sineIn", new);
550 new = (interpolation_t*)malloc(sizeof(interpolation_t));
551 new->function = IF_SINE_OUT;
552 dict_put2(&interpolations, "sineOut", new);
553 new = (interpolation_t*)malloc(sizeof(interpolation_t));
554 new->function = IF_SINE_IN_OUT;
555 dict_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 dict_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 dict_put2(&filters, "no_filters", dummy);
576 noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
578 dict_put2(&filters, "no_blur", noBlur);
579 noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
581 noBevel->composite = 1;
582 dict_put2(&filters, "no_bevel", noBevel);
583 noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
584 noDropshadow->passes = 1;
585 noDropshadow->composite = 1;
586 dict_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 dict_put2(&filters, "no_gradientglow", noGradientGlow);
594 void s_swf(const 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 dict_init(&characters);
613 dict_init(&textures);
614 dict_init(&outlines);
615 dict_init(&gradients);
617 dict_init(&instances);
619 dict_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(const 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 dict_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(const 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(const char*character, const char*as, parameters_t p)
707 character_t* c = dict_lookup(&characters, character);
710 const char*o = as,*s = as;
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, const 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, const char*name, parameters_t*p, char move)
899 swf_GetPlaceObject(NULL, &po);
903 po.cxform = p->cxform;
904 po.name = (char*)name;
909 po.blendmode = p->blendmode;
912 po.filters = p->filters;
913 swf_SetPlaceObject(tag, &po);
916 static void writeInstance(void* _i)
918 instance_t*i = (instance_t*)_i;
921 int frame = i->history->firstFrame;
922 TAG* tag = i->history->firstTag;
923 history_processFlags(i->history);
924 while (tag && frame < currentframe)
927 while (tag && tag->id != ST_SHOWFRAME)
929 if (parametersChange(i->history, frame))
931 readParameters(i->history, &p, frame);
932 m = s_instancepos(i->character->size, &p);
934 if(p.blendmode || p.filters)
935 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
937 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
938 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
940 free_filterlist(p.filters);
947 void dumpSWF(SWF*swf)
949 TAG* tag = swf->firstTag;
950 printf("vvvvvvvvvvvvvvvvvvvvv\n");
952 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
955 printf("^^^^^^^^^^^^^^^^^^^^^\n");
958 static void s_endSprite()
960 SRECT r = currentrect;
965 dict_foreach_value(&instances, writeInstance);
967 if(stack[stackpos].cut)
968 tag = removeFromTo(stack[stackpos].cut, tag);
970 // the writeInstance loop above may have inserted tags after what used to be the current tag,
971 // so let's make sure 'tag' point to the current tag again.
975 tag = swf_InsertTag(tag, ST_SHOWFRAME);
976 tag = swf_InsertTag(tag, ST_END);
978 tag = stack[stackpos].tag;
981 if(stack[stackpos].scalegrid.xmin | stack[stackpos].scalegrid.ymin |
982 stack[stackpos].scalegrid.xmax | stack[stackpos].scalegrid.ymax)
984 tag = swf_InsertTag(tag, ST_DEFINESCALINGGRID);
985 swf_SetU16(tag, stack[stackpos].id);
986 swf_SetRect(tag, &stack[stackpos].scalegrid);
990 syntaxerror("internal error(7)");
991 /* TODO: before clearing, prepend "<spritename>." to names and
992 copy into old instances dict */
993 dict_free_all(&instances, free_instance);
995 currentframe = stack[stackpos].oldframe;
996 currentrect = stack[stackpos].oldrect;
997 currentdepth = stack[stackpos].olddepth;
998 instances = stack[stackpos].oldinstances;
1000 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
1001 free(stack[stackpos].name);
1004 static void s_endSWF()
1010 dict_foreach_value(&instances, writeInstance);
1012 if(stack[stackpos].cut)
1013 tag = removeFromTo(stack[stackpos].cut, tag);
1017 swf = stack[stackpos].swf;
1018 filename = stack[stackpos].filename;
1020 // the writeInstance loop above may have inserted tags after what used yo be the current tag,
1021 // so let's make sure 'tag' point to the current tag again.
1025 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1026 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
1027 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1029 tag = swf_InsertTag(tag, ST_END);
1031 swf_OptimizeTagOrder(swf);
1037 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1038 swf->movieSize = currentrect; /* "autocrop" */
1041 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1042 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1043 swf->movieSize.ymax += 20;
1044 warning("Empty bounding box for movie");
1047 if(do_cgi || !strcmp(filename, "-"))
1048 fi = fileno(stdout);
1050 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1052 syntaxerror("couldn't create output file %s", filename);
1055 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1057 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1071 if(stack[stackpos-1].type == 0)
1072 syntaxerror("End of file encountered in .flash block");
1073 if(stack[stackpos-1].type == 1)
1074 syntaxerror("End of file encountered in .sprite block");
1075 if(stack[stackpos-1].type == 2)
1076 syntaxerror("End of file encountered in .clip block");
1082 return currentframe+1;
1085 void s_frame(int nr, int cut, const char*name, char anchor)
1091 syntaxerror("Illegal frame number");
1092 nr--; // internally, frame 1 is frame 0
1094 for(t=currentframe;t<nr;t++) {
1095 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1096 if(t==nr-1 && name && *name) {
1097 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1098 swf_SetString(tag, name);
1100 swf_SetU8(tag, 1); //make this an anchor
1103 if(nr == 0 && currentframe == 0 && name && *name) {
1104 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1105 swf_SetString(tag, name);
1107 swf_SetU8(tag, 1); //make this an anchor
1112 syntaxerror("Can't cut, frame empty");
1114 stack[stackpos].cut = tag;
1120 int parseColor2(const char*str, RGBA*color);
1122 int addFillStyle(SHAPE*s, SRECT*r, const char*name)
1126 gradient_t*gradient;
1128 if(name[0] == '#') {
1129 parseColor2(name, &color);
1130 return swf_ShapeAddSolidFillStyle(s, &color);
1131 } else if ((texture = dict_lookup(&textures, name))) {
1132 return swf_ShapeAddFillStyle2(s, &texture->fs);
1133 } else if((image = dict_lookup(&images, name))) {
1135 swf_GetMatrix(0, &m);
1136 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1137 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1140 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1141 } else if ((gradient = dict_lookup(&gradients, name))) {
1145 swf_GetMatrix(0, &rot);
1146 ccos = cos(-gradient->rotate*2*M_PI/360);
1147 csin = sin(-gradient->rotate*2*M_PI/360);
1148 rot.sx = ccos*65536;
1149 rot.r1 = -csin*65536;
1150 rot.r0 = csin*65536;
1151 rot.sy = ccos*65536;
1152 r2 = swf_TurnRect(*r, &rot);
1153 swf_GetMatrix(0, &m);
1154 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1155 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1156 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1157 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1158 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1159 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1160 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1161 } else if (parseColor2(name, &color)) {
1162 return swf_ShapeAddSolidFillStyle(s, &color);
1164 syntaxerror("not a color/fillstyle: %s", name);
1169 RGBA black={r:0,g:0,b:0,a:0};
1170 void s_box(const char*name, int width, int height, RGBA color, int linewidth, const char*texture)
1179 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1182 linewidth = linewidth>=20?linewidth-20:0;
1183 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1186 fs1 = addFillStyle(s, &r2, texture);
1189 r.xmin = r2.xmin-linewidth/2;
1190 r.ymin = r2.ymin-linewidth/2;
1191 r.xmax = r2.xmax+linewidth/2;
1192 r.ymax = r2.ymax+linewidth/2;
1193 swf_SetRect(tag,&r);
1194 swf_SetShapeHeader(tag,s);
1195 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1196 swf_ShapeSetLine(tag,s,width,0);
1197 swf_ShapeSetLine(tag,s,0,height);
1198 swf_ShapeSetLine(tag,s,-width,0);
1199 swf_ShapeSetLine(tag,s,0,-height);
1200 swf_ShapeSetEnd(tag);
1203 s_addcharacter(name, id, tag, r);
1207 void s_filled(const char*name, const char*outlinename, RGBA color, int linewidth, const char*texture)
1213 outline = dict_lookup(&outlines, outlinename);
1215 syntaxerror("outline %s not defined", outlinename);
1219 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1222 linewidth = linewidth>=20?linewidth-20:0;
1223 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1226 fs1 = addFillStyle(s, &r2, texture);
1229 rect.xmin = r2.xmin-linewidth/2;
1230 rect.ymin = r2.ymin-linewidth/2;
1231 rect.xmax = r2.xmax+linewidth/2;
1232 rect.ymax = r2.ymax+linewidth/2;
1234 swf_SetRect(tag,&rect);
1235 swf_SetShapeStyles(tag, s);
1236 swf_ShapeCountBits(s,0,0);
1237 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1238 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1239 swf_SetShapeBits(tag, s);
1240 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1243 s_addcharacter(name, id, tag, rect);
1247 void s_circle(const char*name, int r, RGBA color, int linewidth, const char*texture)
1252 r2.xmin = r2.ymin = 0;
1256 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1259 linewidth = linewidth>=20?linewidth-20:0;
1260 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1263 fs1 = addFillStyle(s, &r2, texture);
1265 rect.xmin = r2.xmin-linewidth/2;
1266 rect.ymin = r2.ymin-linewidth/2;
1267 rect.xmax = r2.xmax+linewidth/2;
1268 rect.ymax = r2.ymax+linewidth/2;
1270 swf_SetRect(tag,&rect);
1271 swf_SetShapeHeader(tag,s);
1272 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1273 swf_ShapeSetCircle(tag, s, r,r,r,r);
1274 swf_ShapeSetEnd(tag);
1277 s_addcharacter(name, id, tag, rect);
1281 void s_textshape(const char*name, const char*fontname, float size, const char*_text)
1284 U8*text = (U8*)_text;
1288 font = dict_lookup(&fonts, fontname);
1290 syntaxerror("font \"%s\" not known!", fontname);
1292 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1293 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1294 s_box(name, 0, 0, black, 20, 0);
1297 g = font->ascii2glyph[text[0]];
1299 outline = malloc(sizeof(outline_t));
1300 memset(outline, 0, sizeof(outline_t));
1301 outline->shape = font->glyph[g].shape;
1302 outline->bbox = font->layout->bounds[g];
1306 swf_Shape11DrawerInit(&draw, 0);
1307 swf_DrawText(&draw, font, (int)(size*100), (char*)_text);
1309 outline->shape = swf_ShapeDrawerToShape(&draw);
1310 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1311 draw.dealloc(&draw);
1314 if(dict_lookup(&outlines, name))
1315 syntaxerror("outline %s defined twice", name);
1316 dict_put2(&outlines, name, outline);
1319 void s_text(const char*name, const char*fontname, const char*text, int size, RGBA color)
1324 font = dict_lookup(&fonts, fontname);
1326 syntaxerror("font \"%s\" not known!", fontname);
1328 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1329 swf_SetU16(tag, id);
1330 if(!font->numchars) {
1331 s_box(name, 0, 0, black, 20, 0);
1334 r = swf_SetDefineText(tag, font, &color, (char*)text, size);
1336 if(stack[0].swf->fileVersion >= 8) {
1337 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1338 swf_SetU16(tag, id);
1339 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1340 swf_SetU32(tag, 0);//thickness
1341 swf_SetU32(tag, 0);//sharpness
1342 swf_SetU8(tag, 0);//reserved
1345 s_addcharacter(name, id, tag, r);
1349 void s_quicktime(const char*name, const char*url)
1354 memset(&r, 0, sizeof(r));
1356 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1357 swf_SetU16(tag, id);
1358 swf_SetString(tag, url);
1360 s_addcharacter(name, id, tag, r);
1364 void s_edittext(const char*name, const char*fontname, int size, int width, int height, const char*text, RGBA*color, int maxlength, const char*variable, int flags, int align)
1367 EditTextLayout layout;
1370 if(fontname && *fontname) {
1371 flags |= ET_USEOUTLINES;
1372 font = dict_lookup(&fonts, fontname);
1374 syntaxerror("font \"%s\" not known!", fontname);
1376 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1377 swf_SetU16(tag, id);
1378 layout.align = align;
1379 layout.leftmargin = 0;
1380 layout.rightmargin = 0;
1388 swf_SetEditText(tag, flags, r, (char*)text, color, maxlength, font?font->id:0, size, &layout, (char*)variable);
1390 s_addcharacter(name, id, tag, r);
1394 /* type: either "jpeg" or "png"
1396 void s_image(const char*name, const char*type, const char*filename, int quality)
1398 /* an image is actually two folded: 1st bitmap, 2nd character.
1399 Both of them can be used separately */
1401 /* step 1: the bitmap */
1405 if(!strcmp(type,"jpeg")) {
1406 #ifndef HAVE_JPEGLIB
1407 warning("no jpeg support compiled in");
1408 s_box(name, 0, 0, black, 20, 0);
1411 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1412 swf_SetU16(tag, imageID);
1414 if(swf_SetJPEGBits(tag, (char*)filename, quality) < 0) {
1415 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1418 swf_GetJPEGSize(filename, &width, &height);
1425 s_addimage(name, id, tag, r);
1428 } else if(!strcmp(type,"png")) {
1430 swf_SetU16(tag, imageID);
1432 getPNG(filename, &width, &height, (unsigned char**)&data);
1435 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1438 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1439 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1440 swf_SetU16(tag, imageID);
1441 swf_SetLosslessImage(tag, data, width, height);
1448 s_addimage(name, id, tag, r);
1451 warning("image type \"%s\" not supported yet!", type);
1452 s_box(name, 0, 0, black, 20, 0);
1456 /* step 2: the character */
1457 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1458 swf_SetU16(tag, id);
1459 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1461 s_addcharacter(name, id, tag, r);
1465 void s_getBitmapSize(const char*name, int*width, int*height)
1467 character_t* image = dict_lookup(&images, name);
1468 gradient_t* gradient = dict_lookup(&gradients,name);
1470 *width = image->size.xmax;
1471 *height = image->size.ymax;
1475 /* internal SWF gradient size */
1476 if(gradient->radial) {
1485 syntaxerror("No such bitmap/gradient: %s", name);
1488 void s_texture(const char*name, const char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1490 if(dict_lookup(&textures, name))
1491 syntaxerror("texture %s defined twice", name);
1492 gradient_t* gradient = dict_lookup(&gradients, object);
1493 character_t* bitmap = dict_lookup(&images, object);
1494 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1496 FILLSTYLE*fs = &texture->fs;
1498 memset(&p, 0, sizeof(parameters_t));
1501 fs->type = FILL_TILED;
1502 fs->id_bitmap = bitmap->id;
1503 } else if(gradient) {
1504 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1505 fs->gradient = gradient->gradient;
1507 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1508 makeMatrix(&fs->m, &p);
1509 if(gradient && !gradient->radial) {
1516 p2 = swf_TurnPoint(p1, &m);
1525 dict_put2(&textures, name, texture);
1528 void s_font(const char*name, const char*filename)
1531 font = dict_lookup(&fonts, name);
1534 /* fix the layout. Only needed for old fonts */
1536 for(t=0;t<font->numchars;t++) {
1537 font->glyph[t].advance = 0;
1540 swf_FontCreateLayout(font);
1543 swf_FontReduce_swfc(font);
1544 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1545 swf_FontSetDefine2(tag, font);
1547 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1549 swf_SetU16(tag, id);
1550 swf_SetString(tag, name);
1558 typedef struct _sound_t
1564 void s_sound(const char*name, const char*filename)
1566 struct WAV wav, wav2;
1570 unsigned numsamples = 1;
1571 unsigned blocksize = 1152;
1574 if(dict_lookup(&sounds, name))
1575 syntaxerror("sound %s defined twice", name);
1577 if(wav_read(&wav, filename))
1580 wav_convert2mono(&wav, &wav2, 44100);
1581 samples = (U16*)wav2.data;
1582 numsamples = wav2.size/2;
1584 #ifdef WORDS_BIGENDIAN
1586 for(t=0;t<numsamples;t++)
1587 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1591 if(mp3_read(&mp3, filename))
1593 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1599 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1604 if(numsamples%blocksize != 0)
1606 // apply padding, so that block is a multiple of blocksize
1607 int numblocks = (numsamples+blocksize-1)/blocksize;
1610 numsamples2 = numblocks * blocksize;
1611 samples2 = malloc(sizeof(U16)*numsamples2);
1612 memcpy(samples2, samples, numsamples*sizeof(U16));
1613 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1614 numsamples = numsamples2;
1619 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1620 swf_SetU16(tag, id); //id
1623 swf_SetSoundDefineMP3(
1624 tag, mp3.data, mp3.size,
1631 swf_SetSoundDefine(tag, samples, numsamples);
1634 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1635 swf_SetU16(tag, id);
1636 swf_SetString(tag, name);
1637 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1639 swf_SetU16(tag, id);
1640 swf_SetString(tag, name);
1643 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1647 dict_put2(&sounds, name, sound);
1655 static char* gradient_getToken(const char**p)
1659 while(**p && strchr(" \t\n\r", **p)) {
1663 while(**p && !strchr(" \t\n\r", **p)) {
1666 result = malloc((*p)-start+1);
1667 memcpy(result,start,(*p)-start+1);
1668 result[(*p)-start] = 0;
1672 float parsePercent(const char*str);
1673 RGBA parseColor(const char*str);
1675 GRADIENT parseGradient(const char*str)
1679 const char* p = str;
1680 memset(&gradient, 0, sizeof(GRADIENT));
1681 gradient.ratios = rfx_calloc(16*sizeof(U8));
1682 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1686 char*posstr,*colorstr;
1689 posstr = gradient_getToken(&p);
1695 pos = (int)(parsePercent(posstr)*255.0);
1700 rfx_free(gradient.ratios);
1701 rfx_free(gradient.rgba);
1703 syntaxerror("Error in shape data: Color expected after %s", posstr);
1705 colorstr = gradient_getToken(&p);
1706 color = parseColor(colorstr);
1707 if(gradient.num == 16)
1709 warning("gradient record too big- max size is 16, rest ignored");
1712 gradient.ratios[gradient.num] = pos;
1713 gradient.rgba[gradient.num] = color;
1722 FILTERLIST* parseFilters(char* list)
1724 if (!strcmp(list, "no_filters"))
1727 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1729 char* f_start = list;
1733 f_end = strchr(f_start, ',');
1736 f = dict_lookup(&filters, f_start);
1740 syntaxerror("unknown filter %s", f_start);
1742 if (f_list->num == 8)
1744 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1747 f_list->filter[f_list->num] = f;
1752 f_start = f_end + 1;
1760 void s_gradient(const char*name, const char*text, int radial, int rotate)
1762 gradient_t* gradient;
1763 gradient = malloc(sizeof(gradient_t));
1764 memset(gradient, 0, sizeof(gradient_t));
1765 gradient->gradient = parseGradient(text);
1766 gradient->radial = radial;
1767 gradient->rotate = rotate;
1769 dict_put2(&gradients, name, gradient);
1772 void s_gradientglow(const char*name, const char*gradient, float blurx, float blury,
1773 float angle, float distance, float strength, char innershadow,
1774 char knockout, char composite, char ontop, int passes)
1776 if(dict_lookup(&filters, name))
1777 syntaxerror("filter %s defined twice", name);
1779 gradient_t* g = dict_lookup(&gradients, gradient);
1781 syntaxerror("unknown gradient %s", gradient);
1785 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1786 filter->type = FILTERTYPE_GRADIENTGLOW;
1787 filter->gradient = &g->gradient;
1788 filter->blurx = blurx;
1789 filter->blury = blury;
1790 filter->strength = strength;
1791 filter->angle = angle;
1792 filter->distance = distance;
1793 filter->innershadow = innershadow;
1794 filter->knockout = knockout;
1795 filter->composite = composite;
1796 filter->ontop = ontop;
1797 filter->passes = passes;
1799 dict_put2(&filters, name, filter);
1802 void s_dropshadow(const char*name, RGBA color, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, int passes)
1804 if(dict_lookup(&filters, name))
1805 syntaxerror("filter %s defined twice", name);
1808 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1809 filter->type = FILTERTYPE_DROPSHADOW;
1810 filter->color= color;
1811 filter->blurx = blurx;
1812 filter->blury = blury;
1813 filter->strength = strength;
1814 filter->angle = angle;
1815 filter->distance = distance;
1816 filter->innershadow = innershadow;
1817 filter->knockout = knockout;
1818 filter->composite = composite;
1819 filter->passes = passes;
1821 dict_put2(&filters, name, filter);
1824 void s_bevel(const char*name, RGBA shadow, RGBA highlight, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, char ontop, int passes)
1826 if(dict_lookup(&filters, name))
1827 syntaxerror("filter %s defined twice", name);
1830 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1831 filter->type = FILTERTYPE_BEVEL;
1832 filter->shadow = shadow;
1833 filter->highlight = highlight;
1834 filter->blurx = blurx;
1835 filter->blury = blury;
1836 filter->strength = strength;
1837 filter->angle = angle;
1838 filter->distance = distance;
1839 filter->innershadow = innershadow;
1840 filter->knockout = knockout;
1841 filter->composite = composite;
1842 filter->ontop = ontop;
1843 filter->passes = passes;
1845 dict_put2(&filters, name, filter);
1848 void s_blur(const char*name, double blurx, double blury, int passes)
1850 if(dict_lookup(&filters, name))
1851 syntaxerror("filter %s defined twice", name);
1853 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1854 filter->type = FILTERTYPE_BLUR;
1855 filter->blurx = blurx;
1856 filter->blury = blury;
1857 filter->passes = passes;
1859 dict_put2(&filters, name, filter);
1862 void s_action(const char*text)
1865 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1869 syntaxerror("Couldn't compile ActionScript");
1872 tag = swf_InsertTag(tag, ST_DOACTION);
1874 swf_ActionSet(tag, a);
1879 void s_initaction(const char*character, const char*text)
1883 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1887 syntaxerror("Couldn't compile ActionScript");
1890 c = (character_t*)dict_lookup(&characters, character);
1892 tag = swf_InsertTag(tag, ST_DOINITACTION);
1893 swf_SetU16(tag, c->id);
1894 swf_ActionSet(tag, a);
1899 int s_swf3action(const char*name, const char*action)
1902 instance_t* object = 0;
1904 object = (instance_t*)dict_lookup(&instances, name);
1905 if(!object && name && *name) {
1906 /* we have a name, but couldn't find it. Abort. */
1909 a = action_SetTarget(0, name);
1910 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1911 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1912 else if(!strcmp(action, "stop")) a = action_Stop(a);
1913 else if(!strcmp(action, "play")) a = action_Play(a);
1914 a = action_SetTarget(a, "");
1917 tag = swf_InsertTag(tag, ST_DOACTION);
1918 swf_ActionSet(tag, a);
1923 void s_outline(const char*name, const char*format, const char*source)
1925 if(dict_lookup(&outlines, name))
1926 syntaxerror("outline %s defined twice", name);
1935 //swf_Shape10DrawerInit(&draw, 0);
1936 swf_Shape11DrawerInit(&draw, 0);
1938 draw_string(&draw, source);
1940 shape = swf_ShapeDrawerToShape(&draw);
1941 bounds = swf_ShapeDrawerGetBBox(&draw);
1942 draw.dealloc(&draw);
1944 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1945 outline->shape = shape;
1946 outline->bbox = bounds;
1948 dict_put2(&outlines, name, outline);
1951 int s_playsound(const char*name, int loops, int nomultiple, int stop)
1957 sound = dict_lookup(&sounds, name);
1961 tag = swf_InsertTag(tag, ST_STARTSOUND);
1962 swf_SetU16(tag, sound->id); //id
1963 memset(&info, 0, sizeof(info));
1966 info.nomultiple = nomultiple;
1967 swf_SetSoundInfo(tag, &info);
1971 void s_includeswf(const char*name, const char*filename)
1979 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1980 f = open(filename,O_RDONLY|O_BINARY);
1982 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1983 s_box(name, 0, 0, black, 20, 0);
1986 if (swf_ReadSWF(f,&swf)<0) {
1987 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1988 s_box(name, 0, 0, black, 20, 0);
1993 /* FIXME: The following sets the bounding Box for the character.
1994 It is wrong for two reasons:
1995 a) It may be too small (in case objects in the movie clip at the borders)
1996 b) it may be too big (because the poor movie never got autocropped)
2000 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2001 swf_SetU16(tag, id);
2002 swf_SetU16(tag, swf.frameCount);
2004 swf_Relocate(&swf, idmap);
2006 ftag = swf.firstTag;
2010 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2011 if(cutout[t] == ftag->id) {
2015 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2017 if(ftag->id == ST_END)
2022 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2023 /* We simply dump all tags right after the sprite
2024 header, relying on the fact that swf_OptimizeTagOrder() will
2025 sort things out for us later.
2026 We also rely on the fact that the imported SWF is well-formed.
2028 tag = swf_InsertTag(tag, ftag->id);
2029 swf_SetBlock(tag, ftag->data, ftag->len);
2035 syntaxerror("Included file %s contains errors", filename);
2036 tag = swf_InsertTag(tag, ST_END);
2040 s_addcharacter(name, id, tag, r);
2043 SRECT s_getCharBBox(const char*name)
2045 character_t* c = dict_lookup(&characters, name);
2046 if(!c) syntaxerror("character '%s' unknown(2)", name);
2049 SRECT s_getInstanceBBox(const char*name)
2051 instance_t * i = dict_lookup(&instances, name);
2053 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2055 if(!c) syntaxerror("internal error(5)");
2058 void s_getParameters(const char*name, parameters_t* p)
2060 instance_t * i = dict_lookup(&instances, name);
2062 syntaxerror("instance '%s' unknown(10)", name);
2063 if (change_sets_all)
2064 readParameters(i->history, p, currentframe);
2069 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2071 history_begin(i->history, "x", currentframe, tag, p->x);
2072 history_begin(i->history, "y", currentframe, tag, p->y);
2073 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2074 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2075 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2076 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2077 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2078 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2079 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2080 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2081 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2082 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2083 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2084 history_begin(i->history, "shear", currentframe, tag, p->shear);
2085 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2086 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2087 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2088 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2089 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2090 history_beginFilter(i->history, currentframe, tag, p->filters);
2091 history_begin(i->history, "flags", currentframe, tag, 0);
2094 void s_startclip(const char*instance, const char*character, parameters_t p)
2096 character_t* c = dict_lookup(&characters, character);
2100 syntaxerror("character %s not known", character);
2102 i = s_addinstance(instance, c, currentdepth);
2104 m = s_instancepos(i->character->size, &p);
2106 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2107 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2108 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2110 stack[stackpos].tag = tag;
2111 stack[stackpos].type = 2;
2114 setStartparameters(i, &p, tag);
2121 swf_SetTagPos(stack[stackpos].tag, 0);
2122 swf_GetPlaceObject(stack[stackpos].tag, &p);
2123 p.clipdepth = currentdepth;
2125 swf_ClearTag(stack[stackpos].tag);
2126 swf_SetPlaceObject(stack[stackpos].tag, &p);
2130 void s_put(const char*instance, const char*character, parameters_t p)
2132 character_t* c = dict_lookup(&characters, character);
2136 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2138 i = s_addinstance(instance, c, currentdepth);
2140 m = s_instancepos(i->character->size, &p);
2142 if(p.blendmode || p.filters)
2144 if(stack[0].swf->fileVersion < 8)
2147 warning("blendmodes only supported for flash version>=8");
2149 warning("filters only supported for flash version>=8");
2151 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2154 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2155 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2156 setStartparameters(i, &p, tag);
2160 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2163 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2165 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2166 if (p.set & SF_SCALEX)
2167 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2168 if (p.set & SF_SCALEY)
2169 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2170 if (p.set & SF_CX_R)
2172 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2173 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2175 if (p.set & SF_CX_G)
2177 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2178 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2180 if (p.set & SF_CX_B)
2182 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2183 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2185 if (p.set & SF_CX_A)
2187 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2188 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2190 if (p.set & SF_ROTATE)
2191 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2192 if (p.set & SF_SHEAR)
2193 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2194 if (p.set & SF_PIVOT)
2196 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2197 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2201 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2202 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2204 if (p.set & SF_BLEND)
2205 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2206 if (p.set & SF_FILTER)
2207 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2210 void s_jump(const char* instance, parameters_t p)
2212 instance_t* i = dict_lookup(&instances, instance);
2214 syntaxerror("instance %s not known", instance);
2215 recordChanges(i->history, p, CF_JUMP, 0);
2218 void s_change(const char*instance, parameters_t p, interpolation_t* inter)
2220 instance_t* i = dict_lookup(&instances, instance);
2222 syntaxerror("instance %s not known", instance);
2223 recordChanges(i->history, p, CF_CHANGE, inter);
2226 void s_sweep(const char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2228 instance_t* i = dict_lookup(&instances, instance);
2230 syntaxerror("instance %s not known", instance);
2231 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2234 void s_toggle(const char* instance, U16 flagsOn, U16 flagsOff)
2236 instance_t* i = dict_lookup(&instances, instance);
2238 syntaxerror("instance %s not known", instance);
2239 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2242 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2245 void s_delinstance(const char*instance)
2247 instance_t* i = dict_lookup(&instances, instance);
2249 syntaxerror("instance %s not known", instance);
2251 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2252 swf_SetU16(tag, i->depth);
2253 dict_del(&instances, instance);
2257 void s_schange(const char*instance, parameters_t p, interpolation_t* inter)
2259 instance_t* i = dict_lookup(&instances, instance);
2261 syntaxerror("instance %s not known", instance);
2262 recordChanges(i->history, p, CF_SCHANGE, inter);
2268 syntaxerror(".end unexpected");
2269 switch (stack[stackpos-1].type)
2284 syntaxerror("internal error 1");
2288 // ------------------------------------------------------------------------
2290 typedef int command_func_t(map_t*args);
2292 SRECT parseBox(const char*str)
2294 SRECT r = {0,0,0,0};
2295 float xmin, xmax, ymin, ymax;
2296 char*x = strchr(str, 'x');
2298 if(!strcmp(str, "autocrop")) {
2299 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2303 d1 = strchr(x+1, ':');
2305 d2 = strchr(d1+1, ':');
2307 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2311 else if(d1 && !d2) {
2312 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2318 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2323 r.xmin = (SCOORD)(xmin*20);
2324 r.ymin = (SCOORD)(ymin*20);
2325 r.xmax = (SCOORD)(xmax*20);
2326 r.ymax = (SCOORD)(ymax*20);
2329 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2332 float parseFloat(const char*str)
2336 int parseInt(const char*str)
2341 if(str[0]=='+' || str[0]=='-')
2345 if(str[t]<'0' || str[t]>'9')
2346 syntaxerror("Not an Integer: \"%s\"", str);
2349 static double parseRawTwip(const char*str)
2353 if(str[0]=='+' || str[0]=='-') {
2358 dot = strchr(str, '.');
2362 return sign*parseInt(str);
2364 char* old = strdup(str);
2365 int l=strlen(dot+1);
2368 for(s=str;s<dot-1;s++) {
2369 if(*s<'0' || *s>'9')
2372 syntaxerror("Not a coordinate: \"%s\"", str);
2376 if(*s<'0' || *s>'9')
2379 syntaxerror("Not a coordinate: \"%s\"", str);
2382 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2383 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2386 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2390 return sign*(atoi(str));
2392 return sign*(atoi(str)+0.1*atoi(dot));
2394 return sign*(atoi(str)+0.01*atoi(dot));
2399 static dict_t defines;
2400 static int defines_initialized = 0;
2401 static mem_t define_values;
2403 static double parseNameOrTwip(const char*s)
2407 if(defines_initialized) {
2408 l = (int)dict_lookup(&defines, s);
2411 return *(int*)&define_values.buffer[l-1];
2413 return parseRawTwip(s);
2417 /* automatically generated by yiyiyacc, http://www.quiss.org/yiyiyacc/ */
2418 static double parseExpression(char*s)
2421 memset(chr2index, -1, sizeof(chr2index));
2428 chr2index['\0'] = 7;
2436 int left[10]={11,8,8,8,8,9,9,9,10,10}; //production left side
2437 int plen[10]={1,3,2,3,1,3,3,1,1,3}; //production size
2438 int table[18][12] = {
2439 {0, 4, 0, 0, 5, 6, 0, 0, 1, 2, 3, 0},
2440 {7, 8, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0},
2441 {-4, -4, 9, 10, 0, 0, -4, -4, 0, 0, 0, 0},
2442 {-7, -7, -7, -7, 0, 0, -7, -7, 0, 0, 0, 0},
2443 {0, 0, 0, 0, 5, 6, 0, 0, 0, 11, 3, 0},
2444 {-8, -8, -8, -8, 0, 0, -8, -8, 0, 0, 0, 0},
2445 {0, 4, 0, 0, 5, 6, 0, 0, 12, 2, 3, 0},
2446 {0, 0, 0, 0, 5, 6, 0, 0, 0, 13, 3, 0},
2447 {0, 0, 0, 0, 5, 6, 0, 0, 0, 14, 3, 0},
2448 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 15, 0},
2449 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 16, 0},
2450 {-2, -2, 9, 10, 0, 0, -2, -2, 0, 0, 0, 0},
2451 {7, 8, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0},
2452 {-1, -1, 9, 10, 0, 0, -1, -1, 0, 0, 0, 0},
2453 {-3, -3, 9, 10, 0, 0, -3, -3, 0, 0, 0, 0},
2454 {-5, -5, -5, -5, 0, 0, -5, -5, 0, 0, 0, 0},
2455 {-6, -6, -6, -6, 0, 0, -6, -6, 0, 0, 0, 0},
2456 {-9, -9, -9, -9, 0, 0, -9, -9, 0, 0, 0, 0}};
2464 fprintf(stderr, "Error in expression\n");
2468 if(chr2index[*p]<0) {
2469 action = table[stack[stackpos-1]][4];
2471 while(chr2index[*pnext]<0)
2475 value = parseNameOrTwip(p);
2479 action = table[stack[stackpos-1]][chr2index[*p]];
2482 if(action == accept) {
2483 return values[stack[stackpos-1]];
2484 } else if(action>0) { // shift
2486 fprintf(stderr, "Stack overflow while parsing expression\n");
2489 values[stackpos]=value;
2490 stack[stackpos++]=action;
2492 } else if(action<0) { // reduce
2493 stackpos-=plen[-action];
2494 stack[stackpos] = table[stack[stackpos-1]][left[-action]];
2497 values[stackpos] = values[stackpos+0] + values[stackpos+2];
2500 values[stackpos] = 0 - values[stackpos+1];
2503 values[stackpos] = values[stackpos+0] - values[stackpos+2];
2506 values[stackpos] = values[stackpos+0] * values[stackpos+2];
2509 values[stackpos] = values[stackpos+0] / values[stackpos+2];
2512 values[stackpos] = values[stackpos+1];
2517 fprintf(stderr, "Syntax error in expression\n");
2523 int parseTwip(const char*str)
2525 char*str2 = (char*)str;
2526 int v = (int)(parseExpression(str2)*20);
2530 int parseArc(const char* str)
2532 if (!strcmp(str, "short"))
2534 if (!strcmp(str, "long"))
2536 syntaxerror("invalid value for the arc parameter: %s", str);
2540 int parseDir(const char* str)
2542 if (!strcmp(str, "clockwise"))
2544 if (!strcmp(str, "counterclockwise"))
2546 syntaxerror("invalid value for the dir parameter: %s", str);
2550 int isPoint(const char*str)
2552 if(strchr(str, '('))
2558 SPOINT parsePoint(const char*str)
2562 int l = strlen(str);
2563 char*comma = strchr(str, ',');
2564 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2565 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2566 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2567 p.x = parseTwip(tmp);
2568 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2569 p.y = parseTwip(tmp);
2573 int parseColor2(const char*str, RGBA*color)
2575 int l = strlen(str);
2579 struct {unsigned char r,g,b;char*name;} colors[] =
2580 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2581 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2582 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2583 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2584 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2585 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2586 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2587 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2588 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2589 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2590 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2591 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2595 if(str[0]=='#' && (l==7 || l==9)) {
2596 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2598 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2600 color->r = r; color->g = g; color->b = b; color->a = a;
2603 int len=strlen(str);
2605 if(strchr(str, '/')) {
2606 len = strchr(str, '/')-str;
2607 sscanf(str+len+1,"%02x", &alpha);
2609 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2610 if(!strncmp(str, colors[t].name, len)) {
2615 color->r = r; color->g = g; color->b = b; color->a = a;
2621 RGBA parseColor(const char*str)
2624 if(!parseColor2(str, &c))
2625 syntaxerror("Expression '%s' is not a color", str);
2629 typedef struct _muladd {
2634 MULADD parseMulAdd(const char*str)
2637 char* str2 = (char*)malloc(strlen(str)+5);
2644 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2645 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2646 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2647 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2648 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2649 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2650 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2651 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2652 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2653 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2655 syntaxerror("'%s' is not a valid color transform expression", str);
2657 m.add = (int)(add*256);
2658 m.mul = (int)(mul*256);
2663 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2665 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2666 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2668 if(a<-32768) a=-32768;
2669 if(a>32767) a=32767;
2670 if(m<-32768) m=-32768;
2671 if(m>32767) m=32767;
2677 float parsePxOrPercent(const char*fontname, const char*str)
2679 int l = strlen(str);
2680 if(strchr(str, '%'))
2681 return parsePercent(str);
2682 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2683 float p = atof(str);
2684 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2686 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2690 float parsePercent(const char*str)
2692 int l = strlen(str);
2696 return atoi(str)/100.0;
2698 syntaxerror("Expression '%s' is not a percentage", str);
2701 int isPercent(const char*str)
2703 return str[strlen(str)-1]=='%';
2705 int parseNewSize(const char*str, int size)
2708 return parsePercent(str)*size;
2710 return (int)(atof(str)*20);
2713 int isColor(char*str)
2716 return parseColor2(str, &c);
2719 static const char* lu(map_t* args, char*name)
2721 const char* value = map_lookup(args, name);
2723 map_dump(args, stdout, "");
2724 syntaxerror("internal error 2: value %s should be set", name);
2729 static int c_flash(map_t*args)
2731 const char* filename = map_lookup(args, "filename");
2732 const char* compressstr = lu(args, "compress");
2733 const char* change_modestr = lu(args, "change-sets-all");
2734 const char* exportstr = lu(args, "export");
2735 SRECT bbox = parseBox(lu(args, "bbox"));
2736 int version = parseInt(lu(args, "version"));
2737 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2738 RGBA color = parseColor(lu(args, "background"));
2741 if(!filename || !*filename) {
2742 /* for compatibility */
2743 filename = map_lookup(args, "name");
2744 if(!filename || !*filename) {
2747 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2748 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2752 if(!filename || override_outputname)
2753 filename = outputname;
2755 if(!strcmp(compressstr, "default"))
2756 compress = version>=6;
2757 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2759 else if(!strcmp(compressstr, "no"))
2761 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2763 if(!strcmp(change_modestr, "yes"))
2764 change_sets_all = 1;
2766 if(strcmp(change_modestr, "no"))
2767 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2769 do_exports=atoi(exportstr);
2771 s_swf(filename, bbox, version, fps, compress, color);
2774 int isRelative(const char*str)
2776 return !strncmp(str, "<plus>", 6) ||
2777 !strncmp(str, "<minus>", 7);
2779 const char* getOffset(const char*str)
2781 if(!strncmp(str, "<plus>", 6))
2783 if(!strncmp(str, "<minus>", 7))
2785 syntaxerror("internal error (347)");
2788 int getSign(const char*str)
2790 if(!strncmp(str, "<plus>", 6))
2792 if(!strncmp(str, "<minus>", 7))
2794 syntaxerror("internal error (348)");
2798 static dict_t points;
2799 static mem_t mpoints;
2800 static int points_initialized = 0;
2802 static int c_interpolation(map_t *args)
2805 const char* name = lu(args, "name");
2806 if (dict_lookup(&interpolations, name))
2807 syntaxerror("interpolation %s defined twice", name);
2809 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2810 const char* functionstr = lu(args, "function");
2811 inter->function = 0;
2812 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2813 if (!strcmp(functionstr,interpolationFunctions[i]))
2815 inter->function = i + 1;
2818 if (!inter->function)
2819 syntaxerror("unkown interpolation function %s", functionstr);
2820 inter->speed = parseFloat(lu(args, "speed"));
2821 inter->amplitude = parseTwip(lu(args, "amplitude"));
2822 inter->growth = parseFloat(lu(args, "growth"));
2823 inter->bounces = parseInt(lu(args, "bounces"));
2824 inter->damping = parseFloat(lu(args, "damping"));
2825 inter->slope = parseFloat(lu(args, "slope"));
2827 dict_put2(&interpolations, name, inter);
2831 SPOINT getPoint(SRECT r, const char*name)
2834 if(!strcmp(name, "center")) {
2836 p.x = (r.xmin + r.xmax)/2;
2837 p.y = (r.ymin + r.ymax)/2;
2840 if (!strcmp(name, "bottom-center")) {
2842 p.x = (r.xmin + r.xmax)/2;
2846 if (!strcmp(name, "top-center")) {
2848 p.x = (r.xmin + r.xmax)/2;
2852 if (!strcmp(name, "top-left")) {
2858 if (!strcmp(name, "top-right")) {
2864 if (!strcmp(name, "bottom-right")) {
2870 if (!strcmp(name, "bottom-left")) {
2876 if (!strcmp(name, "left-center")) {
2879 p.y = (r.ymin + r.ymax)/2;
2882 if (!strcmp(name, "right-center")) {
2885 p.y = (r.ymin + r.ymax)/2;
2890 if(points_initialized)
2891 l = (int)dict_lookup(&points, name);
2893 syntaxerror("Invalid point: \"%s\".", name);
2895 return *(SPOINT*)&mpoints.buffer[l-1];
2899 static int texture2(const char*name, const char*object, map_t*args, int errors)
2902 const char*xstr = map_lookup(args, "x");
2903 const char*ystr = map_lookup(args, "y");
2904 const char*widthstr = map_lookup(args, "width");
2905 const char*heightstr = map_lookup(args, "height");
2906 const char*scalestr = map_lookup(args, "scale");
2907 const char*scalexstr = map_lookup(args, "scalex");
2908 const char*scaleystr = map_lookup(args, "scaley");
2909 const char*rotatestr = map_lookup(args, "rotate");
2910 const char* shearstr = map_lookup(args, "shear");
2911 const char* radiusstr = map_lookup(args, "r");
2913 float scalex = 1.0, scaley = 1.0;
2914 float rotate=0, shear=0;
2916 if(!*xstr && !*ystr) {
2918 syntaxerror("x and y must be set");
2921 if(*scalestr && (*scalexstr || *scaleystr)) {
2922 syntaxerror("scale and scalex/scaley can't both be set");
2925 if((*widthstr || *heightstr) && *radiusstr) {
2926 syntaxerror("width/height and radius can't both be set");
2929 widthstr = radiusstr;
2930 heightstr = radiusstr;
2932 if(!*xstr) xstr="0";
2933 if(!*ystr) ystr="0";
2934 if(!*rotatestr) rotatestr="0";
2935 if(!*shearstr) shearstr="0";
2938 scalex = scaley = parsePercent(scalestr);
2939 } else if(*scalexstr || *scaleystr) {
2940 if(scalexstr) scalex = parsePercent(scalexstr);
2941 if(scaleystr) scaley = parsePercent(scaleystr);
2942 } else if(*widthstr || *heightstr) {
2945 s_getBitmapSize(object, &width, &height);
2947 scalex = (float)parseTwip(widthstr)/(float)width;
2949 scaley = (float)parseTwip(heightstr)/(float)height;
2951 x = parseTwip(xstr);
2952 y = parseTwip(ystr);
2953 rotate = parseFloat(rotatestr);
2954 shear = parseFloat(shearstr);
2956 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2961 static int c_texture(map_t*args)
2963 const char*name = lu(args, "instance");
2964 const char*object = lu(args, "character");
2965 return texture2(name, object, args, 1);
2968 static int c_gradient(map_t*args)
2970 const char*name = lu(args, "name");
2971 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2972 int rotate = parseInt(lu(args, "rotate"));
2976 syntaxerror("colon (:) expected");
2978 if(dict_lookup(&gradients, name))
2979 syntaxerror("gradient %s defined twice", name);
2981 s_gradient(name, text, radial, rotate);
2983 /* check whether we also have placement information,
2984 which would make this a positioned gradient.
2985 If there is placement information, texture2() will
2986 add a texture, which has priority over the gradient.
2988 texture2(name, name, args, 0);
2992 static const char* checkFiltername(map_t* args)
2994 const char* name = lu(args, "name");
2995 if (strchr(name, ','))
2996 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
3000 static int c_blur(map_t*args)
3002 const char*name = checkFiltername(args);
3003 const char*blurstr = lu(args, "blur");
3004 const char*blurxstr = lu(args, "blurx");
3005 const char*blurystr = lu(args, "blury");
3006 float blurx=1.0, blury=1.0;
3008 blurx = parseFloat(blurstr);
3009 blury = parseFloat(blurstr);
3012 blurx = parseFloat(blurxstr);
3014 blury = parseFloat(blurystr);
3015 int passes = parseInt(lu(args, "passes"));
3016 s_blur(name, blurx, blury, passes);
3020 static int c_gradientglow(map_t*args)
3022 const char*name = checkFiltername(args);
3023 const char*gradient = lu(args, "gradient");
3024 const char*blurstr = lu(args, "blur");
3025 const char*blurxstr = lu(args, "blurx");
3026 const char*blurystr = lu(args, "blury");
3027 float blurx=1.0, blury=1.0;
3029 blurx = parseFloat(blurstr);
3030 blury = parseFloat(blurstr);
3033 blurx = parseFloat(blurxstr);
3035 blury = parseFloat(blurystr);
3037 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3038 float distance = parseFloat(lu(args, "distance"));
3039 float strength = parseFloat(lu(args, "strength"));
3040 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3041 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3042 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3043 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3044 int passes = parseInt(lu(args, "passes"));
3046 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3050 static int c_dropshadow(map_t*args)
3052 const char*name = checkFiltername(args);
3053 RGBA color = parseColor(lu(args, "color"));
3054 const char*blurstr = lu(args, "blur");
3055 const char*blurxstr = lu(args, "blurx");
3056 const char*blurystr = lu(args, "blury");
3057 float blurx=1.0, blury=1.0;
3059 blurx = parseFloat(blurstr);
3060 blury = parseFloat(blurstr);
3063 blurx = parseFloat(blurxstr);
3065 blury = parseFloat(blurystr);
3067 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3068 float distance = parseFloat(lu(args, "distance"));
3069 float strength = parseFloat(lu(args, "strength"));
3070 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3071 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3072 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3073 int passes = parseInt(lu(args, "passes"));
3075 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3079 static int c_bevel(map_t*args)
3081 const char*name = checkFiltername(args);
3082 RGBA shadow = parseColor(lu(args, "shadow"));
3083 RGBA highlight = parseColor(lu(args, "highlight"));
3084 const char*blurstr = lu(args, "blur");
3085 const char*blurxstr = lu(args, "blurx");
3086 const char*blurystr = lu(args, "blury");
3087 float blurx=1.0, blury=1.0;
3089 blurx = parseFloat(blurstr);
3090 blury = parseFloat(blurstr);
3093 blurx = parseFloat(blurxstr);
3095 blury = parseFloat(blurystr);
3097 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3098 float distance = parseFloat(lu(args, "distance"));
3099 float strength = parseFloat(lu(args, "strength"));
3100 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3101 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3102 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3103 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3104 int passes = parseInt(lu(args, "passes"));
3106 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3110 static int c_define(map_t*args)
3112 const char*name = lu(args, "name");
3113 const char*value = lu(args, "value");
3115 if(!defines_initialized) {
3116 dict_init(&defines);
3117 mem_init(&define_values);
3118 defines_initialized = 1;
3120 int val = parseTwip(value);
3121 int pos = mem_put(&define_values, &val, sizeof(val));
3123 string_set(&s, name);
3124 dict_put(&defines, s, (void*)(pos+1));
3127 static int c_point(map_t*args)
3129 const char*name = lu(args, "name");
3133 if(!points_initialized) {
3136 points_initialized = 1;
3138 p.x = parseTwip(lu(args, "x"));
3139 p.y = parseTwip(lu(args, "y"));
3140 pos = mem_put(&mpoints, &p, sizeof(p));
3141 string_set(&s1, name);
3142 dict_put(&points, s1, (void*)(pos+1));
3145 static int c_play(map_t*args)
3147 const char*name = lu(args, "name");
3148 const char*loop = lu(args, "loop");
3149 const char*nomultiple = lu(args, "nomultiple");
3151 if(!strcmp(nomultiple, "nomultiple"))
3154 nm = parseInt(nomultiple);
3156 if(s_playsound(name, parseInt(loop), nm, 0)) {
3158 } else if(s_swf3action(name, "play")) {
3164 static int c_stop(map_t*args)
3166 const char*name = map_lookup(args, "name");
3168 if(s_playsound(name, 0,0,1))
3170 else if(s_swf3action(name, "stop"))
3172 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3176 static int c_nextframe(map_t*args)
3178 const char*name = lu(args, "name");
3180 if(s_swf3action(name, "nextframe")) {
3183 syntaxerror("I don't know anything about movie \"%s\"", name);
3187 static int c_previousframe(map_t*args)
3189 const char*name = lu(args, "name");
3191 if(s_swf3action(name, "previousframe")) {
3194 syntaxerror("I don't know anything about movie \"%s\"", name);
3198 static int c_movement(map_t*args, int type)
3200 const char*instance = lu(args, "name");
3202 const char* xstr="";
3203 const char* ystr="";
3208 xstr = lu(args, "x");
3209 ystr = lu(args, "y");
3211 s_getParameters(instance, &p);
3216 if(isRelative(xstr))
3218 if(type == PT_PUT || type == PT_STARTCLIP)
3219 syntaxerror("relative x values not allowed for initial put or startclip");
3220 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3224 p.x = parseTwip(xstr);
3230 if(isRelative(ystr))
3232 if(type == PT_PUT || type == PT_STARTCLIP)
3233 syntaxerror("relative y values not allowed for initial put or startclip");
3234 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3238 p.y = parseTwip(ystr);
3243 if (change_sets_all)
3251 const char* interstr = lu(args, "interpolation");
3252 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3254 syntaxerror("unkown interpolation %s", interstr);
3255 s_change(instance, p, inter);
3260 const char* interstr = lu(args, "interpolation");
3261 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3263 syntaxerror("unkown interpolation %s", interstr);
3264 s_schange(instance, p, inter);
3269 const char* rstr = lu(args, "r");
3270 int radius = parseTwip(rstr);
3272 syntaxerror("sweep not possible: radius must be greater than 0.");
3273 const char* dirstr = lu(args, "dir");
3274 int clockwise = parseDir(dirstr);
3275 const char* arcstr = lu(args, "arc");
3276 int short_arc = parseArc(arcstr);
3277 const char* interstr = lu(args, "interpolation");
3278 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3280 syntaxerror("unkown interpolation %s", interstr);
3281 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3288 static int c_placement(map_t*args, int type)
3290 const char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3291 const char*character = 0;
3293 const char* luminancestr = lu(args, "luminance");
3294 const char* scalestr = lu(args, "scale");
3295 const char* scalexstr = lu(args, "scalex");
3296 const char* scaleystr = lu(args, "scaley");
3297 const char* rotatestr = lu(args, "rotate");
3298 const char* shearstr = lu(args, "shear");
3299 const char* xstr="", *pivotstr="";
3300 const char* ystr="", *anglestr="";
3301 const char*above = lu(args, "above"); /*FIXME*/
3302 const char*below = lu(args, "below");
3303 const char* rstr = lu(args, "red");
3304 const char* gstr = lu(args, "green");
3305 const char* bstr = lu(args, "blue");
3306 const char* astr = lu(args, "alpha");
3307 const char* pinstr = lu(args, "pin");
3308 const char* as = map_lookup(args, "as");
3309 const char* blendmode = lu(args, "blend");
3310 const char* filterstr = lu(args, "filter");
3321 { // (?) .rotate or .arcchange
3322 pivotstr = lu(args, "pivot");
3323 anglestr = lu(args, "angle");
3327 xstr = lu(args, "x");
3328 ystr = lu(args, "y");
3332 luminance = parseMulAdd(luminancestr);
3336 luminance.mul = 256;
3341 if(scalexstr[0]||scaleystr[0])
3342 syntaxerror("scalex/scaley and scale cannot both be set");
3343 scalexstr = scaleystr = scalestr;
3346 if(type == PT_PUT || type == PT_STARTCLIP) {
3348 character = lu(args, "character");
3349 parameters_clear(&p);
3350 } else if (type == PT_BUTTON) {
3351 character = lu(args, "name");
3352 parameters_clear(&p);
3355 s_getParameters(instance, &p);
3361 if(isRelative(xstr))
3363 if(type == PT_PUT || type == PT_STARTCLIP)
3364 syntaxerror("relative x values not allowed for initial put or startclip");
3365 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3369 p.x = parseTwip(xstr);
3375 if(isRelative(ystr))
3377 if(type == PT_PUT || type == PT_STARTCLIP)
3378 syntaxerror("relative y values not allowed for initial put or startclip");
3379 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3383 p.y = parseTwip(ystr);
3388 /* scale, scalex, scaley */
3390 oldbbox = s_getCharBBox(character);
3392 oldbbox = s_getInstanceBBox(instance);
3393 oldwidth = oldbbox.xmax - oldbbox.xmin;
3394 oldheight = oldbbox.ymax - oldbbox.ymin;
3401 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3402 set = set | SF_SCALEX;
3410 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3411 set = set | SF_SCALEY;
3417 if(isRelative(rotatestr))
3418 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3420 p.rotate = parseFloat(rotatestr);
3421 set = set | SF_ROTATE;
3427 if(isRelative(shearstr))
3428 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3430 p.shear = parseFloat(shearstr);
3431 set = set | SF_SHEAR;
3436 if(isPoint(pivotstr))
3437 p.pivot = parsePoint(pivotstr);
3439 p.pivot = getPoint(oldbbox, pivotstr);
3440 set = set | SF_PIVOT;
3446 p.pin = parsePoint(pinstr);
3448 p.pin = getPoint(oldbbox, pinstr);
3452 /* color transform */
3454 if(rstr[0] || luminancestr[0])
3458 r = parseMulAdd(rstr);
3461 r.add = p.cxform.r0;
3462 r.mul = p.cxform.r1;
3464 r = mergeMulAdd(r, luminance);
3465 p.cxform.r0 = r.mul;
3466 p.cxform.r1 = r.add;
3467 set = set | SF_CX_R;
3469 if(gstr[0] || luminancestr[0])
3473 g = parseMulAdd(gstr);
3476 g.add = p.cxform.g0;
3477 g.mul = p.cxform.g1;
3479 g = mergeMulAdd(g, luminance);
3480 p.cxform.g0 = g.mul;
3481 p.cxform.g1 = g.add;
3482 set = set | SF_CX_G;
3484 if(bstr[0] || luminancestr[0])
3488 b = parseMulAdd(bstr);
3491 b.add = p.cxform.b0;
3492 b.mul = p.cxform.b1;
3494 b = mergeMulAdd(b, luminance);
3495 p.cxform.b0 = b.mul;
3496 p.cxform.b1 = b.add;
3497 set = set | SF_CX_B;
3501 MULADD a = parseMulAdd(astr);
3502 p.cxform.a0 = a.mul;
3503 p.cxform.a1 = a.add;
3504 set = set | SF_CX_A;
3511 for(t = 0; blendModeNames[t]; t++)
3513 if(!strcmp(blendModeNames[t], blendmode))
3521 syntaxerror("unknown blend mode: '%s'", blendmode);
3523 p.blendmode = blend;
3524 set = set | SF_BLEND;
3529 p.filters = parseFilters((char*)filterstr);
3530 set = set | SF_FILTER;
3533 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3534 warning("As of version 0.8.2 using the .change command to modify an \
3535 object's position on the stage is considered deprecated. Future \
3536 versions may consider x and y parameters for the .change command \
3537 to be illegal; please use the .move command.");
3539 if (change_sets_all)
3546 s_put(instance, character, p);
3550 const char* interstr = lu(args, "interpolation");
3551 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3553 syntaxerror("unkown interpolation %s", interstr);
3554 s_change(instance, p, inter);
3559 const char* interstr = lu(args, "interpolation");
3560 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3562 syntaxerror("unkown interpolation %s", interstr);
3563 s_schange(instance, p, inter);
3567 s_jump(instance, p);
3570 s_startclip(instance, character, p);
3574 s_buttonput(character, as, p);
3576 s_buttonput(character, "shape", p);
3582 static int c_put(map_t*args)
3584 c_placement(args, PT_PUT);
3587 static int c_change(map_t*args)
3589 if (currentframe == 0)
3590 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3591 c_placement(args, PT_CHANGE);
3594 static int c_schange(map_t*args)
3596 c_placement(args, PT_SCHANGE);
3599 static int c_move(map_t* args)
3601 c_movement(args, PT_MOVE);
3604 static int c_smove(map_t* args)
3606 c_movement(args, PT_SMOVE);
3609 static int c_sweep(map_t* args)
3611 c_movement(args, PT_SWEEP);
3614 static int c_arcchange(map_t*args)
3616 c_placement(args, 0);
3619 static int c_jump(map_t*args)
3621 c_placement(args, PT_JUMP);
3624 static int c_startclip(map_t*args)
3626 c_placement(args, PT_STARTCLIP);
3629 static int c_show(map_t*args)
3631 c_placement(args, PT_BUTTON);
3634 static int c_toggle(map_t* args)
3636 const char*instance = lu(args, "name");
3637 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3638 const char* alignstr = lu(args, "fixed_alignment");
3639 if (!strcmp(alignstr, "on"))
3640 flagsOn += IF_FIXED_ALIGNMENT;
3642 if (!strcmp(alignstr, "off"))
3643 flagsOff -= IF_FIXED_ALIGNMENT;
3645 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3646 s_toggle(instance, flagsOn, flagsOff);
3649 static int c_del(map_t*args)
3651 const char*instance = lu(args, "name");
3652 s_delinstance(instance);
3655 static int c_end(map_t*args)
3660 static int c_sprite(map_t*args)
3662 const char* name = lu(args, "name");
3663 const char* scalinggrid = lu(args, "scalinggrid");
3665 if(scalinggrid && *scalinggrid) {
3666 SRECT r = parseBox(scalinggrid);
3673 static int c_frame(map_t*args)
3675 const char*framestr = lu(args, "n");
3676 const char*cutstr = lu(args, "cut");
3678 const char*name = lu(args, "name");
3679 const char*anchor = lu(args, "anchor");
3682 if(!strcmp(anchor, "anchor") && !*name)
3687 if(strcmp(cutstr, "no"))
3689 if(isRelative(framestr)) {
3690 frame = s_getframe();
3691 if(getSign(framestr)<0)
3692 syntaxerror("relative frame expressions must be positive");
3693 frame += parseInt(getOffset(framestr));
3696 frame = parseInt(framestr);
3697 if(s_getframe() >= frame
3698 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3699 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3701 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3704 static int c_primitive(map_t*args)
3706 const char*name = lu(args, "name");
3707 const char*command = lu(args, "commandname");
3708 int width=0, height=0, r=0;
3709 int linewidth = parseTwip(lu(args, "line"));
3710 const char*colorstr = lu(args, "color");
3711 RGBA color = parseColor(colorstr);
3712 const char*fillstr = lu(args, "fill");
3717 const char* outline=0;
3719 if(!strcmp(command, "circle"))
3721 else if(!strcmp(command, "filled"))
3725 width = parseTwip(lu(args, "width"));
3726 height = parseTwip(lu(args, "height"));
3727 } else if (type==1) {
3728 r = parseTwip(lu(args, "r"));
3729 } else if (type==2) {
3730 outline = lu(args, "outline");
3733 if(!strcmp(fillstr, "fill"))
3735 if(!strcmp(fillstr, "none"))
3737 if(width<0 || height<0 || linewidth<0 || r<0)
3738 syntaxerror("values width, height, line, r must be positive");
3740 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3741 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3742 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3746 static int c_textshape(map_t*args)
3748 const char*name = lu(args, "name");
3749 const char*text = lu(args, "text");
3750 const char*font = lu(args, "font");
3751 float size = parsePxOrPercent(font, lu(args, "size"));
3753 s_textshape(name, font, size, text);
3757 static int c_swf(map_t*args)
3759 const char*name = lu(args, "name");
3760 const char*filename = lu(args, "filename");
3761 const char*command = lu(args, "commandname");
3762 if(!strcmp(command, "shape"))
3763 warning("Please use .swf instead of .shape");
3764 s_includeswf(name, filename);
3768 static int c_font(map_t*args)
3770 const char*name = lu(args, "name");
3771 const char*filename = lu(args, "filename");
3772 s_font(name, filename);
3776 static int c_sound(map_t*args)
3778 const char*name = lu(args, "name");
3779 const char*filename = lu(args, "filename");
3780 s_sound(name, filename);
3784 static int c_text(map_t*args)
3786 const char*name = lu(args, "name");
3787 const char*text = lu(args, "text");
3788 const char*font = lu(args, "font");
3789 float size = parsePxOrPercent(font, lu(args, "size"));
3790 RGBA color = parseColor(lu(args, "color"));
3791 s_text(name, font, text, (int)(size*100), color);
3795 static int c_soundtrack(map_t*args)
3800 static int c_quicktime(map_t*args)
3802 const char*name = lu(args, "name");
3803 const char*url = lu(args, "url");
3804 s_quicktime(name, url);
3808 static int c_image(map_t*args)
3810 const char*command = lu(args, "commandname");
3811 const char*name = lu(args, "name");
3812 const char*filename = lu(args, "filename");
3813 if(!strcmp(command,"jpeg")) {
3814 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3815 s_image(name, "jpeg", filename, quality);
3817 s_image(name, "png", filename, 0);
3822 static int c_outline(map_t*args)
3824 const char*name = lu(args, "name");
3825 const char*format = lu(args, "format");
3829 syntaxerror("colon (:) expected");
3831 s_outline(name, format, text);
3835 int fakechar(map_t*args)
3837 const char*name = lu(args, "name");
3838 s_box(name, 0, 0, black, 20, 0);
3842 static int c_egon(map_t*args) {return fakechar(args);}
3843 static int c_button(map_t*args) {
3844 const char*name = lu(args, "name");
3848 static int current_button_flags = 0;
3849 static int c_on_press(map_t*args)
3851 const char*position = lu(args, "position");
3852 const char*action = "";
3853 if(!strcmp(position, "inside")) {
3854 current_button_flags |= BC_OVERUP_OVERDOWN;
3855 } else if(!strcmp(position, "outside")) {
3856 //current_button_flags |= BC_IDLE_OUTDOWN;
3857 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3858 } else if(!strcmp(position, "anywhere")) {
3859 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3862 if(type == RAWDATA) {
3864 s_buttonaction(current_button_flags, action);
3865 current_button_flags = 0;
3871 static int c_on_release(map_t*args)
3873 const char*position = lu(args, "position");
3874 const char*action = "";
3875 if(!strcmp(position, "inside")) {
3876 current_button_flags |= BC_OVERDOWN_OVERUP;
3877 } else if(!strcmp(position, "outside")) {
3878 current_button_flags |= BC_OUTDOWN_IDLE;
3879 } else if(!strcmp(position, "anywhere")) {
3880 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3883 if(type == RAWDATA) {
3885 s_buttonaction(current_button_flags, action);
3886 current_button_flags = 0;
3892 static int c_on_move_in(map_t*args)
3894 const char*position = lu(args, "state");
3895 const char*action = "";
3896 if(!strcmp(position, "pressed")) {
3897 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3898 } else if(!strcmp(position, "not_pressed")) {
3899 current_button_flags |= BC_IDLE_OVERUP;
3900 } else if(!strcmp(position, "any")) {
3901 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3904 if(type == RAWDATA) {
3906 s_buttonaction(current_button_flags, action);
3907 current_button_flags = 0;
3913 static int c_on_move_out(map_t*args)
3915 const char*position = lu(args, "state");
3916 const char*action = "";
3917 if(!strcmp(position, "pressed")) {
3918 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3919 } else if(!strcmp(position, "not_pressed")) {
3920 current_button_flags |= BC_OVERUP_IDLE;
3921 } else if(!strcmp(position, "any")) {
3922 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3925 if(type == RAWDATA) {
3927 s_buttonaction(current_button_flags, action);
3928 current_button_flags = 0;
3934 static int c_on_key(map_t*args)
3936 const char*key = lu(args, "key");
3937 const char*action = "";
3938 if(strlen(key)==1) {
3941 current_button_flags |= 0x4000 + (key[0]*0x200);
3943 syntaxerror("invalid character: %c"+key[0]);
3948 <ctrl-x> = 0x200*(x-'a')
3952 syntaxerror("invalid key: %s",key);
3955 if(type == RAWDATA) {
3957 s_buttonaction(current_button_flags, action);
3958 current_button_flags = 0;
3965 static int c_edittext(map_t*args)
3967 //"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"},
3968 const char*name = lu(args, "name");
3969 const char*font = lu(args, "font");
3970 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3971 int width = parseTwip(lu(args, "width"));
3972 int height = parseTwip(lu(args, "height"));
3973 const char*text = lu(args, "text");
3974 RGBA color = parseColor(lu(args, "color"));
3975 int maxlength = parseInt(lu(args, "maxlength"));
3976 const char*variable = lu(args, "variable");
3977 const char*passwordstr = lu(args, "password");
3978 const char*wordwrapstr = lu(args, "wordwrap");
3979 const char*multilinestr = lu(args, "multiline");
3980 const char*htmlstr = lu(args, "html");
3981 const char*noselectstr = lu(args, "noselect");
3982 const char*readonlystr = lu(args, "readonly");
3983 const char*borderstr = lu(args, "border");
3984 const char*autosizestr = lu(args, "autosize");
3985 const char*alignstr = lu(args, "align");
3989 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3990 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3991 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3992 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3993 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3994 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3995 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3996 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3997 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3998 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3999 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
4000 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
4001 else syntaxerror("Unknown alignment: %s", alignstr);
4003 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
4007 static int c_morphshape(map_t*args) {return fakechar(args);}
4008 static int c_movie(map_t*args) {return fakechar(args);}
4010 static char* readfile(char*filename)
4012 FILE*fi = fopen(filename, "rb");
4016 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
4017 fseek(fi, 0, SEEK_END);
4019 fseek(fi, 0, SEEK_SET);
4020 text = rfx_alloc(l+1);
4021 fread(text, l, 1, fi);
4027 static int c_action(map_t*args)
4029 const char* filename = map_lookup(args, "filename");
4030 if(!filename ||!*filename) {
4032 if(type != RAWDATA) {
4033 syntaxerror("colon (:) expected");
4037 s_action(readfile((char*)filename));
4043 static int c_initaction(map_t*args)
4045 const char* character = lu(args, "name");
4046 const char* filename = map_lookup(args, "filename");
4047 if(!filename ||!*filename) {
4049 if(type != RAWDATA) {
4050 syntaxerror("colon (:) expected");
4052 s_initaction(character, text);
4054 s_initaction(character, readfile((char*)filename));
4062 command_func_t* func;
4065 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1"},
4066 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
4067 // "import" type stuff
4068 {"swf", c_swf, "name filename"},
4069 {"shape", c_swf, "name filename"},
4070 {"jpeg", c_image, "name filename quality=80%"},
4071 {"png", c_image, "name filename"},
4072 {"movie", c_movie, "name filename"},
4073 {"sound", c_sound, "name filename"},
4074 {"font", c_font, "name filename glyphs="},
4075 {"soundtrack", c_soundtrack, "filename"},
4076 {"quicktime", c_quicktime, "url"},
4078 // generators of primitives
4080 {"define", c_define, "name value=0"},
4081 {"point", c_point, "name x=0 y=0"},
4082 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4083 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4084 {"outline", c_outline, "name format=simple"},
4085 {"textshape", c_textshape, "name font size=100% text"},
4088 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4089 {"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"},
4090 {"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"},
4091 {"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"},
4093 // character generators
4094 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4095 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4096 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4098 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4099 {"text", c_text, "name text font size=100% color=white"},
4100 {"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="},
4101 {"morphshape", c_morphshape, "name start end"},
4102 {"button", c_button, "name"},
4103 {"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="},
4104 {"on_press", c_on_press, "position=inside"},
4105 {"on_release", c_on_release, "position=anywhere"},
4106 {"on_move_in", c_on_move_in, "state=not_pressed"},
4107 {"on_move_out", c_on_move_out, "state=not_pressed"},
4108 {"on_key", c_on_key, "key=any"},
4111 {"play", c_play, "name loop=0 @nomultiple=0"},
4112 {"stop", c_stop, "name= "},
4113 {"nextframe", c_nextframe, "name"},
4114 {"previousframe", c_previousframe, "name"},
4116 // object placement tags
4117 {"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="},
4118 {"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="},
4119 {"move", c_move, "name x= y= interpolation=linear"},
4120 {"smove", c_smove, "name x= y= interpolation=linear"},
4121 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4122 {"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"},
4123 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4124 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4125 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4126 {"del", c_del, "name"},
4127 // virtual object placement
4128 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4130 {"toggle", c_toggle, "name fixed_alignment="},
4132 // commands which start a block
4133 //startclip (see above)
4134 {"sprite", c_sprite, "name scalinggrid="},
4135 {"action", c_action, "filename="},
4136 {"initaction", c_initaction, "name filename="},
4142 static map_t parseArguments(char*command, char*pattern)
4158 string_set(&t1, "commandname");
4159 string_set(&t2, command);
4160 map_put(&result, t1, t2);
4162 if(!pattern || !*pattern)
4169 if(!strncmp("<i> ", x, 3)) {
4171 if(type == COMMAND || type == RAWDATA) {
4173 syntaxerror("character name expected");
4175 name[pos].str = "instance";
4177 value[pos].str = text;
4178 value[pos].len = strlen(text);
4182 if(type == ASSIGNMENT)
4185 name[pos].str = "character";
4187 value[pos].str = text;
4188 value[pos].len = strlen(text);
4196 isboolean[pos] = (x[0] =='@');
4209 name[pos].len = d-x;
4214 name[pos].len = e-x;
4215 value[pos].str = e+1;
4216 value[pos].len = d-e-1;
4224 /* for(t=0;t<len;t++) {
4225 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4226 isboolean[t]?"(boolean)":"");
4231 if(type == RAWDATA || type == COMMAND) {
4236 // first, search for boolean arguments
4237 for(pos=0;pos<len;pos++)
4239 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4241 if(type == ASSIGNMENT)
4243 value[pos].str = text;
4244 value[pos].len = strlen(text);
4245 /*printf("setting boolean parameter %s (to %s)\n",
4246 strdup_n(name[pos], namelen[pos]),
4247 strdup_n(value[pos], valuelen[pos]));*/
4252 // second, search for normal arguments
4254 for(pos=0;pos<len;pos++)
4256 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4257 (type != ASSIGNMENT && !set[pos])) {
4259 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4261 if(type == ASSIGNMENT)
4264 value[pos].str = text;
4265 value[pos].len = strlen(text);
4267 printf("setting parameter %s (to %s)\n",
4268 strdup_n(name[pos].str, name[pos].len),
4269 strdup_n(value[pos].str, value[pos].len));
4275 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4279 for(t=0;t<len;t++) {
4280 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4283 for(t=0;t<len;t++) {
4284 if(value[t].str && value[t].str[0] == '*') {
4285 //relative default- take value from some other parameter
4287 for(s=0;s<len;s++) {
4288 if(value[s].len == value[t].len-1 &&
4289 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4290 value[t].str = value[s].str;
4293 if(value[t].str == 0) {
4295 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4299 /* ok, now construct the dictionary from the parameters */
4303 map_put(&result, name[t], value[t]);
4307 static void parseArgumentsForCommand(char*command)
4312 msg("<verbose> parse Command: %s (line %d)", command, line);
4314 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4315 if(!strcmp(arguments[t].command, command)) {
4317 /* ugly hack- will be removed soon (once documentation and .sc generating
4318 utilities have been changed) */
4319 if(!strcmp(command, "swf") && !stackpos) {
4320 warning("Please use .flash instead of .swf- this will be mandatory soon");
4325 args = parseArguments(command, arguments[t].arguments);
4331 syntaxerror("command %s not known", command);
4333 // catch missing .flash directives at the beginning of a file
4334 if(strcmp(command, "flash") && !stackpos)
4336 syntaxerror("No movie defined- use .flash first");
4340 printf(".%s\n", command);fflush(stdout);
4341 map_dump(&args, stdout, "\t");fflush(stdout);
4344 (*arguments[nr].func)(&args);
4346 /*if(!strcmp(command, "button") ||
4347 !strcmp(command, "action")) {
4350 if(type == COMMAND) {
4351 if(!strcmp(text, "end"))
4366 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4367 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4368 * No syntax checking is done */
4369 static void analyseArgumentsForCommand(char*command)
4373 const char* fontfile;
4375 U8* glyphs_to_include;
4376 msg("<verbose> analyse Command: %s (line %d)", command, line);
4378 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4380 if(!strcmp(arguments[t].command, command))
4382 args = parseArguments(command, arguments[t].arguments);
4388 printf(".%s\n", command);fflush(stdout);
4389 map_dump(&args, stdout, "\t");fflush(stdout);
4391 const char* name = lu(&args, "name");
4392 if (!strcmp(command, "font"))
4394 if(dict_lookup(&fonts, name))
4395 syntaxerror("font %s defined twice", name);
4398 fontfile = lu(&args, "filename");
4399 font = swf_LoadFont(fontfile);
4401 warning("Couldn't open font file \"%s\"", fontfile);
4402 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4403 memset(font, 0, sizeof(SWFFONT));
4407 swf_FontPrepareForEditText(font);
4408 glyphs_to_include = (U8*)lu(&args, "glyphs");
4409 if (!strcmp(glyphs_to_include, "all"))
4411 swf_FontUseAll(font);
4412 font->use->glyphs_specified = 1;
4416 if (strcmp (glyphs_to_include, ""))
4418 swf_FontUseUTF8(font, glyphs_to_include);
4419 font->use->glyphs_specified = 1;
4422 swf_FontInitUsage(font);
4425 dict_put2(&fonts, name, font);
4429 SWFFONT* font = dict_lookup(&fonts, lu(&args, "font"));
4431 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4433 if (font->use && !font->use->glyphs_specified)
4435 if (!strcmp(command, "edittext"))
4437 swf_FontUseAll(font);
4438 font->use->glyphs_specified = 1;
4441 swf_FontUseUTF8(font, (U8*)lu(&args, "text"));
4448 void skipParameters()
4452 while (type != COMMAND);
4456 void findFontUsage()
4458 char* fontRelated = "font;text;textshape;edittext;";
4459 while(!noMoreTokens())
4463 syntaxerror("command expected");
4464 if (strstr(fontRelated, text))
4465 analyseArgumentsForCommand(text);
4467 if(strcmp(text, "end"))
4477 cleanUp = &freeFontDictionary;
4481 int main (int argc,char ** argv)
4484 processargs(argc, argv);
4485 initLog(0,-1,0,0,-1,verbose);
4488 args_callback_usage(argv[0]);
4492 file = generateTokens(filename);
4494 fprintf(stderr, "parser returned error.\n");
4501 while(!noMoreTokens()) {
4504 syntaxerror("command expected");
4505 parseArgumentsForCommand(text);