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()
363 while(id<65536 && idmap[id]) {
367 syntaxerror("Out of character ids.");
371 static void s_addcharacter(const char*name, U16 id, TAG*ctag, SRECT r)
373 if(dict_lookup(&characters, name))
374 syntaxerror("character %s defined twice", name);
375 character_t* c = character_new();
377 c->definingTag = ctag;
380 dict_put2(&characters, name, c);
383 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
385 swf_SetString(tag, name);
386 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
389 swf_SetString(tag, name);
392 static void s_addimage(const char*name, U16 id, TAG*ctag, SRECT r)
394 if(dict_lookup(&images, name))
395 syntaxerror("image %s defined twice", name);
397 character_t* c = character_new();
398 c->definingTag = ctag;
401 dict_put2(&images, name, c);
403 static instance_t* s_addinstance(const char*name, character_t*c, U16 depth)
405 if(dict_lookup(&instances, name))
406 syntaxerror("object %s defined twice", name);
407 instance_t* i = instance_new();
410 //swf_GetMatrix(0, &i->matrix);
411 dict_put2(&instances, name, i);
415 static void parameters_clear(parameters_t*p)
418 p->scalex = 1.0; p->scaley = 1.0;
421 p->pivot.x = 0; p->pivot.y = 0;
426 swf_GetCXForm(0, &p->cxform, 1);
429 static void makeMatrix(MATRIX*m, parameters_t*p)
438 sx = p->scalex*cos(p->rotate/360*2*M_PI);
439 r1 = -p->scalex*sin(p->rotate/360*2*M_PI)+sx*p->shear;
440 r0 = p->scaley*sin(p->rotate/360*2*M_PI);
441 sy = p->scaley*cos(p->rotate/360*2*M_PI)+r0*p->shear;
443 m->sx = (int)(sx*65536+0.5);
444 m->r1 = (int)(r1*65536+0.5);
445 m->r0 = (int)(r0*65536+0.5);
446 m->sy = (int)(sy*65536+0.5);
450 h = swf_TurnPoint(p->pin, m);
455 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
460 r = swf_TurnRect(rect, &m);
461 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
462 currentrect.xmax == 0 && currentrect.ymax == 0)
465 swf_ExpandRect2(¤trect, &r);
471 interpolation_t* new;
472 new = (interpolation_t*)malloc(sizeof(interpolation_t));
473 new->function = IF_LINEAR;
474 dict_put2(&interpolations, "linear", new);
476 new = (interpolation_t*)malloc(sizeof(interpolation_t));
477 new->function = IF_QUAD_IN;
479 dict_put2(&interpolations, "quadIn", new);
480 new = (interpolation_t*)malloc(sizeof(interpolation_t));
481 new->function = IF_QUAD_OUT;
483 dict_put2(&interpolations, "quadOut", new);
484 new = (interpolation_t*)malloc(sizeof(interpolation_t));
485 new->function = IF_QUAD_IN_OUT;
487 dict_put2(&interpolations, "quadInOut", new);
489 new = (interpolation_t*)malloc(sizeof(interpolation_t));
490 new->function = IF_CUBIC_IN;
492 dict_put2(&interpolations, "cubicIn", new);
493 new = (interpolation_t*)malloc(sizeof(interpolation_t));
494 new->function = IF_CUBIC_OUT;
496 dict_put2(&interpolations, "cubicOut", new);
497 new = (interpolation_t*)malloc(sizeof(interpolation_t));
498 new->function = IF_CUBIC_IN_OUT;
500 dict_put2(&interpolations, "cubicInOut", new);
502 new = (interpolation_t*)malloc(sizeof(interpolation_t));
503 new->function = IF_QUART_IN;
505 dict_put2(&interpolations, "quartIn", new);
506 new = (interpolation_t*)malloc(sizeof(interpolation_t));
507 new->function = IF_QUART_OUT;
509 dict_put2(&interpolations, "quartOut", new);
510 new = (interpolation_t*)malloc(sizeof(interpolation_t));
511 new->function = IF_QUART_IN_OUT;
513 dict_put2(&interpolations, "quartInOut", new);
515 new = (interpolation_t*)malloc(sizeof(interpolation_t));
516 new->function = IF_QUINT_IN;
518 dict_put2(&interpolations, "quintIn", new);
519 new = (interpolation_t*)malloc(sizeof(interpolation_t));
520 new->function = IF_QUINT_OUT;
522 dict_put2(&interpolations, "quintOut", new);
523 new = (interpolation_t*)malloc(sizeof(interpolation_t));
524 new->function = IF_QUINT_IN_OUT;
526 dict_put2(&interpolations, "quintInOut", new);
528 new = (interpolation_t*)malloc(sizeof(interpolation_t));
529 new->function = IF_CIRCLE_IN;
530 dict_put2(&interpolations, "circleIn", new);
531 new = (interpolation_t*)malloc(sizeof(interpolation_t));
532 new->function = IF_CIRCLE_OUT;
533 dict_put2(&interpolations, "circleOut", new);
534 new = (interpolation_t*)malloc(sizeof(interpolation_t));
535 new->function = IF_CIRCLE_IN_OUT;
536 dict_put2(&interpolations, "circleInOut", new);
538 new = (interpolation_t*)malloc(sizeof(interpolation_t));
539 new->function = IF_EXPONENTIAL_IN;
540 dict_put2(&interpolations, "exponentialIn", new);
541 new = (interpolation_t*)malloc(sizeof(interpolation_t));
542 new->function = IF_EXPONENTIAL_OUT;
543 dict_put2(&interpolations, "exponentialOut", new);
544 new = (interpolation_t*)malloc(sizeof(interpolation_t));
545 new->function = IF_EXPONENTIAL_IN_OUT;
546 dict_put2(&interpolations, "exponentialInOut", new);
548 new = (interpolation_t*)malloc(sizeof(interpolation_t));
549 new->function = IF_SINE_IN;
550 dict_put2(&interpolations, "sineIn", new);
551 new = (interpolation_t*)malloc(sizeof(interpolation_t));
552 new->function = IF_SINE_OUT;
553 dict_put2(&interpolations, "sineOut", new);
554 new = (interpolation_t*)malloc(sizeof(interpolation_t));
555 new->function = IF_SINE_IN_OUT;
556 dict_put2(&interpolations, "sineInOut", new);
559 memset(&c, 0, sizeof(RGBA));
560 gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
561 noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
562 noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
563 noGradient->gradient.num = 2;
564 noGradient->gradient.rgba[0] = c;
565 noGradient->gradient.ratios[0] = 0;
566 noGradient->gradient.rgba[1] = c;
567 noGradient->gradient.ratios[1] = 255;
568 noGradient->radial = 0;
569 noGradient->rotate = 0;
570 dict_put2(&gradients, "no_gradient", noGradient);
573 // put a no_filters entry in the filters dictionary to provoce a message when a user tries
574 // to define a no_filters filter. The real filter=no_filters case is handled in parseFilters.
575 FILTER* dummy = (FILTER*)malloc(sizeof(FILTER));
576 dict_put2(&filters, "no_filters", dummy);
577 noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
579 dict_put2(&filters, "no_blur", noBlur);
580 noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
582 noBevel->composite = 1;
583 dict_put2(&filters, "no_bevel", noBevel);
584 noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
585 noDropshadow->passes = 1;
586 noDropshadow->composite = 1;
587 dict_put2(&filters, "no_dropshadow", noDropshadow);
588 noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
589 noGradientGlow->passes = 1;
590 noGradientGlow->composite = 1;
591 noGradientGlow->gradient = &noGradient->gradient;
592 dict_put2(&filters, "no_gradientglow", noGradientGlow);
595 void s_swf(const char*name, SRECT r, int version, int fps, int compress, RGBA background)
598 syntaxerror(".swf blocks can't be nested");
599 if(stackpos==sizeof(stack)/sizeof(stack[0]))
600 syntaxerror("too many levels of recursion");
602 SWF*swf = (SWF*)malloc(sizeof(SWF));
604 memset(swf, 0, sizeof(swf));
605 swf->fileVersion = version;
607 swf->frameRate = fps;
608 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
609 swf->compressed = compress;
610 swf_SetRGB(tag,&background);
612 dict_init(&characters);
614 dict_init(&textures);
615 dict_init(&outlines);
616 dict_init(&gradients);
618 dict_init(&instances);
620 dict_init(&interpolations);
622 cleanUp = &freeDictionaries;
624 memset(&stack[stackpos], 0, sizeof(stack[0]));
625 stack[stackpos].type = 0;
626 stack[stackpos].filename = strdup(name);
627 stack[stackpos].swf = swf;
628 stack[stackpos].oldframe = -1;
632 memset(¤trect, 0, sizeof(currentrect));
635 memset(idmap, 0, sizeof(idmap));
639 void s_sprite(const char*name, SRECT*scalegrid)
641 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
642 swf_SetU16(tag, id); //id
643 swf_SetU16(tag, 0); //frames
645 memset(&stack[stackpos], 0, sizeof(stack[0]));
646 stack[stackpos].type = 1;
647 stack[stackpos].oldframe = currentframe;
648 stack[stackpos].olddepth = currentdepth;
649 stack[stackpos].oldrect = currentrect;
650 stack[stackpos].oldinstances = instances;
651 stack[stackpos].tag = tag;
652 stack[stackpos].id = id;
653 stack[stackpos].name = strdup(name);
655 stack[stackpos].scalegrid = *scalegrid;
657 memset(&stack[stackpos].scalegrid, 0, sizeof(SRECT));
660 /* FIXME: those four fields should be bundled together */
661 dict_init(&instances);
664 memset(¤trect, 0, sizeof(currentrect));
670 typedef struct _buttonrecord
678 typedef struct _button
682 buttonrecord_t records[4];
685 static button_t mybutton;
687 void s_button(const char*name)
689 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
690 swf_SetU16(tag, id); //id
691 swf_ButtonSetFlags(tag, 0); //menu=no
693 memset(&mybutton, 0, sizeof(mybutton));
695 memset(&stack[stackpos], 0, sizeof(stack[0]));
696 stack[stackpos].type = 3;
697 stack[stackpos].tag = tag;
698 stack[stackpos].id = id;
699 stack[stackpos].name = strdup(name);
700 stack[stackpos].oldrect = currentrect;
701 memset(¤trect, 0, sizeof(currentrect));
706 void s_buttonput(const char*character, const char*as, parameters_t p)
708 character_t* c = dict_lookup(&characters, character);
711 const char*o = as,*s = as;
713 if(!stackpos || (stack[stackpos-1].type != 3)) {
714 syntaxerror(".show may only appear in .button");
717 syntaxerror("character %s not known (in .shape %s)", character, character);
719 if(mybutton.endofshapes) {
720 syntaxerror("a .do may not precede a .show", character, character);
723 m = s_instancepos(c->size, &p);
731 if(*s==',' || *s==0) {
732 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
733 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
734 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
735 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
736 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
737 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
744 static void setbuttonrecords(TAG*tag)
746 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
747 if(!mybutton.endofshapes) {
750 if(!mybutton.records[3].set) {
751 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
755 if(mybutton.records[t].set) {
756 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
759 swf_SetU8(tag,0); // end of button records
760 mybutton.endofshapes = 1;
764 void s_buttonaction(int flags, const char*action)
770 if(!stackpos || !stack[stackpos-1].tag ||
771 stack[stackpos-1].tag->id != ST_DEFINEBUTTON2) {
772 syntaxerror("Need to be inside a button for .on_* commands");
774 setbuttonrecords(stack[stackpos-1].tag);
776 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
778 syntaxerror("Couldn't compile ActionScript");
781 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
782 swf_ActionSet(stack[stackpos-1].tag, a);
783 mybutton.nr_actions++;
788 static void setactionend(TAG*tag)
790 if(!mybutton.nr_actions) {
791 /* no actions means we didn't have an actionoffset,
792 which means we can't signal the end of the
793 buttonaction records, so, *sigh*, we have
794 to insert a dummy record */
795 swf_SetU16(tag, 0); //offset
796 swf_SetU16(tag, 0); //condition
797 swf_SetU8(tag, 0); //action
801 static void s_endButton()
804 setbuttonrecords(stack[stackpos-1].tag);
805 setactionend(stack[stackpos-1].tag);
808 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
812 tag = stack[stackpos].tag;
813 currentrect = stack[stackpos].oldrect;
815 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
816 free(stack[stackpos].name);
819 TAG* removeFromTo(TAG*from, TAG*to)
821 TAG*save = from->prev;
823 TAG*next = from->next;
824 if(swf_isAllowedSpriteTag(from))
825 swf_DeleteTag(0, from);
832 static int parametersChange(history_t* history, int frame)
836 willChange = willChange || history_change(history, frame, "x");
837 willChange = willChange || history_change(history, frame, "y");
838 willChange = willChange || history_change(history, frame, "scalex");
839 willChange = willChange || history_change(history, frame, "scaley");
840 willChange = willChange || history_change(history, frame, "cxform.r0");
841 willChange = willChange || history_change(history, frame, "cxform.g0");
842 willChange = willChange || history_change(history, frame, "cxform.b0");
843 willChange = willChange || history_change(history, frame, "cxform.a0");
844 willChange = willChange || history_change(history, frame, "cxform.r1");
845 willChange = willChange || history_change(history, frame, "cxform.g1");
846 willChange = willChange || history_change(history, frame, "cxform.b1");
847 willChange = willChange || history_change(history, frame, "cxform.a1");
848 willChange = willChange || history_change(history, frame, "rotate");
849 willChange = willChange || history_change(history, frame, "shear");
850 willChange = willChange || history_change(history, frame, "pivot.x");
851 willChange = willChange || history_change(history, frame, "pivot.y");
852 willChange = willChange || history_change(history, frame, "pin.x");
853 willChange = willChange || history_change(history, frame, "pin.y");
854 willChange = willChange || history_change(history, frame, "blendmode");
855 willChange = willChange || history_changeFilter(history, frame);
860 static void free_filterlist(FILTERLIST* f_list)
863 for (i = 0; i < f_list->num; i++)
865 if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
866 gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
867 free(f_list->filter[i]);
872 static void readParameters(history_t* history, parameters_t* p, int frame)
874 p->x = history_value(history, frame, "x");
875 p->y = history_value(history, frame, "y");
876 p->scalex = history_value(history, frame, "scalex");
877 p->scaley = history_value(history, frame, "scaley");
878 p->cxform.r0 = history_value(history, frame, "cxform.r0");
879 p->cxform.g0 = history_value(history, frame, "cxform.g0");
880 p->cxform.b0 = history_value(history, frame, "cxform.b0");
881 p->cxform.a0 = history_value(history, frame, "cxform.a0");
882 p->cxform.r1 = history_value(history, frame, "cxform.r1");
883 p->cxform.g1 = history_value(history, frame, "cxform.g1");
884 p->cxform.b1 = history_value(history, frame, "cxform.b1");
885 p->cxform.a1 = history_value(history, frame, "cxform.a1");
886 p->rotate = history_rotateValue(history, frame);
887 p->shear = history_value(history, frame, "shear");
888 p->pivot.x = history_value(history, frame, "pivot.x");
889 p->pivot.y = history_value(history, frame, "pivot.y");
890 p->pin.x = history_value(history, frame, "pin.x");
891 p->pin.y = history_value(history, frame, "pin.y");
892 p->blendmode = history_value(history, frame, "blendmode");
893 p->filters = history_filterValue(history, frame);
896 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, const char*name, parameters_t*p, char move)
900 swf_GetPlaceObject(NULL, &po);
904 po.cxform = p->cxform;
905 po.name = (char*)name;
910 po.blendmode = p->blendmode;
913 po.filters = p->filters;
914 swf_SetPlaceObject(tag, &po);
917 static void writeInstance(void* _i)
919 instance_t*i = (instance_t*)_i;
922 int frame = i->history->firstFrame;
923 TAG* tag = i->history->firstTag;
924 history_processFlags(i->history);
925 while (tag && frame < currentframe)
928 while (tag && tag->id != ST_SHOWFRAME)
930 if (parametersChange(i->history, frame))
932 readParameters(i->history, &p, frame);
933 m = s_instancepos(i->character->size, &p);
935 if(p.blendmode || p.filters)
936 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
938 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
939 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
941 free_filterlist(p.filters);
948 void dumpSWF(SWF*swf)
950 TAG* tag = swf->firstTag;
951 printf("vvvvvvvvvvvvvvvvvvvvv\n");
953 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
956 printf("^^^^^^^^^^^^^^^^^^^^^\n");
959 static void s_endSprite()
961 SRECT r = currentrect;
966 dict_foreach_value(&instances, writeInstance);
968 if(stack[stackpos].cut)
969 tag = removeFromTo(stack[stackpos].cut, tag);
971 // the writeInstance loop above may have inserted tags after what used to be the current tag,
972 // so let's make sure 'tag' point to the current tag again.
976 tag = swf_InsertTag(tag, ST_SHOWFRAME);
977 tag = swf_InsertTag(tag, ST_END);
979 tag = stack[stackpos].tag;
982 if(stack[stackpos].scalegrid.xmin | stack[stackpos].scalegrid.ymin |
983 stack[stackpos].scalegrid.xmax | stack[stackpos].scalegrid.ymax)
985 tag = swf_InsertTag(tag, ST_DEFINESCALINGGRID);
986 swf_SetU16(tag, stack[stackpos].id);
987 swf_SetRect(tag, &stack[stackpos].scalegrid);
991 syntaxerror("internal error(7)");
992 /* TODO: before clearing, prepend "<spritename>." to names and
993 copy into old instances dict */
994 dict_free_all(&instances, free_instance);
996 currentframe = stack[stackpos].oldframe;
997 currentrect = stack[stackpos].oldrect;
998 currentdepth = stack[stackpos].olddepth;
999 instances = stack[stackpos].oldinstances;
1001 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
1002 free(stack[stackpos].name);
1005 static void s_endSWF()
1011 dict_foreach_value(&instances, writeInstance);
1013 if(stack[stackpos].cut)
1014 tag = removeFromTo(stack[stackpos].cut, tag);
1018 swf = stack[stackpos].swf;
1019 filename = stack[stackpos].filename;
1021 // the writeInstance loop above may have inserted tags after what used yo be the current tag,
1022 // so let's make sure 'tag' point to the current tag again.
1026 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1027 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
1028 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1030 tag = swf_InsertTag(tag, ST_END);
1032 swf_OptimizeTagOrder(swf);
1038 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1039 swf->movieSize = currentrect; /* "autocrop" */
1042 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1043 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1044 swf->movieSize.ymax += 20;
1045 warning("Empty bounding box for movie");
1048 if(do_cgi || !strcmp(filename, "-"))
1049 fi = fileno(stdout);
1051 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1053 syntaxerror("couldn't create output file %s", filename);
1056 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1058 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1072 if(stack[stackpos-1].type == 0)
1073 syntaxerror("End of file encountered in .flash block");
1074 if(stack[stackpos-1].type == 1)
1075 syntaxerror("End of file encountered in .sprite block");
1076 if(stack[stackpos-1].type == 2)
1077 syntaxerror("End of file encountered in .clip block");
1083 return currentframe+1;
1086 void s_frame(int nr, int cut, const char*name, char anchor)
1092 syntaxerror("Illegal frame number");
1093 nr--; // internally, frame 1 is frame 0
1095 for(t=currentframe;t<nr;t++) {
1096 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1097 if(t==nr-1 && name && *name) {
1098 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1099 swf_SetString(tag, name);
1101 swf_SetU8(tag, 1); //make this an anchor
1104 if(nr == 0 && currentframe == 0 && name && *name) {
1105 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1106 swf_SetString(tag, name);
1108 swf_SetU8(tag, 1); //make this an anchor
1113 syntaxerror("Can't cut, frame empty");
1115 stack[stackpos].cut = tag;
1121 int parseColor2(const char*str, RGBA*color);
1123 int addFillStyle(SHAPE*s, SRECT*r, const char*name)
1127 gradient_t*gradient;
1129 if(name[0] == '#') {
1130 parseColor2(name, &color);
1131 return swf_ShapeAddSolidFillStyle(s, &color);
1132 } else if ((texture = dict_lookup(&textures, name))) {
1133 return swf_ShapeAddFillStyle2(s, &texture->fs);
1134 } else if((image = dict_lookup(&images, name))) {
1136 swf_GetMatrix(0, &m);
1137 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1138 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1141 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1142 } else if ((gradient = dict_lookup(&gradients, name))) {
1146 swf_GetMatrix(0, &rot);
1147 ccos = cos(-gradient->rotate*2*M_PI/360);
1148 csin = sin(-gradient->rotate*2*M_PI/360);
1149 rot.sx = ccos*65536;
1150 rot.r1 = -csin*65536;
1151 rot.r0 = csin*65536;
1152 rot.sy = ccos*65536;
1153 r2 = swf_TurnRect(*r, &rot);
1154 swf_GetMatrix(0, &m);
1155 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1156 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1157 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1158 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1159 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1160 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1161 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1162 } else if (parseColor2(name, &color)) {
1163 return swf_ShapeAddSolidFillStyle(s, &color);
1165 syntaxerror("not a color/fillstyle: %s", name);
1170 RGBA black={r:0,g:0,b:0,a:0};
1171 void s_box(const char*name, int width, int height, RGBA color, int linewidth, const char*texture)
1180 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1183 linewidth = linewidth>=20?linewidth-20:0;
1184 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1187 fs1 = addFillStyle(s, &r2, texture);
1190 r.xmin = r2.xmin-linewidth/2;
1191 r.ymin = r2.ymin-linewidth/2;
1192 r.xmax = r2.xmax+linewidth/2;
1193 r.ymax = r2.ymax+linewidth/2;
1194 swf_SetRect(tag,&r);
1195 swf_SetShapeHeader(tag,s);
1196 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1197 swf_ShapeSetLine(tag,s,width,0);
1198 swf_ShapeSetLine(tag,s,0,height);
1199 swf_ShapeSetLine(tag,s,-width,0);
1200 swf_ShapeSetLine(tag,s,0,-height);
1201 swf_ShapeSetEnd(tag);
1204 s_addcharacter(name, id, tag, r);
1208 void s_filled(const char*name, const char*outlinename, RGBA color, int linewidth, const char*texture)
1214 outline = dict_lookup(&outlines, outlinename);
1216 syntaxerror("outline %s not defined", outlinename);
1220 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1223 linewidth = linewidth>=20?linewidth-20:0;
1224 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1227 fs1 = addFillStyle(s, &r2, texture);
1230 rect.xmin = r2.xmin-linewidth/2;
1231 rect.ymin = r2.ymin-linewidth/2;
1232 rect.xmax = r2.xmax+linewidth/2;
1233 rect.ymax = r2.ymax+linewidth/2;
1235 swf_SetRect(tag,&rect);
1236 swf_SetShapeStyles(tag, s);
1237 swf_ShapeCountBits(s,0,0);
1238 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1239 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1240 swf_SetShapeBits(tag, s);
1241 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1244 s_addcharacter(name, id, tag, rect);
1248 void s_circle(const char*name, int r, RGBA color, int linewidth, const char*texture)
1253 r2.xmin = r2.ymin = 0;
1257 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1260 linewidth = linewidth>=20?linewidth-20:0;
1261 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1264 fs1 = addFillStyle(s, &r2, texture);
1266 rect.xmin = r2.xmin-linewidth/2;
1267 rect.ymin = r2.ymin-linewidth/2;
1268 rect.xmax = r2.xmax+linewidth/2;
1269 rect.ymax = r2.ymax+linewidth/2;
1271 swf_SetRect(tag,&rect);
1272 swf_SetShapeHeader(tag,s);
1273 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1274 swf_ShapeSetCircle(tag, s, r,r,r,r);
1275 swf_ShapeSetEnd(tag);
1278 s_addcharacter(name, id, tag, rect);
1282 void s_textshape(const char*name, const char*fontname, float size, const char*_text)
1285 U8*text = (U8*)_text;
1289 font = dict_lookup(&fonts, fontname);
1291 syntaxerror("font \"%s\" not known!", fontname);
1293 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1294 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1295 s_box(name, 0, 0, black, 20, 0);
1298 g = font->ascii2glyph[text[0]];
1300 outline = malloc(sizeof(outline_t));
1301 memset(outline, 0, sizeof(outline_t));
1302 outline->shape = font->glyph[g].shape;
1303 outline->bbox = font->layout->bounds[g];
1307 swf_Shape11DrawerInit(&draw, 0);
1308 swf_DrawText(&draw, font, (int)(size*100), (char*)_text);
1310 outline->shape = swf_ShapeDrawerToShape(&draw);
1311 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1312 draw.dealloc(&draw);
1315 if(dict_lookup(&outlines, name))
1316 syntaxerror("outline %s defined twice", name);
1317 dict_put2(&outlines, name, outline);
1320 void s_text(const char*name, const char*fontname, const char*text, int size, RGBA color)
1325 font = dict_lookup(&fonts, fontname);
1327 syntaxerror("font \"%s\" not known!", fontname);
1329 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1330 swf_SetU16(tag, id);
1331 if(!font->numchars) {
1332 s_box(name, 0, 0, black, 20, 0);
1335 r = swf_SetDefineText(tag, font, &color, (char*)text, size);
1337 if(stack[0].swf->fileVersion >= 8) {
1338 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1339 swf_SetU16(tag, id);
1340 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1341 swf_SetU32(tag, 0);//thickness
1342 swf_SetU32(tag, 0);//sharpness
1343 swf_SetU8(tag, 0);//reserved
1346 s_addcharacter(name, id, tag, r);
1350 void s_quicktime(const char*name, const char*url)
1355 memset(&r, 0, sizeof(r));
1357 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1358 swf_SetU16(tag, id);
1359 swf_SetString(tag, url);
1361 s_addcharacter(name, id, tag, r);
1365 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)
1368 EditTextLayout layout;
1371 if(fontname && *fontname) {
1372 flags |= ET_USEOUTLINES;
1373 font = dict_lookup(&fonts, fontname);
1375 syntaxerror("font \"%s\" not known!", fontname);
1377 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1378 swf_SetU16(tag, id);
1379 layout.align = align;
1380 layout.leftmargin = 0;
1381 layout.rightmargin = 0;
1389 swf_SetEditText(tag, flags, r, (char*)text, color, maxlength, font?font->id:0, size, &layout, (char*)variable);
1391 s_addcharacter(name, id, tag, r);
1395 /* type: either "jpeg" or "png"
1397 void s_image(const char*name, const char*type, const char*filename, int quality)
1399 /* an image is actually two folded: 1st bitmap, 2nd character.
1400 Both of them can be used separately */
1402 /* step 1: the bitmap */
1406 if(!strcmp(type,"jpeg")) {
1407 #ifndef HAVE_JPEGLIB
1408 warning("no jpeg support compiled in");
1409 s_box(name, 0, 0, black, 20, 0);
1412 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1413 swf_SetU16(tag, imageID);
1415 if(swf_SetJPEGBits(tag, (char*)filename, quality) < 0) {
1416 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1419 swf_GetJPEGSize(filename, &width, &height);
1426 s_addimage(name, id, tag, r);
1429 } else if(!strcmp(type,"png")) {
1431 swf_SetU16(tag, imageID);
1433 getPNG(filename, &width, &height, (unsigned char**)&data);
1436 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1439 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1440 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1441 swf_SetU16(tag, imageID);
1442 swf_SetLosslessImage(tag, data, width, height);
1449 s_addimage(name, id, tag, r);
1452 warning("image type \"%s\" not supported yet!", type);
1453 s_box(name, 0, 0, black, 20, 0);
1457 /* step 2: the character */
1458 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1459 swf_SetU16(tag, id);
1460 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1462 s_addcharacter(name, id, tag, r);
1466 void s_getBitmapSize(const char*name, int*width, int*height)
1468 character_t* image = dict_lookup(&images, name);
1469 gradient_t* gradient = dict_lookup(&gradients,name);
1471 *width = image->size.xmax;
1472 *height = image->size.ymax;
1476 /* internal SWF gradient size */
1477 if(gradient->radial) {
1486 syntaxerror("No such bitmap/gradient: %s", name);
1489 void s_texture(const char*name, const char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1491 if(dict_lookup(&textures, name))
1492 syntaxerror("texture %s defined twice", name);
1493 gradient_t* gradient = dict_lookup(&gradients, object);
1494 character_t* bitmap = dict_lookup(&images, object);
1495 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1497 FILLSTYLE*fs = &texture->fs;
1499 memset(&p, 0, sizeof(parameters_t));
1502 fs->type = FILL_TILED;
1503 fs->id_bitmap = bitmap->id;
1504 } else if(gradient) {
1505 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1506 fs->gradient = gradient->gradient;
1508 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1509 makeMatrix(&fs->m, &p);
1510 if(gradient && !gradient->radial) {
1517 p2 = swf_TurnPoint(p1, &m);
1526 dict_put2(&textures, name, texture);
1529 void s_font(const char*name, const char*filename)
1532 font = dict_lookup(&fonts, name);
1535 /* fix the layout. Only needed for old fonts */
1537 for(t=0;t<font->numchars;t++) {
1538 font->glyph[t].advance = 0;
1541 swf_FontCreateLayout(font);
1544 swf_FontReduce_swfc(font);
1545 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1546 swf_FontSetDefine2(tag, font);
1548 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1550 swf_SetU16(tag, id);
1551 swf_SetString(tag, name);
1559 typedef struct _sound_t
1565 void s_sound(const char*name, const char*filename)
1567 struct WAV wav, wav2;
1571 unsigned numsamples = 1;
1572 unsigned blocksize = 1152;
1575 if(dict_lookup(&sounds, name))
1576 syntaxerror("sound %s defined twice", name);
1578 if(wav_read(&wav, filename))
1581 wav_convert2mono(&wav, &wav2, 44100);
1582 samples = (U16*)wav2.data;
1583 numsamples = wav2.size/2;
1585 #ifdef WORDS_BIGENDIAN
1587 for(t=0;t<numsamples;t++)
1588 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1592 if(mp3_read(&mp3, filename))
1594 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1600 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1605 if(numsamples%blocksize != 0)
1607 // apply padding, so that block is a multiple of blocksize
1608 int numblocks = (numsamples+blocksize-1)/blocksize;
1611 numsamples2 = numblocks * blocksize;
1612 samples2 = malloc(sizeof(U16)*numsamples2);
1613 memcpy(samples2, samples, numsamples*sizeof(U16));
1614 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1615 numsamples = numsamples2;
1620 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1621 swf_SetU16(tag, id); //id
1624 swf_SetSoundDefineMP3(
1625 tag, mp3.data, mp3.size,
1632 swf_SetSoundDefine(tag, samples, numsamples);
1635 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1636 swf_SetU16(tag, id);
1637 swf_SetString(tag, name);
1638 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1640 swf_SetU16(tag, id);
1641 swf_SetString(tag, name);
1644 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1648 dict_put2(&sounds, name, sound);
1656 static char* gradient_getToken(const char**p)
1660 while(**p && strchr(" \t\n\r", **p)) {
1664 while(**p && !strchr(" \t\n\r", **p)) {
1667 result = malloc((*p)-start+1);
1668 memcpy(result,start,(*p)-start+1);
1669 result[(*p)-start] = 0;
1673 float parsePercent(const char*str);
1674 RGBA parseColor(const char*str);
1676 GRADIENT parseGradient(const char*str)
1680 const char* p = str;
1681 memset(&gradient, 0, sizeof(GRADIENT));
1682 gradient.ratios = rfx_calloc(16*sizeof(U8));
1683 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1687 char*posstr,*colorstr;
1690 posstr = gradient_getToken(&p);
1696 pos = (int)(parsePercent(posstr)*255.0);
1701 rfx_free(gradient.ratios);
1702 rfx_free(gradient.rgba);
1704 syntaxerror("Error in shape data: Color expected after %s", posstr);
1706 colorstr = gradient_getToken(&p);
1707 color = parseColor(colorstr);
1708 if(gradient.num == 16)
1710 warning("gradient record too big- max size is 16, rest ignored");
1713 gradient.ratios[gradient.num] = pos;
1714 gradient.rgba[gradient.num] = color;
1723 FILTERLIST* parseFilters(char* list)
1725 if (!strcmp(list, "no_filters"))
1728 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1730 char* f_start = list;
1734 f_end = strchr(f_start, ',');
1737 f = dict_lookup(&filters, f_start);
1741 syntaxerror("unknown filter %s", f_start);
1743 if (f_list->num == 8)
1745 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1748 f_list->filter[f_list->num] = f;
1753 f_start = f_end + 1;
1761 void s_gradient(const char*name, const char*text, int radial, int rotate)
1763 gradient_t* gradient;
1764 gradient = malloc(sizeof(gradient_t));
1765 memset(gradient, 0, sizeof(gradient_t));
1766 gradient->gradient = parseGradient(text);
1767 gradient->radial = radial;
1768 gradient->rotate = rotate;
1770 dict_put2(&gradients, name, gradient);
1773 void s_gradientglow(const char*name, const char*gradient, float blurx, float blury,
1774 float angle, float distance, float strength, char innershadow,
1775 char knockout, char composite, char ontop, int passes)
1777 if(dict_lookup(&filters, name))
1778 syntaxerror("filter %s defined twice", name);
1780 gradient_t* g = dict_lookup(&gradients, gradient);
1782 syntaxerror("unknown gradient %s", gradient);
1786 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1787 filter->type = FILTERTYPE_GRADIENTGLOW;
1788 filter->gradient = &g->gradient;
1789 filter->blurx = blurx;
1790 filter->blury = blury;
1791 filter->strength = strength;
1792 filter->angle = angle;
1793 filter->distance = distance;
1794 filter->innershadow = innershadow;
1795 filter->knockout = knockout;
1796 filter->composite = composite;
1797 filter->ontop = ontop;
1798 filter->passes = passes;
1800 dict_put2(&filters, name, filter);
1803 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)
1805 if(dict_lookup(&filters, name))
1806 syntaxerror("filter %s defined twice", name);
1809 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1810 filter->type = FILTERTYPE_DROPSHADOW;
1811 filter->color= color;
1812 filter->blurx = blurx;
1813 filter->blury = blury;
1814 filter->strength = strength;
1815 filter->angle = angle;
1816 filter->distance = distance;
1817 filter->innershadow = innershadow;
1818 filter->knockout = knockout;
1819 filter->composite = composite;
1820 filter->passes = passes;
1822 dict_put2(&filters, name, filter);
1825 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)
1827 if(dict_lookup(&filters, name))
1828 syntaxerror("filter %s defined twice", name);
1831 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1832 filter->type = FILTERTYPE_BEVEL;
1833 filter->shadow = shadow;
1834 filter->highlight = highlight;
1835 filter->blurx = blurx;
1836 filter->blury = blury;
1837 filter->strength = strength;
1838 filter->angle = angle;
1839 filter->distance = distance;
1840 filter->innershadow = innershadow;
1841 filter->knockout = knockout;
1842 filter->composite = composite;
1843 filter->ontop = ontop;
1844 filter->passes = passes;
1846 dict_put2(&filters, name, filter);
1849 void s_blur(const char*name, double blurx, double blury, int passes)
1851 if(dict_lookup(&filters, name))
1852 syntaxerror("filter %s defined twice", name);
1854 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1855 filter->type = FILTERTYPE_BLUR;
1856 filter->blurx = blurx;
1857 filter->blury = blury;
1858 filter->passes = passes;
1860 dict_put2(&filters, name, filter);
1863 void s_action(const char*text)
1866 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1870 syntaxerror("Couldn't compile ActionScript");
1873 tag = swf_InsertTag(tag, ST_DOACTION);
1875 swf_ActionSet(tag, a);
1880 void s_initaction(const char*character, const char*text)
1884 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1888 syntaxerror("Couldn't compile ActionScript");
1891 c = (character_t*)dict_lookup(&characters, character);
1893 tag = swf_InsertTag(tag, ST_DOINITACTION);
1894 swf_SetU16(tag, c->id);
1895 swf_ActionSet(tag, a);
1900 int s_swf3action(const char*name, const char*action)
1903 instance_t* object = 0;
1905 object = (instance_t*)dict_lookup(&instances, name);
1906 if(!object && name && *name) {
1907 /* we have a name, but couldn't find it. Abort. */
1910 a = action_SetTarget(0, name);
1911 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1912 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1913 else if(!strcmp(action, "stop")) a = action_Stop(a);
1914 else if(!strcmp(action, "play")) a = action_Play(a);
1915 a = action_SetTarget(a, "");
1918 tag = swf_InsertTag(tag, ST_DOACTION);
1919 swf_ActionSet(tag, a);
1924 void s_outline(const char*name, const char*format, const char*source)
1926 if(dict_lookup(&outlines, name))
1927 syntaxerror("outline %s defined twice", name);
1936 //swf_Shape10DrawerInit(&draw, 0);
1937 swf_Shape11DrawerInit(&draw, 0);
1939 draw_string(&draw, source);
1941 shape = swf_ShapeDrawerToShape(&draw);
1942 bounds = swf_ShapeDrawerGetBBox(&draw);
1943 draw.dealloc(&draw);
1945 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1946 outline->shape = shape;
1947 outline->bbox = bounds;
1949 dict_put2(&outlines, name, outline);
1952 int s_playsound(const char*name, int loops, int nomultiple, int stop)
1958 sound = dict_lookup(&sounds, name);
1962 tag = swf_InsertTag(tag, ST_STARTSOUND);
1963 swf_SetU16(tag, sound->id); //id
1964 memset(&info, 0, sizeof(info));
1967 info.nomultiple = nomultiple;
1968 swf_SetSoundInfo(tag, &info);
1972 void s_includeswf(const char*name, const char*filename)
1980 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1981 f = open(filename,O_RDONLY|O_BINARY);
1983 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1984 s_box(name, 0, 0, black, 20, 0);
1987 if (swf_ReadSWF(f,&swf)<0) {
1988 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1989 s_box(name, 0, 0, black, 20, 0);
1994 /* FIXME: The following sets the bounding Box for the character.
1995 It is wrong for two reasons:
1996 a) It may be too small (in case objects in the movie clip at the borders)
1997 b) it may be too big (because the poor movie never got autocropped)
2001 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2002 swf_SetU16(tag, id);
2003 swf_SetU16(tag, swf.frameCount);
2005 swf_Relocate(&swf, idmap);
2007 ftag = swf.firstTag;
2011 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2012 if(cutout[t] == ftag->id) {
2016 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2018 if(ftag->id == ST_END)
2023 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2024 /* We simply dump all tags right after the sprite
2025 header, relying on the fact that swf_OptimizeTagOrder() will
2026 sort things out for us later.
2027 We also rely on the fact that the imported SWF is well-formed.
2029 tag = swf_InsertTag(tag, ftag->id);
2030 swf_SetBlock(tag, ftag->data, ftag->len);
2036 syntaxerror("Included file %s contains errors", filename);
2037 tag = swf_InsertTag(tag, ST_END);
2041 s_addcharacter(name, id, tag, r);
2044 SRECT s_getCharBBox(const char*name)
2046 character_t* c = dict_lookup(&characters, name);
2047 if(!c) syntaxerror("character '%s' unknown(2)", name);
2050 SRECT s_getInstanceBBox(const char*name)
2052 instance_t * i = dict_lookup(&instances, name);
2054 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2056 if(!c) syntaxerror("internal error(5)");
2059 void s_getParameters(const char*name, parameters_t* p)
2061 instance_t * i = dict_lookup(&instances, name);
2063 syntaxerror("instance '%s' unknown(10)", name);
2064 if (change_sets_all)
2065 readParameters(i->history, p, currentframe);
2070 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2072 history_begin(i->history, "x", currentframe, tag, p->x);
2073 history_begin(i->history, "y", currentframe, tag, p->y);
2074 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2075 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2076 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2077 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2078 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2079 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2080 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2081 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2082 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2083 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2084 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2085 history_begin(i->history, "shear", currentframe, tag, p->shear);
2086 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2087 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2088 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2089 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2090 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2091 history_beginFilter(i->history, currentframe, tag, p->filters);
2092 history_begin(i->history, "flags", currentframe, tag, 0);
2095 void s_startclip(const char*instance, const char*character, parameters_t p)
2097 character_t* c = dict_lookup(&characters, character);
2101 syntaxerror("character %s not known", character);
2103 i = s_addinstance(instance, c, currentdepth);
2105 m = s_instancepos(i->character->size, &p);
2107 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2108 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2109 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2111 stack[stackpos].tag = tag;
2112 stack[stackpos].type = 2;
2115 setStartparameters(i, &p, tag);
2122 swf_SetTagPos(stack[stackpos].tag, 0);
2123 swf_GetPlaceObject(stack[stackpos].tag, &p);
2124 p.clipdepth = currentdepth;
2126 swf_ClearTag(stack[stackpos].tag);
2127 swf_SetPlaceObject(stack[stackpos].tag, &p);
2131 void s_put(const char*instance, const char*character, parameters_t p)
2133 character_t* c = dict_lookup(&characters, character);
2137 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2139 i = s_addinstance(instance, c, currentdepth);
2141 m = s_instancepos(i->character->size, &p);
2143 if(p.blendmode || p.filters)
2145 if(stack[0].swf->fileVersion < 8)
2148 warning("blendmodes only supported for flash version>=8");
2150 warning("filters only supported for flash version>=8");
2152 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2155 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2156 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2157 setStartparameters(i, &p, tag);
2161 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2164 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2166 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2167 if (p.set & SF_SCALEX)
2168 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2169 if (p.set & SF_SCALEY)
2170 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2171 if (p.set & SF_CX_R)
2173 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2174 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2176 if (p.set & SF_CX_G)
2178 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2179 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2181 if (p.set & SF_CX_B)
2183 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2184 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2186 if (p.set & SF_CX_A)
2188 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2189 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2191 if (p.set & SF_ROTATE)
2192 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2193 if (p.set & SF_SHEAR)
2194 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2195 if (p.set & SF_PIVOT)
2197 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2198 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2202 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2203 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2205 if (p.set & SF_BLEND)
2206 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2207 if (p.set & SF_FILTER)
2208 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2211 void s_jump(const char* instance, parameters_t p)
2213 instance_t* i = dict_lookup(&instances, instance);
2215 syntaxerror("instance %s not known", instance);
2216 recordChanges(i->history, p, CF_JUMP, 0);
2219 void s_change(const char*instance, parameters_t p, interpolation_t* inter)
2221 instance_t* i = dict_lookup(&instances, instance);
2223 syntaxerror("instance %s not known", instance);
2224 recordChanges(i->history, p, CF_CHANGE, inter);
2227 void s_sweep(const char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2229 instance_t* i = dict_lookup(&instances, instance);
2231 syntaxerror("instance %s not known", instance);
2232 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2235 void s_toggle(const char* instance, U16 flagsOn, U16 flagsOff)
2237 instance_t* i = dict_lookup(&instances, instance);
2239 syntaxerror("instance %s not known", instance);
2240 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2243 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2246 void s_delinstance(const char*instance)
2248 instance_t* i = dict_lookup(&instances, instance);
2250 syntaxerror("instance %s not known", instance);
2252 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2253 swf_SetU16(tag, i->depth);
2254 dict_del(&instances, instance);
2258 void s_schange(const char*instance, parameters_t p, interpolation_t* inter)
2260 instance_t* i = dict_lookup(&instances, instance);
2262 syntaxerror("instance %s not known", instance);
2263 recordChanges(i->history, p, CF_SCHANGE, inter);
2269 syntaxerror(".end unexpected");
2270 switch (stack[stackpos-1].type)
2285 syntaxerror("internal error 1");
2289 // ------------------------------------------------------------------------
2291 typedef int command_func_t(map_t*args);
2293 SRECT parseBox(const char*str)
2295 SRECT r = {0,0,0,0};
2296 float xmin, xmax, ymin, ymax;
2297 char*x = strchr(str, 'x');
2299 if(!strcmp(str, "autocrop")) {
2300 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2304 d1 = strchr(x+1, ':');
2306 d2 = strchr(d1+1, ':');
2308 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2312 else if(d1 && !d2) {
2313 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2319 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2324 r.xmin = (SCOORD)(xmin*20);
2325 r.ymin = (SCOORD)(ymin*20);
2326 r.xmax = (SCOORD)(xmax*20);
2327 r.ymax = (SCOORD)(ymax*20);
2330 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2333 float parseFloat(const char*str)
2337 int parseInt(const char*str)
2342 if(str[0]=='+' || str[0]=='-')
2346 if(str[t]<'0' || str[t]>'9')
2347 syntaxerror("Not an Integer: \"%s\"", str);
2350 static double parseRawTwip(const char*str)
2354 if(str[0]=='+' || str[0]=='-') {
2359 dot = strchr(str, '.');
2363 return sign*parseInt(str);
2365 char* old = strdup(str);
2366 int l=strlen(dot+1);
2369 for(s=str;s<dot-1;s++) {
2370 if(*s<'0' || *s>'9')
2373 syntaxerror("Not a coordinate: \"%s\"", str);
2377 if(*s<'0' || *s>'9')
2380 syntaxerror("Not a coordinate: \"%s\"", str);
2383 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2384 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2387 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2391 return sign*(atoi(str));
2393 return sign*(atoi(str)+0.1*atoi(dot));
2395 return sign*(atoi(str)+0.01*atoi(dot));
2400 static dict_t defines;
2401 static int defines_initialized = 0;
2402 static mem_t define_values;
2404 static double parseNameOrTwip(const char*s)
2408 if(defines_initialized) {
2409 l = (int)dict_lookup(&defines, s);
2412 return *(int*)&define_values.buffer[l-1];
2414 return parseRawTwip(s);
2418 /* automatically generated by yiyiyacc, http://www.quiss.org/yiyiyacc/ */
2419 static double parseExpression(char*s)
2422 memset(chr2index, -1, sizeof(chr2index));
2429 chr2index['\0'] = 7;
2437 int left[10]={11,8,8,8,8,9,9,9,10,10}; //production left side
2438 int plen[10]={1,3,2,3,1,3,3,1,1,3}; //production size
2439 int table[18][12] = {
2440 {0, 4, 0, 0, 5, 6, 0, 0, 1, 2, 3, 0},
2441 {7, 8, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0},
2442 {-4, -4, 9, 10, 0, 0, -4, -4, 0, 0, 0, 0},
2443 {-7, -7, -7, -7, 0, 0, -7, -7, 0, 0, 0, 0},
2444 {0, 0, 0, 0, 5, 6, 0, 0, 0, 11, 3, 0},
2445 {-8, -8, -8, -8, 0, 0, -8, -8, 0, 0, 0, 0},
2446 {0, 4, 0, 0, 5, 6, 0, 0, 12, 2, 3, 0},
2447 {0, 0, 0, 0, 5, 6, 0, 0, 0, 13, 3, 0},
2448 {0, 0, 0, 0, 5, 6, 0, 0, 0, 14, 3, 0},
2449 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 15, 0},
2450 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 16, 0},
2451 {-2, -2, 9, 10, 0, 0, -2, -2, 0, 0, 0, 0},
2452 {7, 8, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0},
2453 {-1, -1, 9, 10, 0, 0, -1, -1, 0, 0, 0, 0},
2454 {-3, -3, 9, 10, 0, 0, -3, -3, 0, 0, 0, 0},
2455 {-5, -5, -5, -5, 0, 0, -5, -5, 0, 0, 0, 0},
2456 {-6, -6, -6, -6, 0, 0, -6, -6, 0, 0, 0, 0},
2457 {-9, -9, -9, -9, 0, 0, -9, -9, 0, 0, 0, 0}};
2465 fprintf(stderr, "Error in expression\n");
2469 if(chr2index[*p]<0) {
2470 action = table[stack[stackpos-1]][4];
2472 while(chr2index[*pnext]<0)
2476 value = parseNameOrTwip(p);
2480 action = table[stack[stackpos-1]][chr2index[*p]];
2483 if(action == accept) {
2484 return values[stack[stackpos-1]];
2485 } else if(action>0) { // shift
2487 fprintf(stderr, "Stack overflow while parsing expression\n");
2490 values[stackpos]=value;
2491 stack[stackpos++]=action;
2493 } else if(action<0) { // reduce
2494 stackpos-=plen[-action];
2495 stack[stackpos] = table[stack[stackpos-1]][left[-action]];
2498 values[stackpos] = values[stackpos+0] + values[stackpos+2];
2501 values[stackpos] = 0 - values[stackpos+1];
2504 values[stackpos] = values[stackpos+0] - values[stackpos+2];
2507 values[stackpos] = values[stackpos+0] * values[stackpos+2];
2510 values[stackpos] = values[stackpos+0] / values[stackpos+2];
2513 values[stackpos] = values[stackpos+1];
2518 fprintf(stderr, "Syntax error in expression\n");
2524 int parseTwip(const char*str)
2526 char*str2 = (char*)str;
2527 int v = (int)(parseExpression(str2)*20);
2531 int parseArc(const char* str)
2533 if (!strcmp(str, "short"))
2535 if (!strcmp(str, "long"))
2537 syntaxerror("invalid value for the arc parameter: %s", str);
2541 int parseDir(const char* str)
2543 if (!strcmp(str, "clockwise"))
2545 if (!strcmp(str, "counterclockwise"))
2547 syntaxerror("invalid value for the dir parameter: %s", str);
2551 int isPoint(const char*str)
2553 if(strchr(str, '('))
2559 SPOINT parsePoint(const char*str)
2563 int l = strlen(str);
2564 char*comma = strchr(str, ',');
2565 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2566 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2567 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2568 p.x = parseTwip(tmp);
2569 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2570 p.y = parseTwip(tmp);
2574 int parseColor2(const char*str, RGBA*color)
2576 int l = strlen(str);
2580 struct {unsigned char r,g,b;char*name;} colors[] =
2581 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2582 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2583 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2584 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2585 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2586 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2587 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2588 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2589 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2590 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2591 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2592 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2596 if(str[0]=='#' && (l==7 || l==9)) {
2597 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2599 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2601 color->r = r; color->g = g; color->b = b; color->a = a;
2604 int len=strlen(str);
2606 if(strchr(str, '/')) {
2607 len = strchr(str, '/')-str;
2608 sscanf(str+len+1,"%02x", &alpha);
2610 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2611 if(!strncmp(str, colors[t].name, len)) {
2616 color->r = r; color->g = g; color->b = b; color->a = a;
2622 RGBA parseColor(const char*str)
2625 if(!parseColor2(str, &c))
2626 syntaxerror("Expression '%s' is not a color", str);
2630 typedef struct _muladd {
2635 MULADD parseMulAdd(const char*str)
2638 char* str2 = (char*)malloc(strlen(str)+5);
2645 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2646 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2647 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2648 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2649 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2650 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2651 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2652 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2653 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2654 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2656 syntaxerror("'%s' is not a valid color transform expression", str);
2658 m.add = (int)(add*256);
2659 m.mul = (int)(mul*256);
2664 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2666 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2667 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2669 if(a<-32768) a=-32768;
2670 if(a>32767) a=32767;
2671 if(m<-32768) m=-32768;
2672 if(m>32767) m=32767;
2678 float parsePxOrPercent(const char*fontname, const char*str)
2680 int l = strlen(str);
2681 if(strchr(str, '%'))
2682 return parsePercent(str);
2683 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2684 float p = atof(str);
2685 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2687 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2691 float parsePercent(const char*str)
2693 int l = strlen(str);
2697 return atoi(str)/100.0;
2699 syntaxerror("Expression '%s' is not a percentage", str);
2702 int isPercent(const char*str)
2704 return str[strlen(str)-1]=='%';
2706 int parseNewSize(const char*str, int size)
2709 return parsePercent(str)*size;
2711 return (int)(atof(str)*20);
2714 int isColor(char*str)
2717 return parseColor2(str, &c);
2720 static const char* lu(map_t* args, char*name)
2722 const char* value = map_lookup(args, name);
2724 map_dump(args, stdout, "");
2725 syntaxerror("internal error 2: value %s should be set", name);
2730 static int c_flash(map_t*args)
2732 const char* filename = map_lookup(args, "filename");
2733 const char* compressstr = lu(args, "compress");
2734 const char* change_modestr = lu(args, "change-sets-all");
2735 const char* exportstr = lu(args, "export");
2736 SRECT bbox = parseBox(lu(args, "bbox"));
2737 int version = parseInt(lu(args, "version"));
2738 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2739 RGBA color = parseColor(lu(args, "background"));
2742 if(!filename || !*filename) {
2743 /* for compatibility */
2744 filename = map_lookup(args, "name");
2745 if(!filename || !*filename) {
2748 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2749 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2753 if(!filename || override_outputname)
2754 filename = outputname;
2756 if(!strcmp(compressstr, "default"))
2757 compress = version>=6;
2758 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2760 else if(!strcmp(compressstr, "no"))
2762 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2764 if(!strcmp(change_modestr, "yes"))
2765 change_sets_all = 1;
2767 if(strcmp(change_modestr, "no"))
2768 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2770 do_exports=atoi(exportstr);
2772 s_swf(filename, bbox, version, fps, compress, color);
2775 int isRelative(const char*str)
2777 return !strncmp(str, "<plus>", 6) ||
2778 !strncmp(str, "<minus>", 7);
2780 const char* getOffset(const char*str)
2782 if(!strncmp(str, "<plus>", 6))
2784 if(!strncmp(str, "<minus>", 7))
2786 syntaxerror("internal error (347)");
2789 int getSign(const char*str)
2791 if(!strncmp(str, "<plus>", 6))
2793 if(!strncmp(str, "<minus>", 7))
2795 syntaxerror("internal error (348)");
2799 static dict_t points;
2800 static mem_t mpoints;
2801 static int points_initialized = 0;
2803 static int c_interpolation(map_t *args)
2806 const char* name = lu(args, "name");
2807 if (dict_lookup(&interpolations, name))
2808 syntaxerror("interpolation %s defined twice", name);
2810 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2811 const char* functionstr = lu(args, "function");
2812 inter->function = 0;
2813 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2814 if (!strcmp(functionstr,interpolationFunctions[i]))
2816 inter->function = i + 1;
2819 if (!inter->function)
2820 syntaxerror("unkown interpolation function %s", functionstr);
2821 inter->speed = parseFloat(lu(args, "speed"));
2822 inter->amplitude = parseTwip(lu(args, "amplitude"));
2823 inter->growth = parseFloat(lu(args, "growth"));
2824 inter->bounces = parseInt(lu(args, "bounces"));
2825 inter->damping = parseFloat(lu(args, "damping"));
2826 inter->slope = parseFloat(lu(args, "slope"));
2828 dict_put2(&interpolations, name, inter);
2832 SPOINT getPoint(SRECT r, const char*name)
2835 if(!strcmp(name, "center")) {
2837 p.x = (r.xmin + r.xmax)/2;
2838 p.y = (r.ymin + r.ymax)/2;
2841 if (!strcmp(name, "bottom-center")) {
2843 p.x = (r.xmin + r.xmax)/2;
2847 if (!strcmp(name, "top-center")) {
2849 p.x = (r.xmin + r.xmax)/2;
2853 if (!strcmp(name, "top-left")) {
2859 if (!strcmp(name, "top-right")) {
2865 if (!strcmp(name, "bottom-right")) {
2871 if (!strcmp(name, "bottom-left")) {
2877 if (!strcmp(name, "left-center")) {
2880 p.y = (r.ymin + r.ymax)/2;
2883 if (!strcmp(name, "right-center")) {
2886 p.y = (r.ymin + r.ymax)/2;
2891 if(points_initialized)
2892 l = (int)dict_lookup(&points, name);
2894 syntaxerror("Invalid point: \"%s\".", name);
2896 return *(SPOINT*)&mpoints.buffer[l-1];
2900 static int texture2(const char*name, const char*object, map_t*args, int errors)
2903 const char*xstr = map_lookup(args, "x");
2904 const char*ystr = map_lookup(args, "y");
2905 const char*widthstr = map_lookup(args, "width");
2906 const char*heightstr = map_lookup(args, "height");
2907 const char*scalestr = map_lookup(args, "scale");
2908 const char*scalexstr = map_lookup(args, "scalex");
2909 const char*scaleystr = map_lookup(args, "scaley");
2910 const char*rotatestr = map_lookup(args, "rotate");
2911 const char* shearstr = map_lookup(args, "shear");
2912 const char* radiusstr = map_lookup(args, "r");
2914 float scalex = 1.0, scaley = 1.0;
2915 float rotate=0, shear=0;
2917 if(!*xstr && !*ystr) {
2919 syntaxerror("x and y must be set");
2922 if(*scalestr && (*scalexstr || *scaleystr)) {
2923 syntaxerror("scale and scalex/scaley can't both be set");
2926 if((*widthstr || *heightstr) && *radiusstr) {
2927 syntaxerror("width/height and radius can't both be set");
2930 widthstr = radiusstr;
2931 heightstr = radiusstr;
2933 if(!*xstr) xstr="0";
2934 if(!*ystr) ystr="0";
2935 if(!*rotatestr) rotatestr="0";
2936 if(!*shearstr) shearstr="0";
2939 scalex = scaley = parsePercent(scalestr);
2940 } else if(*scalexstr || *scaleystr) {
2941 if(scalexstr) scalex = parsePercent(scalexstr);
2942 if(scaleystr) scaley = parsePercent(scaleystr);
2943 } else if(*widthstr || *heightstr) {
2946 s_getBitmapSize(object, &width, &height);
2948 scalex = (float)parseTwip(widthstr)/(float)width;
2950 scaley = (float)parseTwip(heightstr)/(float)height;
2952 x = parseTwip(xstr);
2953 y = parseTwip(ystr);
2954 rotate = parseFloat(rotatestr);
2955 shear = parseFloat(shearstr);
2957 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2962 static int c_texture(map_t*args)
2964 const char*name = lu(args, "instance");
2965 const char*object = lu(args, "character");
2966 return texture2(name, object, args, 1);
2969 static int c_gradient(map_t*args)
2971 const char*name = lu(args, "name");
2972 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2973 int rotate = parseInt(lu(args, "rotate"));
2977 syntaxerror("colon (:) expected");
2979 if(dict_lookup(&gradients, name))
2980 syntaxerror("gradient %s defined twice", name);
2982 s_gradient(name, text, radial, rotate);
2984 /* check whether we also have placement information,
2985 which would make this a positioned gradient.
2986 If there is placement information, texture2() will
2987 add a texture, which has priority over the gradient.
2989 texture2(name, name, args, 0);
2993 static const char* checkFiltername(map_t* args)
2995 const char* name = lu(args, "name");
2996 if (strchr(name, ','))
2997 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
3001 static int c_blur(map_t*args)
3003 const char*name = checkFiltername(args);
3004 const char*blurstr = lu(args, "blur");
3005 const char*blurxstr = lu(args, "blurx");
3006 const char*blurystr = lu(args, "blury");
3007 float blurx=1.0, blury=1.0;
3009 blurx = parseFloat(blurstr);
3010 blury = parseFloat(blurstr);
3013 blurx = parseFloat(blurxstr);
3015 blury = parseFloat(blurystr);
3016 int passes = parseInt(lu(args, "passes"));
3017 s_blur(name, blurx, blury, passes);
3021 static int c_gradientglow(map_t*args)
3023 const char*name = checkFiltername(args);
3024 const char*gradient = lu(args, "gradient");
3025 const char*blurstr = lu(args, "blur");
3026 const char*blurxstr = lu(args, "blurx");
3027 const char*blurystr = lu(args, "blury");
3028 float blurx=1.0, blury=1.0;
3030 blurx = parseFloat(blurstr);
3031 blury = parseFloat(blurstr);
3034 blurx = parseFloat(blurxstr);
3036 blury = parseFloat(blurystr);
3038 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3039 float distance = parseFloat(lu(args, "distance"));
3040 float strength = parseFloat(lu(args, "strength"));
3041 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3042 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3043 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3044 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3045 int passes = parseInt(lu(args, "passes"));
3047 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3051 static int c_dropshadow(map_t*args)
3053 const char*name = checkFiltername(args);
3054 RGBA color = parseColor(lu(args, "color"));
3055 const char*blurstr = lu(args, "blur");
3056 const char*blurxstr = lu(args, "blurx");
3057 const char*blurystr = lu(args, "blury");
3058 float blurx=1.0, blury=1.0;
3060 blurx = parseFloat(blurstr);
3061 blury = parseFloat(blurstr);
3064 blurx = parseFloat(blurxstr);
3066 blury = parseFloat(blurystr);
3068 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3069 float distance = parseFloat(lu(args, "distance"));
3070 float strength = parseFloat(lu(args, "strength"));
3071 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3072 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3073 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3074 int passes = parseInt(lu(args, "passes"));
3076 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3080 static int c_bevel(map_t*args)
3082 const char*name = checkFiltername(args);
3083 RGBA shadow = parseColor(lu(args, "shadow"));
3084 RGBA highlight = parseColor(lu(args, "highlight"));
3085 const char*blurstr = lu(args, "blur");
3086 const char*blurxstr = lu(args, "blurx");
3087 const char*blurystr = lu(args, "blury");
3088 float blurx=1.0, blury=1.0;
3090 blurx = parseFloat(blurstr);
3091 blury = parseFloat(blurstr);
3094 blurx = parseFloat(blurxstr);
3096 blury = parseFloat(blurystr);
3098 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3099 float distance = parseFloat(lu(args, "distance"));
3100 float strength = parseFloat(lu(args, "strength"));
3101 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3102 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3103 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3104 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3105 int passes = parseInt(lu(args, "passes"));
3107 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3111 static int c_define(map_t*args)
3113 const char*name = lu(args, "name");
3114 const char*value = lu(args, "value");
3116 if(!defines_initialized) {
3117 dict_init(&defines);
3118 mem_init(&define_values);
3119 defines_initialized = 1;
3121 int val = parseTwip(value);
3122 int pos = mem_put(&define_values, &val, sizeof(val));
3124 string_set(&s, name);
3125 dict_put(&defines, s, (void*)(pos+1));
3128 static int c_point(map_t*args)
3130 const char*name = lu(args, "name");
3134 if(!points_initialized) {
3137 points_initialized = 1;
3139 p.x = parseTwip(lu(args, "x"));
3140 p.y = parseTwip(lu(args, "y"));
3141 pos = mem_put(&mpoints, &p, sizeof(p));
3142 string_set(&s1, name);
3143 dict_put(&points, s1, (void*)(pos+1));
3146 static int c_play(map_t*args)
3148 const char*name = lu(args, "name");
3149 const char*loop = lu(args, "loop");
3150 const char*nomultiple = lu(args, "nomultiple");
3152 if(!strcmp(nomultiple, "nomultiple"))
3155 nm = parseInt(nomultiple);
3157 if(s_playsound(name, parseInt(loop), nm, 0)) {
3159 } else if(s_swf3action(name, "play")) {
3165 static int c_stop(map_t*args)
3167 const char*name = map_lookup(args, "name");
3169 if(s_playsound(name, 0,0,1))
3171 else if(s_swf3action(name, "stop"))
3173 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3177 static int c_nextframe(map_t*args)
3179 const char*name = lu(args, "name");
3181 if(s_swf3action(name, "nextframe")) {
3184 syntaxerror("I don't know anything about movie \"%s\"", name);
3188 static int c_previousframe(map_t*args)
3190 const char*name = lu(args, "name");
3192 if(s_swf3action(name, "previousframe")) {
3195 syntaxerror("I don't know anything about movie \"%s\"", name);
3199 static int c_movement(map_t*args, int type)
3201 const char*instance = lu(args, "name");
3203 const char* xstr="";
3204 const char* ystr="";
3209 xstr = lu(args, "x");
3210 ystr = lu(args, "y");
3212 s_getParameters(instance, &p);
3217 if(isRelative(xstr))
3219 if(type == PT_PUT || type == PT_STARTCLIP)
3220 syntaxerror("relative x values not allowed for initial put or startclip");
3221 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3225 p.x = parseTwip(xstr);
3231 if(isRelative(ystr))
3233 if(type == PT_PUT || type == PT_STARTCLIP)
3234 syntaxerror("relative y values not allowed for initial put or startclip");
3235 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3239 p.y = parseTwip(ystr);
3244 if (change_sets_all)
3252 const char* interstr = lu(args, "interpolation");
3253 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3255 syntaxerror("unkown interpolation %s", interstr);
3256 s_change(instance, p, inter);
3261 const char* interstr = lu(args, "interpolation");
3262 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3264 syntaxerror("unkown interpolation %s", interstr);
3265 s_schange(instance, p, inter);
3270 const char* rstr = lu(args, "r");
3271 int radius = parseTwip(rstr);
3273 syntaxerror("sweep not possible: radius must be greater than 0.");
3274 const char* dirstr = lu(args, "dir");
3275 int clockwise = parseDir(dirstr);
3276 const char* arcstr = lu(args, "arc");
3277 int short_arc = parseArc(arcstr);
3278 const char* interstr = lu(args, "interpolation");
3279 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3281 syntaxerror("unkown interpolation %s", interstr);
3282 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3289 static int c_placement(map_t*args, int type)
3291 const char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3292 const char*character = 0;
3294 const char* luminancestr = lu(args, "luminance");
3295 const char* scalestr = lu(args, "scale");
3296 const char* scalexstr = lu(args, "scalex");
3297 const char* scaleystr = lu(args, "scaley");
3298 const char* rotatestr = lu(args, "rotate");
3299 const char* shearstr = lu(args, "shear");
3300 const char* xstr="", *pivotstr="";
3301 const char* ystr="", *anglestr="";
3302 const char*above = lu(args, "above"); /*FIXME*/
3303 const char*below = lu(args, "below");
3304 const char* rstr = lu(args, "red");
3305 const char* gstr = lu(args, "green");
3306 const char* bstr = lu(args, "blue");
3307 const char* astr = lu(args, "alpha");
3308 const char* pinstr = lu(args, "pin");
3309 const char* as = map_lookup(args, "as");
3310 const char* blendmode = lu(args, "blend");
3311 const char* filterstr = lu(args, "filter");
3322 { // (?) .rotate or .arcchange
3323 pivotstr = lu(args, "pivot");
3324 anglestr = lu(args, "angle");
3328 xstr = lu(args, "x");
3329 ystr = lu(args, "y");
3333 luminance = parseMulAdd(luminancestr);
3337 luminance.mul = 256;
3342 if(scalexstr[0]||scaleystr[0])
3343 syntaxerror("scalex/scaley and scale cannot both be set");
3344 scalexstr = scaleystr = scalestr;
3347 if(type == PT_PUT || type == PT_STARTCLIP) {
3349 character = lu(args, "character");
3350 parameters_clear(&p);
3351 } else if (type == PT_BUTTON) {
3352 character = lu(args, "name");
3353 parameters_clear(&p);
3356 s_getParameters(instance, &p);
3362 if(isRelative(xstr))
3364 if(type == PT_PUT || type == PT_STARTCLIP)
3365 syntaxerror("relative x values not allowed for initial put or startclip");
3366 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3370 p.x = parseTwip(xstr);
3376 if(isRelative(ystr))
3378 if(type == PT_PUT || type == PT_STARTCLIP)
3379 syntaxerror("relative y values not allowed for initial put or startclip");
3380 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3384 p.y = parseTwip(ystr);
3389 /* scale, scalex, scaley */
3391 oldbbox = s_getCharBBox(character);
3393 oldbbox = s_getInstanceBBox(instance);
3394 oldwidth = oldbbox.xmax - oldbbox.xmin;
3395 oldheight = oldbbox.ymax - oldbbox.ymin;
3402 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3403 set = set | SF_SCALEX;
3411 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3412 set = set | SF_SCALEY;
3418 if(isRelative(rotatestr))
3419 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3421 p.rotate = parseFloat(rotatestr);
3422 set = set | SF_ROTATE;
3428 if(isRelative(shearstr))
3429 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3431 p.shear = parseFloat(shearstr);
3432 set = set | SF_SHEAR;
3437 if(isPoint(pivotstr))
3438 p.pivot = parsePoint(pivotstr);
3440 p.pivot = getPoint(oldbbox, pivotstr);
3441 set = set | SF_PIVOT;
3447 p.pin = parsePoint(pinstr);
3449 p.pin = getPoint(oldbbox, pinstr);
3453 /* color transform */
3455 if(rstr[0] || luminancestr[0])
3459 r = parseMulAdd(rstr);
3462 r.add = p.cxform.r0;
3463 r.mul = p.cxform.r1;
3465 r = mergeMulAdd(r, luminance);
3466 p.cxform.r0 = r.mul;
3467 p.cxform.r1 = r.add;
3468 set = set | SF_CX_R;
3470 if(gstr[0] || luminancestr[0])
3474 g = parseMulAdd(gstr);
3477 g.add = p.cxform.g0;
3478 g.mul = p.cxform.g1;
3480 g = mergeMulAdd(g, luminance);
3481 p.cxform.g0 = g.mul;
3482 p.cxform.g1 = g.add;
3483 set = set | SF_CX_G;
3485 if(bstr[0] || luminancestr[0])
3489 b = parseMulAdd(bstr);
3492 b.add = p.cxform.b0;
3493 b.mul = p.cxform.b1;
3495 b = mergeMulAdd(b, luminance);
3496 p.cxform.b0 = b.mul;
3497 p.cxform.b1 = b.add;
3498 set = set | SF_CX_B;
3502 MULADD a = parseMulAdd(astr);
3503 p.cxform.a0 = a.mul;
3504 p.cxform.a1 = a.add;
3505 set = set | SF_CX_A;
3512 for(t = 0; blendModeNames[t]; t++)
3514 if(!strcmp(blendModeNames[t], blendmode))
3522 syntaxerror("unknown blend mode: '%s'", blendmode);
3524 p.blendmode = blend;
3525 set = set | SF_BLEND;
3530 p.filters = parseFilters((char*)filterstr);
3531 set = set | SF_FILTER;
3534 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3535 warning("As of version 0.8.2 using the .change command to modify an \
3536 object's position on the stage is considered deprecated. Future \
3537 versions may consider x and y parameters for the .change command \
3538 to be illegal; please use the .move command.");
3540 if (change_sets_all)
3547 s_put(instance, character, p);
3551 const char* interstr = lu(args, "interpolation");
3552 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3554 syntaxerror("unkown interpolation %s", interstr);
3555 s_change(instance, p, inter);
3560 const char* interstr = lu(args, "interpolation");
3561 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3563 syntaxerror("unkown interpolation %s", interstr);
3564 s_schange(instance, p, inter);
3568 s_jump(instance, p);
3571 s_startclip(instance, character, p);
3575 s_buttonput(character, as, p);
3577 s_buttonput(character, "shape", p);
3583 static int c_put(map_t*args)
3585 c_placement(args, PT_PUT);
3588 static int c_change(map_t*args)
3590 if (currentframe == 0)
3591 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3592 c_placement(args, PT_CHANGE);
3595 static int c_schange(map_t*args)
3597 c_placement(args, PT_SCHANGE);
3600 static int c_move(map_t* args)
3602 c_movement(args, PT_MOVE);
3605 static int c_smove(map_t* args)
3607 c_movement(args, PT_SMOVE);
3610 static int c_sweep(map_t* args)
3612 c_movement(args, PT_SWEEP);
3615 static int c_arcchange(map_t*args)
3617 c_placement(args, 0);
3620 static int c_jump(map_t*args)
3622 c_placement(args, PT_JUMP);
3625 static int c_startclip(map_t*args)
3627 c_placement(args, PT_STARTCLIP);
3630 static int c_show(map_t*args)
3632 c_placement(args, PT_BUTTON);
3635 static int c_toggle(map_t* args)
3637 const char*instance = lu(args, "name");
3638 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3639 const char* alignstr = lu(args, "fixed_alignment");
3640 if (!strcmp(alignstr, "on"))
3641 flagsOn += IF_FIXED_ALIGNMENT;
3643 if (!strcmp(alignstr, "off"))
3644 flagsOff -= IF_FIXED_ALIGNMENT;
3646 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3647 s_toggle(instance, flagsOn, flagsOff);
3650 static int c_del(map_t*args)
3652 const char*instance = lu(args, "name");
3653 s_delinstance(instance);
3656 static int c_end(map_t*args)
3661 static int c_sprite(map_t*args)
3663 const char* name = lu(args, "name");
3664 const char* scalinggrid = lu(args, "scalinggrid");
3666 if(scalinggrid && *scalinggrid) {
3667 SRECT r = parseBox(scalinggrid);
3674 static int c_frame(map_t*args)
3676 const char*framestr = lu(args, "n");
3677 const char*cutstr = lu(args, "cut");
3679 const char*name = lu(args, "name");
3680 const char*anchor = lu(args, "anchor");
3683 if(!strcmp(anchor, "anchor") && !*name)
3688 if(strcmp(cutstr, "no"))
3690 if(isRelative(framestr)) {
3691 frame = s_getframe();
3692 if(getSign(framestr)<0)
3693 syntaxerror("relative frame expressions must be positive");
3694 frame += parseInt(getOffset(framestr));
3697 frame = parseInt(framestr);
3698 if(s_getframe() >= frame
3699 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3700 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3702 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3705 static int c_primitive(map_t*args)
3707 const char*name = lu(args, "name");
3708 const char*command = lu(args, "commandname");
3709 int width=0, height=0, r=0;
3710 int linewidth = parseTwip(lu(args, "line"));
3711 const char*colorstr = lu(args, "color");
3712 RGBA color = parseColor(colorstr);
3713 const char*fillstr = lu(args, "fill");
3718 const char* outline=0;
3720 if(!strcmp(command, "circle"))
3722 else if(!strcmp(command, "filled"))
3726 width = parseTwip(lu(args, "width"));
3727 height = parseTwip(lu(args, "height"));
3728 } else if (type==1) {
3729 r = parseTwip(lu(args, "r"));
3730 } else if (type==2) {
3731 outline = lu(args, "outline");
3734 if(!strcmp(fillstr, "fill"))
3736 if(!strcmp(fillstr, "none"))
3738 if(width<0 || height<0 || linewidth<0 || r<0)
3739 syntaxerror("values width, height, line, r must be positive");
3741 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3742 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3743 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3747 static int c_textshape(map_t*args)
3749 const char*name = lu(args, "name");
3750 const char*text = lu(args, "text");
3751 const char*font = lu(args, "font");
3752 float size = parsePxOrPercent(font, lu(args, "size"));
3754 s_textshape(name, font, size, text);
3758 static int c_swf(map_t*args)
3760 const char*name = lu(args, "name");
3761 const char*filename = lu(args, "filename");
3762 const char*command = lu(args, "commandname");
3763 if(!strcmp(command, "shape"))
3764 warning("Please use .swf instead of .shape");
3765 s_includeswf(name, filename);
3769 static int c_font(map_t*args)
3771 const char*name = lu(args, "name");
3772 const char*filename = lu(args, "filename");
3773 s_font(name, filename);
3777 static int c_sound(map_t*args)
3779 const char*name = lu(args, "name");
3780 const char*filename = lu(args, "filename");
3781 s_sound(name, filename);
3785 static int c_text(map_t*args)
3787 const char*name = lu(args, "name");
3788 const char*text = lu(args, "text");
3789 const char*font = lu(args, "font");
3790 float size = parsePxOrPercent(font, lu(args, "size"));
3791 RGBA color = parseColor(lu(args, "color"));
3792 s_text(name, font, text, (int)(size*100), color);
3796 static int c_soundtrack(map_t*args)
3801 static int c_quicktime(map_t*args)
3803 const char*name = lu(args, "name");
3804 const char*url = lu(args, "url");
3805 s_quicktime(name, url);
3809 static int c_image(map_t*args)
3811 const char*command = lu(args, "commandname");
3812 const char*name = lu(args, "name");
3813 const char*filename = lu(args, "filename");
3814 if(!strcmp(command,"jpeg")) {
3815 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3816 s_image(name, "jpeg", filename, quality);
3818 s_image(name, "png", filename, 0);
3823 static int c_outline(map_t*args)
3825 const char*name = lu(args, "name");
3826 const char*format = lu(args, "format");
3830 syntaxerror("colon (:) expected");
3832 s_outline(name, format, text);
3836 int fakechar(map_t*args)
3838 const char*name = lu(args, "name");
3839 s_box(name, 0, 0, black, 20, 0);
3843 static int c_egon(map_t*args) {return fakechar(args);}
3844 static int c_button(map_t*args) {
3845 const char*name = lu(args, "name");
3849 static int current_button_flags = 0;
3850 static int c_on_press(map_t*args)
3852 const char*position = lu(args, "position");
3853 const char*action = "";
3854 if(!strcmp(position, "inside")) {
3855 current_button_flags |= BC_OVERUP_OVERDOWN;
3856 } else if(!strcmp(position, "outside")) {
3857 //current_button_flags |= BC_IDLE_OUTDOWN;
3858 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3859 } else if(!strcmp(position, "anywhere")) {
3860 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3863 if(type == RAWDATA) {
3865 s_buttonaction(current_button_flags, action);
3866 current_button_flags = 0;
3872 static int c_on_release(map_t*args)
3874 const char*position = lu(args, "position");
3875 const char*action = "";
3876 if(!strcmp(position, "inside")) {
3877 current_button_flags |= BC_OVERDOWN_OVERUP;
3878 } else if(!strcmp(position, "outside")) {
3879 current_button_flags |= BC_OUTDOWN_IDLE;
3880 } else if(!strcmp(position, "anywhere")) {
3881 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3884 if(type == RAWDATA) {
3886 s_buttonaction(current_button_flags, action);
3887 current_button_flags = 0;
3893 static int c_on_move_in(map_t*args)
3895 const char*position = lu(args, "state");
3896 const char*action = "";
3897 if(!strcmp(position, "pressed")) {
3898 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3899 } else if(!strcmp(position, "not_pressed")) {
3900 current_button_flags |= BC_IDLE_OVERUP;
3901 } else if(!strcmp(position, "any")) {
3902 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3905 if(type == RAWDATA) {
3907 s_buttonaction(current_button_flags, action);
3908 current_button_flags = 0;
3914 static int c_on_move_out(map_t*args)
3916 const char*position = lu(args, "state");
3917 const char*action = "";
3918 if(!strcmp(position, "pressed")) {
3919 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3920 } else if(!strcmp(position, "not_pressed")) {
3921 current_button_flags |= BC_OVERUP_IDLE;
3922 } else if(!strcmp(position, "any")) {
3923 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3926 if(type == RAWDATA) {
3928 s_buttonaction(current_button_flags, action);
3929 current_button_flags = 0;
3935 static int c_on_key(map_t*args)
3937 const char*key = lu(args, "key");
3938 const char*action = "";
3939 if(strlen(key)==1) {
3942 current_button_flags |= 0x4000 + (key[0]*0x200);
3944 syntaxerror("invalid character: %c"+key[0]);
3949 <ctrl-x> = 0x200*(x-'a')
3953 syntaxerror("invalid key: %s",key);
3956 if(type == RAWDATA) {
3958 s_buttonaction(current_button_flags, action);
3959 current_button_flags = 0;
3966 static int c_edittext(map_t*args)
3968 //"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"},
3969 const char*name = lu(args, "name");
3970 const char*font = lu(args, "font");
3971 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3972 int width = parseTwip(lu(args, "width"));
3973 int height = parseTwip(lu(args, "height"));
3974 const char*text = lu(args, "text");
3975 RGBA color = parseColor(lu(args, "color"));
3976 int maxlength = parseInt(lu(args, "maxlength"));
3977 const char*variable = lu(args, "variable");
3978 const char*passwordstr = lu(args, "password");
3979 const char*wordwrapstr = lu(args, "wordwrap");
3980 const char*multilinestr = lu(args, "multiline");
3981 const char*htmlstr = lu(args, "html");
3982 const char*noselectstr = lu(args, "noselect");
3983 const char*readonlystr = lu(args, "readonly");
3984 const char*borderstr = lu(args, "border");
3985 const char*autosizestr = lu(args, "autosize");
3986 const char*alignstr = lu(args, "align");
3990 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3991 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3992 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3993 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3994 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3995 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3996 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3997 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3998 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3999 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
4000 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
4001 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
4002 else syntaxerror("Unknown alignment: %s", alignstr);
4004 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
4008 static int c_morphshape(map_t*args) {return fakechar(args);}
4009 static int c_movie(map_t*args) {return fakechar(args);}
4011 static char* readfile(char*filename)
4013 FILE*fi = fopen(filename, "rb");
4017 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
4018 fseek(fi, 0, SEEK_END);
4020 fseek(fi, 0, SEEK_SET);
4021 text = rfx_alloc(l+1);
4022 fread(text, l, 1, fi);
4028 static int c_action(map_t*args)
4030 const char* filename = map_lookup(args, "filename");
4031 if(!filename ||!*filename) {
4033 if(type != RAWDATA) {
4034 syntaxerror("colon (:) expected");
4038 s_action(readfile((char*)filename));
4044 static int c_initaction(map_t*args)
4046 const char* character = lu(args, "name");
4047 const char* filename = map_lookup(args, "filename");
4048 if(!filename ||!*filename) {
4050 if(type != RAWDATA) {
4051 syntaxerror("colon (:) expected");
4053 s_initaction(character, text);
4055 s_initaction(character, readfile((char*)filename));
4063 command_func_t* func;
4066 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1"},
4067 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
4068 // "import" type stuff
4069 {"swf", c_swf, "name filename"},
4070 {"shape", c_swf, "name filename"},
4071 {"jpeg", c_image, "name filename quality=80%"},
4072 {"png", c_image, "name filename"},
4073 {"movie", c_movie, "name filename"},
4074 {"sound", c_sound, "name filename"},
4075 {"font", c_font, "name filename glyphs="},
4076 {"soundtrack", c_soundtrack, "filename"},
4077 {"quicktime", c_quicktime, "url"},
4079 // generators of primitives
4081 {"define", c_define, "name value=0"},
4082 {"point", c_point, "name x=0 y=0"},
4083 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4084 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4085 {"outline", c_outline, "name format=simple"},
4086 {"textshape", c_textshape, "name font size=100% text"},
4089 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4090 {"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"},
4091 {"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"},
4092 {"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"},
4094 // character generators
4095 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4096 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4097 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4099 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4100 {"text", c_text, "name text font size=100% color=white"},
4101 {"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="},
4102 {"morphshape", c_morphshape, "name start end"},
4103 {"button", c_button, "name"},
4104 {"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="},
4105 {"on_press", c_on_press, "position=inside"},
4106 {"on_release", c_on_release, "position=anywhere"},
4107 {"on_move_in", c_on_move_in, "state=not_pressed"},
4108 {"on_move_out", c_on_move_out, "state=not_pressed"},
4109 {"on_key", c_on_key, "key=any"},
4112 {"play", c_play, "name loop=0 @nomultiple=0"},
4113 {"stop", c_stop, "name= "},
4114 {"nextframe", c_nextframe, "name"},
4115 {"previousframe", c_previousframe, "name"},
4117 // object placement tags
4118 {"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="},
4119 {"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="},
4120 {"move", c_move, "name x= y= interpolation=linear"},
4121 {"smove", c_smove, "name x= y= interpolation=linear"},
4122 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4123 {"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"},
4124 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4125 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4126 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4127 {"del", c_del, "name"},
4128 // virtual object placement
4129 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4131 {"toggle", c_toggle, "name fixed_alignment="},
4133 // commands which start a block
4134 //startclip (see above)
4135 {"sprite", c_sprite, "name scalinggrid="},
4136 {"action", c_action, "filename="},
4137 {"initaction", c_initaction, "name filename="},
4143 static map_t parseArguments(char*command, char*pattern)
4159 string_set(&t1, "commandname");
4160 string_set(&t2, command);
4161 map_put(&result, t1, t2);
4163 if(!pattern || !*pattern)
4170 if(!strncmp("<i> ", x, 3)) {
4172 if(type == COMMAND || type == RAWDATA) {
4174 syntaxerror("character name expected");
4176 name[pos].str = "instance";
4178 value[pos].str = text;
4179 value[pos].len = strlen(text);
4183 if(type == ASSIGNMENT)
4186 name[pos].str = "character";
4188 value[pos].str = text;
4189 value[pos].len = strlen(text);
4197 isboolean[pos] = (x[0] =='@');
4210 name[pos].len = d-x;
4215 name[pos].len = e-x;
4216 value[pos].str = e+1;
4217 value[pos].len = d-e-1;
4225 /* for(t=0;t<len;t++) {
4226 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4227 isboolean[t]?"(boolean)":"");
4232 if(type == RAWDATA || type == COMMAND) {
4237 // first, search for boolean arguments
4238 for(pos=0;pos<len;pos++)
4240 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4242 if(type == ASSIGNMENT)
4244 value[pos].str = text;
4245 value[pos].len = strlen(text);
4246 /*printf("setting boolean parameter %s (to %s)\n",
4247 strdup_n(name[pos], namelen[pos]),
4248 strdup_n(value[pos], valuelen[pos]));*/
4253 // second, search for normal arguments
4255 for(pos=0;pos<len;pos++)
4257 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4258 (type != ASSIGNMENT && !set[pos])) {
4260 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4262 if(type == ASSIGNMENT)
4265 value[pos].str = text;
4266 value[pos].len = strlen(text);
4268 printf("setting parameter %s (to %s)\n",
4269 strdup_n(name[pos].str, name[pos].len),
4270 strdup_n(value[pos].str, value[pos].len));
4276 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4280 for(t=0;t<len;t++) {
4281 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4284 for(t=0;t<len;t++) {
4285 if(value[t].str && value[t].str[0] == '*') {
4286 //relative default- take value from some other parameter
4288 for(s=0;s<len;s++) {
4289 if(value[s].len == value[t].len-1 &&
4290 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4291 value[t].str = value[s].str;
4294 if(value[t].str == 0) {
4296 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4300 /* ok, now construct the dictionary from the parameters */
4304 map_put(&result, name[t], value[t]);
4308 static void parseArgumentsForCommand(char*command)
4313 msg("<verbose> parse Command: %s (line %d)", command, line);
4315 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4316 if(!strcmp(arguments[t].command, command)) {
4318 /* ugly hack- will be removed soon (once documentation and .sc generating
4319 utilities have been changed) */
4320 if(!strcmp(command, "swf") && !stackpos) {
4321 warning("Please use .flash instead of .swf- this will be mandatory soon");
4326 args = parseArguments(command, arguments[t].arguments);
4332 syntaxerror("command %s not known", command);
4335 // catch missing .flash directives at the beginning of a file
4336 if(strcmp(command, "flash") && !stackpos)
4338 syntaxerror("No movie defined- use .flash first");
4343 printf(".%s\n", command);fflush(stdout);
4344 map_dump(&args, stdout, "\t");fflush(stdout);
4348 (*arguments[nr].func)(&args);
4350 if(!strcmp(command, "action") || !strcmp(command, "initaction") ||
4351 !strcmp(command, "outline") || !strcmp(command, "gradient")) {
4353 if(type != RAWDATA) {
4354 syntaxerror("colon (:) expected");
4363 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4364 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4365 * No syntax checking is done */
4366 static void analyseArgumentsForCommand(char*command)
4370 const char* fontfile;
4372 U8* glyphs_to_include;
4373 msg("<verbose> analyse Command: %s (line %d)", command, line);
4375 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4377 if(!strcmp(arguments[t].command, command))
4379 args = parseArguments(command, arguments[t].arguments);
4385 printf(".%s\n", command);fflush(stdout);
4386 map_dump(&args, stdout, "\t");fflush(stdout);
4388 const char* name = lu(&args, "name");
4389 if (!strcmp(command, "font"))
4391 if(dict_lookup(&fonts, name))
4392 syntaxerror("font %s defined twice", name);
4395 fontfile = lu(&args, "filename");
4396 font = swf_LoadFont(fontfile);
4398 warning("Couldn't open font file \"%s\"", fontfile);
4399 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4400 memset(font, 0, sizeof(SWFFONT));
4404 swf_FontPrepareForEditText(font);
4405 glyphs_to_include = (U8*)lu(&args, "glyphs");
4406 if (!strcmp(glyphs_to_include, "all"))
4408 swf_FontUseAll(font);
4409 font->use->glyphs_specified = 1;
4413 if (strcmp (glyphs_to_include, ""))
4415 swf_FontUseUTF8(font, glyphs_to_include);
4416 font->use->glyphs_specified = 1;
4419 swf_FontInitUsage(font);
4422 dict_put2(&fonts, name, font);
4426 SWFFONT* font = dict_lookup(&fonts, lu(&args, "font"));
4428 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4430 if (font->use && !font->use->glyphs_specified)
4432 if (!strcmp(command, "edittext"))
4434 swf_FontUseAll(font);
4435 font->use->glyphs_specified = 1;
4438 swf_FontUseUTF8(font, (U8*)lu(&args, "text"));
4445 void skipParameters()
4449 while (type != COMMAND);
4453 void findFontUsage()
4455 char* fontRelated = "font;text;textshape;edittext;";
4456 while(!noMoreTokens())
4460 syntaxerror("command expected");
4461 if (strstr(fontRelated, text))
4462 analyseArgumentsForCommand(text);
4464 if(strcmp(text, "end"))
4474 cleanUp = &freeFontDictionary;
4478 int main (int argc,char ** argv)
4481 processargs(argc, argv);
4482 initLog(0,-1,0,0,-1,verbose);
4485 args_callback_usage(argv[0]);
4489 file = generateTokens(filename);
4491 fprintf(stderr, "parser returned error.\n");
4498 while(!noMoreTokens()) {
4501 syntaxerror("command expected");
4502 parseArgumentsForCommand(text);