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, 1, free_instance);
344 dict_free_all(&characters, 1, free);
345 dict_free_all(&images, 1, free);
346 dict_free_all(&textures, 1, free);
347 dict_free_all(&outlines, 1, free_outline);
348 dict_free_all(&gradients, 1, free_gradient);
349 dict_free_all(&filters, 1, free);
350 dict_free_all(&fonts, 1, free_font);
351 dict_free_all(&sounds, 1, free);
352 dict_free_all(&interpolations, 1, free);
356 static void freeFontDictionary()
358 dict_free_all(&fonts, 1, 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_put(&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_put(&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_put(&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_put(&interpolations, "linear", new);
476 new = (interpolation_t*)malloc(sizeof(interpolation_t));
477 new->function = IF_QUAD_IN;
479 dict_put(&interpolations, "quadIn", new);
480 new = (interpolation_t*)malloc(sizeof(interpolation_t));
481 new->function = IF_QUAD_OUT;
483 dict_put(&interpolations, "quadOut", new);
484 new = (interpolation_t*)malloc(sizeof(interpolation_t));
485 new->function = IF_QUAD_IN_OUT;
487 dict_put(&interpolations, "quadInOut", new);
489 new = (interpolation_t*)malloc(sizeof(interpolation_t));
490 new->function = IF_CUBIC_IN;
492 dict_put(&interpolations, "cubicIn", new);
493 new = (interpolation_t*)malloc(sizeof(interpolation_t));
494 new->function = IF_CUBIC_OUT;
496 dict_put(&interpolations, "cubicOut", new);
497 new = (interpolation_t*)malloc(sizeof(interpolation_t));
498 new->function = IF_CUBIC_IN_OUT;
500 dict_put(&interpolations, "cubicInOut", new);
502 new = (interpolation_t*)malloc(sizeof(interpolation_t));
503 new->function = IF_QUART_IN;
505 dict_put(&interpolations, "quartIn", new);
506 new = (interpolation_t*)malloc(sizeof(interpolation_t));
507 new->function = IF_QUART_OUT;
509 dict_put(&interpolations, "quartOut", new);
510 new = (interpolation_t*)malloc(sizeof(interpolation_t));
511 new->function = IF_QUART_IN_OUT;
513 dict_put(&interpolations, "quartInOut", new);
515 new = (interpolation_t*)malloc(sizeof(interpolation_t));
516 new->function = IF_QUINT_IN;
518 dict_put(&interpolations, "quintIn", new);
519 new = (interpolation_t*)malloc(sizeof(interpolation_t));
520 new->function = IF_QUINT_OUT;
522 dict_put(&interpolations, "quintOut", new);
523 new = (interpolation_t*)malloc(sizeof(interpolation_t));
524 new->function = IF_QUINT_IN_OUT;
526 dict_put(&interpolations, "quintInOut", new);
528 new = (interpolation_t*)malloc(sizeof(interpolation_t));
529 new->function = IF_CIRCLE_IN;
530 dict_put(&interpolations, "circleIn", new);
531 new = (interpolation_t*)malloc(sizeof(interpolation_t));
532 new->function = IF_CIRCLE_OUT;
533 dict_put(&interpolations, "circleOut", new);
534 new = (interpolation_t*)malloc(sizeof(interpolation_t));
535 new->function = IF_CIRCLE_IN_OUT;
536 dict_put(&interpolations, "circleInOut", new);
538 new = (interpolation_t*)malloc(sizeof(interpolation_t));
539 new->function = IF_EXPONENTIAL_IN;
540 dict_put(&interpolations, "exponentialIn", new);
541 new = (interpolation_t*)malloc(sizeof(interpolation_t));
542 new->function = IF_EXPONENTIAL_OUT;
543 dict_put(&interpolations, "exponentialOut", new);
544 new = (interpolation_t*)malloc(sizeof(interpolation_t));
545 new->function = IF_EXPONENTIAL_IN_OUT;
546 dict_put(&interpolations, "exponentialInOut", new);
548 new = (interpolation_t*)malloc(sizeof(interpolation_t));
549 new->function = IF_SINE_IN;
550 dict_put(&interpolations, "sineIn", new);
551 new = (interpolation_t*)malloc(sizeof(interpolation_t));
552 new->function = IF_SINE_OUT;
553 dict_put(&interpolations, "sineOut", new);
554 new = (interpolation_t*)malloc(sizeof(interpolation_t));
555 new->function = IF_SINE_IN_OUT;
556 dict_put(&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_put(&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_put(&filters, "no_filters", dummy);
577 noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
579 dict_put(&filters, "no_blur", noBlur);
580 noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
582 noBevel->composite = 1;
583 dict_put(&filters, "no_bevel", noBevel);
584 noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
585 noDropshadow->passes = 1;
586 noDropshadow->composite = 1;
587 dict_put(&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_put(&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, 16);
613 dict_init(&images, 16);
614 dict_init(&textures, 16);
615 dict_init(&outlines, 16);
616 dict_init(&gradients, 16);
617 dict_init(&filters, 16);
618 dict_init(&instances, 16);
619 dict_init(&sounds, 16);
620 dict_init(&interpolations, 16);
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));
636 idmap[0]=1; //main movie has ID 0
641 void s_sprite(const char*name, SRECT*scalegrid)
643 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
644 swf_SetU16(tag, id); //id
645 swf_SetU16(tag, 0); //frames
647 memset(&stack[stackpos], 0, sizeof(stack[0]));
648 stack[stackpos].type = 1;
649 stack[stackpos].oldframe = currentframe;
650 stack[stackpos].olddepth = currentdepth;
651 stack[stackpos].oldrect = currentrect;
652 stack[stackpos].oldinstances = instances;
653 stack[stackpos].tag = tag;
654 stack[stackpos].id = id;
655 stack[stackpos].name = strdup(name);
657 stack[stackpos].scalegrid = *scalegrid;
659 memset(&stack[stackpos].scalegrid, 0, sizeof(SRECT));
662 /* FIXME: those four fields should be bundled together */
663 dict_init(&instances, 16);
666 memset(¤trect, 0, sizeof(currentrect));
672 typedef struct _buttonrecord
680 typedef struct _button
684 buttonrecord_t records[4];
687 static button_t mybutton;
689 void s_button(const char*name)
691 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
692 swf_SetU16(tag, id); //id
693 swf_ButtonSetFlags(tag, 0); //menu=no
695 memset(&mybutton, 0, sizeof(mybutton));
697 memset(&stack[stackpos], 0, sizeof(stack[0]));
698 stack[stackpos].type = 3;
699 stack[stackpos].tag = tag;
700 stack[stackpos].id = id;
701 stack[stackpos].name = strdup(name);
702 stack[stackpos].oldrect = currentrect;
703 memset(¤trect, 0, sizeof(currentrect));
708 void s_buttonput(const char*character, const char*as, parameters_t p)
710 character_t* c = dict_lookup(&characters, character);
713 const char*o = as,*s = as;
715 if(!stackpos || (stack[stackpos-1].type != 3)) {
716 syntaxerror(".show may only appear in .button");
719 syntaxerror("character %s not known (in .shape %s)", character, character);
721 if(mybutton.endofshapes) {
722 syntaxerror("a .do may not precede a .show", character, character);
725 m = s_instancepos(c->size, &p);
733 if(*s==',' || *s==0) {
734 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
735 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
736 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
737 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
738 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
739 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
746 static void setbuttonrecords(TAG*tag)
748 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
749 if(!mybutton.endofshapes) {
752 if(!mybutton.records[3].set) {
753 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
757 if(mybutton.records[t].set) {
758 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
761 swf_SetU8(tag,0); // end of button records
762 mybutton.endofshapes = 1;
766 void s_buttonaction(int flags, const char*action)
772 if(!stackpos || !stack[stackpos-1].tag ||
773 stack[stackpos-1].tag->id != ST_DEFINEBUTTON2) {
774 syntaxerror("Need to be inside a button for .on_* commands");
776 setbuttonrecords(stack[stackpos-1].tag);
778 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
780 syntaxerror("Couldn't compile ActionScript");
783 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
784 swf_ActionSet(stack[stackpos-1].tag, a);
785 mybutton.nr_actions++;
790 static void setactionend(TAG*tag)
792 if(!mybutton.nr_actions) {
793 /* no actions means we didn't have an actionoffset,
794 which means we can't signal the end of the
795 buttonaction records, so, *sigh*, we have
796 to insert a dummy record */
797 swf_SetU16(tag, 0); //offset
798 swf_SetU16(tag, 0); //condition
799 swf_SetU8(tag, 0); //action
803 static void s_endButton()
806 setbuttonrecords(stack[stackpos-1].tag);
807 setactionend(stack[stackpos-1].tag);
810 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
814 tag = stack[stackpos].tag;
815 currentrect = stack[stackpos].oldrect;
817 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
818 free(stack[stackpos].name);
821 TAG* removeFromTo(TAG*from, TAG*to)
823 TAG*save = from->prev;
825 TAG*next = from->next;
826 if(swf_isAllowedSpriteTag(from))
827 swf_DeleteTag(0, from);
834 static int parametersChange(history_t* history, int frame)
838 willChange = willChange || history_change(history, frame, "x");
839 willChange = willChange || history_change(history, frame, "y");
840 willChange = willChange || history_change(history, frame, "scalex");
841 willChange = willChange || history_change(history, frame, "scaley");
842 willChange = willChange || history_change(history, frame, "cxform.r0");
843 willChange = willChange || history_change(history, frame, "cxform.g0");
844 willChange = willChange || history_change(history, frame, "cxform.b0");
845 willChange = willChange || history_change(history, frame, "cxform.a0");
846 willChange = willChange || history_change(history, frame, "cxform.r1");
847 willChange = willChange || history_change(history, frame, "cxform.g1");
848 willChange = willChange || history_change(history, frame, "cxform.b1");
849 willChange = willChange || history_change(history, frame, "cxform.a1");
850 willChange = willChange || history_change(history, frame, "rotate");
851 willChange = willChange || history_change(history, frame, "shear");
852 willChange = willChange || history_change(history, frame, "pivot.x");
853 willChange = willChange || history_change(history, frame, "pivot.y");
854 willChange = willChange || history_change(history, frame, "pin.x");
855 willChange = willChange || history_change(history, frame, "pin.y");
856 willChange = willChange || history_change(history, frame, "blendmode");
857 willChange = willChange || history_changeFilter(history, frame);
862 static void free_filterlist(FILTERLIST* f_list)
865 for (i = 0; i < f_list->num; i++)
867 if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
868 gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
869 free(f_list->filter[i]);
874 static void readParameters(history_t* history, parameters_t* p, int frame)
876 p->x = history_value(history, frame, "x");
877 p->y = history_value(history, frame, "y");
878 p->scalex = history_value(history, frame, "scalex");
879 p->scaley = history_value(history, frame, "scaley");
880 p->cxform.r0 = history_value(history, frame, "cxform.r0");
881 p->cxform.g0 = history_value(history, frame, "cxform.g0");
882 p->cxform.b0 = history_value(history, frame, "cxform.b0");
883 p->cxform.a0 = history_value(history, frame, "cxform.a0");
884 p->cxform.r1 = history_value(history, frame, "cxform.r1");
885 p->cxform.g1 = history_value(history, frame, "cxform.g1");
886 p->cxform.b1 = history_value(history, frame, "cxform.b1");
887 p->cxform.a1 = history_value(history, frame, "cxform.a1");
888 p->rotate = history_rotateValue(history, frame);
889 p->shear = history_value(history, frame, "shear");
890 p->pivot.x = history_value(history, frame, "pivot.x");
891 p->pivot.y = history_value(history, frame, "pivot.y");
892 p->pin.x = history_value(history, frame, "pin.x");
893 p->pin.y = history_value(history, frame, "pin.y");
894 p->blendmode = history_value(history, frame, "blendmode");
895 p->filters = history_filterValue(history, frame);
898 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, const char*name, parameters_t*p, char move)
902 swf_GetPlaceObject(NULL, &po);
906 po.cxform = p->cxform;
907 po.name = (char*)name;
912 po.blendmode = p->blendmode;
915 po.filters = p->filters;
916 swf_SetPlaceObject(tag, &po);
919 static void writeInstance(void* _i)
921 instance_t*i = (instance_t*)_i;
924 int frame = i->history->firstFrame;
925 TAG* tag = i->history->firstTag;
926 history_processFlags(i->history);
927 while (tag && frame < currentframe)
930 while (tag && tag->id != ST_SHOWFRAME)
932 if (parametersChange(i->history, frame))
934 readParameters(i->history, &p, frame);
935 m = s_instancepos(i->character->size, &p);
937 if(p.blendmode || p.filters)
938 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
940 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
941 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
943 free_filterlist(p.filters);
950 void dumpSWF(SWF*swf)
952 TAG* tag = swf->firstTag;
953 printf("vvvvvvvvvvvvvvvvvvvvv\n");
955 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
958 printf("^^^^^^^^^^^^^^^^^^^^^\n");
961 static void s_endSprite()
963 SRECT r = currentrect;
968 dict_foreach_value(&instances, writeInstance);
970 if(stack[stackpos].cut)
971 tag = removeFromTo(stack[stackpos].cut, tag);
973 // the writeInstance loop above may have inserted tags after what used to be the current tag,
974 // so let's make sure 'tag' point to the current tag again.
978 tag = swf_InsertTag(tag, ST_SHOWFRAME);
979 tag = swf_InsertTag(tag, ST_END);
981 tag = stack[stackpos].tag;
984 if(stack[stackpos].scalegrid.xmin | stack[stackpos].scalegrid.ymin |
985 stack[stackpos].scalegrid.xmax | stack[stackpos].scalegrid.ymax)
987 tag = swf_InsertTag(tag, ST_DEFINESCALINGGRID);
988 swf_SetU16(tag, stack[stackpos].id);
989 swf_SetRect(tag, &stack[stackpos].scalegrid);
993 syntaxerror("internal error(7)");
994 /* TODO: before clearing, prepend "<spritename>." to names and
995 copy into old instances dict */
996 dict_free_all(&instances, 1, free_instance);
998 currentframe = stack[stackpos].oldframe;
999 currentrect = stack[stackpos].oldrect;
1000 currentdepth = stack[stackpos].olddepth;
1001 instances = stack[stackpos].oldinstances;
1003 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
1004 free(stack[stackpos].name);
1007 static void s_endSWF()
1013 dict_foreach_value(&instances, writeInstance);
1015 if(stack[stackpos].cut)
1016 tag = removeFromTo(stack[stackpos].cut, tag);
1020 swf = stack[stackpos].swf;
1021 filename = stack[stackpos].filename;
1023 // the writeInstance loop above may have inserted tags after what used yo be the current tag,
1024 // so let's make sure 'tag' point to the current tag again.
1028 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1029 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
1030 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1032 tag = swf_InsertTag(tag, ST_END);
1034 swf_OptimizeTagOrder(swf);
1040 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1041 swf->movieSize = currentrect; /* "autocrop" */
1044 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1045 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1046 swf->movieSize.ymax += 20;
1047 warning("Empty bounding box for movie");
1050 if(do_cgi || !strcmp(filename, "-"))
1051 fi = fileno(stdout);
1053 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1055 syntaxerror("couldn't create output file %s", filename);
1058 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1060 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1074 if(stack[stackpos-1].type == 0)
1075 syntaxerror("End of file encountered in .flash block");
1076 if(stack[stackpos-1].type == 1)
1077 syntaxerror("End of file encountered in .sprite block");
1078 if(stack[stackpos-1].type == 2)
1079 syntaxerror("End of file encountered in .clip block");
1085 return currentframe+1;
1088 void s_frame(int nr, int cut, const char*name, char anchor)
1094 syntaxerror("Illegal frame number");
1095 nr--; // internally, frame 1 is frame 0
1097 for(t=currentframe;t<nr;t++) {
1098 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1099 if(t==nr-1 && name && *name) {
1100 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1101 swf_SetString(tag, name);
1103 swf_SetU8(tag, 1); //make this an anchor
1106 if(nr == 0 && currentframe == 0 && name && *name) {
1107 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1108 swf_SetString(tag, name);
1110 swf_SetU8(tag, 1); //make this an anchor
1115 syntaxerror("Can't cut, frame empty");
1117 stack[stackpos].cut = tag;
1123 int parseColor2(const char*str, RGBA*color);
1125 int addFillStyle(SHAPE*s, SRECT*r, const char*name)
1129 gradient_t*gradient;
1131 if(name[0] == '#') {
1132 parseColor2(name, &color);
1133 return swf_ShapeAddSolidFillStyle(s, &color);
1134 } else if ((texture = dict_lookup(&textures, name))) {
1135 return swf_ShapeAddFillStyle2(s, &texture->fs);
1136 } else if((image = dict_lookup(&images, name))) {
1138 swf_GetMatrix(0, &m);
1139 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1140 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1143 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1144 } else if ((gradient = dict_lookup(&gradients, name))) {
1148 swf_GetMatrix(0, &rot);
1149 ccos = cos(-gradient->rotate*2*M_PI/360);
1150 csin = sin(-gradient->rotate*2*M_PI/360);
1151 rot.sx = ccos*65536;
1152 rot.r1 = -csin*65536;
1153 rot.r0 = csin*65536;
1154 rot.sy = ccos*65536;
1155 r2 = swf_TurnRect(*r, &rot);
1156 swf_GetMatrix(0, &m);
1157 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1158 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1159 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1160 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1161 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1162 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1163 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1164 } else if (parseColor2(name, &color)) {
1165 return swf_ShapeAddSolidFillStyle(s, &color);
1167 syntaxerror("not a color/fillstyle: %s", name);
1172 RGBA black={r:0,g:0,b:0,a:0};
1173 void s_box(const char*name, int width, int height, RGBA color, int linewidth, const char*texture)
1182 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1185 linewidth = linewidth>=20?linewidth-20:0;
1186 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1189 fs1 = addFillStyle(s, &r2, texture);
1192 r.xmin = r2.xmin-linewidth/2;
1193 r.ymin = r2.ymin-linewidth/2;
1194 r.xmax = r2.xmax+linewidth/2;
1195 r.ymax = r2.ymax+linewidth/2;
1196 swf_SetRect(tag,&r);
1197 swf_SetShapeHeader(tag,s);
1198 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1199 swf_ShapeSetLine(tag,s,width,0);
1200 swf_ShapeSetLine(tag,s,0,height);
1201 swf_ShapeSetLine(tag,s,-width,0);
1202 swf_ShapeSetLine(tag,s,0,-height);
1203 swf_ShapeSetEnd(tag);
1206 s_addcharacter(name, id, tag, r);
1210 void s_filled(const char*name, const char*outlinename, RGBA color, int linewidth, const char*texture)
1216 outline = dict_lookup(&outlines, outlinename);
1218 syntaxerror("outline %s not defined", outlinename);
1222 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1225 linewidth = linewidth>=20?linewidth-20:0;
1226 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1229 fs1 = addFillStyle(s, &r2, texture);
1232 rect.xmin = r2.xmin-linewidth/2;
1233 rect.ymin = r2.ymin-linewidth/2;
1234 rect.xmax = r2.xmax+linewidth/2;
1235 rect.ymax = r2.ymax+linewidth/2;
1237 swf_SetRect(tag,&rect);
1238 swf_SetShapeStyles(tag, s);
1239 swf_ShapeCountBits(s,0,0);
1240 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1241 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1242 swf_SetShapeBits(tag, s);
1243 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1246 s_addcharacter(name, id, tag, rect);
1250 void s_circle(const char*name, int r, RGBA color, int linewidth, const char*texture)
1255 r2.xmin = r2.ymin = 0;
1259 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1262 linewidth = linewidth>=20?linewidth-20:0;
1263 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1266 fs1 = addFillStyle(s, &r2, texture);
1268 rect.xmin = r2.xmin-linewidth/2;
1269 rect.ymin = r2.ymin-linewidth/2;
1270 rect.xmax = r2.xmax+linewidth/2;
1271 rect.ymax = r2.ymax+linewidth/2;
1273 swf_SetRect(tag,&rect);
1274 swf_SetShapeHeader(tag,s);
1275 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1276 swf_ShapeSetCircle(tag, s, r,r,r,r);
1277 swf_ShapeSetEnd(tag);
1280 s_addcharacter(name, id, tag, rect);
1284 void s_textshape(const char*name, const char*fontname, float size, const char*_text)
1287 U8*text = (U8*)_text;
1291 font = dict_lookup(&fonts, fontname);
1293 syntaxerror("font \"%s\" not known!", fontname);
1295 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1296 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1297 s_box(name, 0, 0, black, 20, 0);
1300 g = font->ascii2glyph[text[0]];
1302 outline = malloc(sizeof(outline_t));
1303 memset(outline, 0, sizeof(outline_t));
1304 outline->shape = font->glyph[g].shape;
1305 outline->bbox = font->layout->bounds[g];
1309 swf_Shape11DrawerInit(&draw, 0);
1310 swf_DrawText(&draw, font, (int)(size*100), (char*)_text);
1312 outline->shape = swf_ShapeDrawerToShape(&draw);
1313 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1314 draw.dealloc(&draw);
1317 if(dict_lookup(&outlines, name))
1318 syntaxerror("outline %s defined twice", name);
1319 dict_put(&outlines, name, outline);
1322 void s_text(const char*name, const char*fontname, const char*text, int size, RGBA color)
1327 font = dict_lookup(&fonts, fontname);
1329 syntaxerror("font \"%s\" not known!", fontname);
1331 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1332 swf_SetU16(tag, id);
1333 if(!font->numchars) {
1334 s_box(name, 0, 0, black, 20, 0);
1337 r = swf_SetDefineText(tag, font, &color, (char*)text, size);
1339 if(stack[0].swf->fileVersion >= 8) {
1340 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1341 swf_SetU16(tag, id);
1342 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1343 swf_SetU32(tag, 0);//thickness
1344 swf_SetU32(tag, 0);//sharpness
1345 swf_SetU8(tag, 0);//reserved
1348 s_addcharacter(name, id, tag, r);
1352 void s_quicktime(const char*name, const char*url)
1357 memset(&r, 0, sizeof(r));
1359 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1360 swf_SetU16(tag, id);
1361 swf_SetString(tag, url);
1363 s_addcharacter(name, id, tag, r);
1367 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)
1370 EditTextLayout layout;
1373 if(fontname && *fontname) {
1374 flags |= ET_USEOUTLINES;
1375 font = dict_lookup(&fonts, fontname);
1377 syntaxerror("font \"%s\" not known!", fontname);
1379 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1380 swf_SetU16(tag, id);
1381 layout.align = align;
1382 layout.leftmargin = 0;
1383 layout.rightmargin = 0;
1391 swf_SetEditText(tag, flags, r, (char*)text, color, maxlength, font?font->id:0, size, &layout, (char*)variable);
1393 s_addcharacter(name, id, tag, r);
1397 /* type: either "jpeg" or "png"
1399 void s_image(const char*name, const char*type, const char*filename, int quality)
1401 /* an image is actually two folded: 1st bitmap, 2nd character.
1402 Both of them can be used separately */
1404 /* step 1: the bitmap */
1408 if(!strcmp(type,"jpeg")) {
1409 #ifndef HAVE_JPEGLIB
1410 warning("no jpeg support compiled in");
1411 s_box(name, 0, 0, black, 20, 0);
1414 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1415 swf_SetU16(tag, imageID);
1417 if(swf_SetJPEGBits(tag, (char*)filename, quality) < 0) {
1418 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1421 swf_GetJPEGSize(filename, &width, &height);
1428 s_addimage(name, id, tag, r);
1431 } else if(!strcmp(type,"png")) {
1433 swf_SetU16(tag, imageID);
1435 getPNG(filename, &width, &height, (unsigned char**)&data);
1438 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1441 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1442 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1443 swf_SetU16(tag, imageID);
1444 swf_SetLosslessImage(tag, data, width, height);
1451 s_addimage(name, id, tag, r);
1454 warning("image type \"%s\" not supported yet!", type);
1455 s_box(name, 0, 0, black, 20, 0);
1459 /* step 2: the character */
1460 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1461 swf_SetU16(tag, id);
1462 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1464 s_addcharacter(name, id, tag, r);
1468 void s_getBitmapSize(const char*name, int*width, int*height)
1470 character_t* image = dict_lookup(&images, name);
1471 gradient_t* gradient = dict_lookup(&gradients,name);
1473 *width = image->size.xmax;
1474 *height = image->size.ymax;
1478 /* internal SWF gradient size */
1479 if(gradient->radial) {
1488 syntaxerror("No such bitmap/gradient: %s", name);
1491 void s_texture(const char*name, const char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1493 if(dict_lookup(&textures, name))
1494 syntaxerror("texture %s defined twice", name);
1495 gradient_t* gradient = dict_lookup(&gradients, object);
1496 character_t* bitmap = dict_lookup(&images, object);
1497 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1499 FILLSTYLE*fs = &texture->fs;
1501 memset(&p, 0, sizeof(parameters_t));
1504 fs->type = FILL_TILED;
1505 fs->id_bitmap = bitmap->id;
1506 } else if(gradient) {
1507 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1508 fs->gradient = gradient->gradient;
1510 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1511 makeMatrix(&fs->m, &p);
1512 if(gradient && !gradient->radial) {
1519 p2 = swf_TurnPoint(p1, &m);
1528 dict_put(&textures, name, texture);
1531 void s_font(const char*name, const char*filename)
1534 font = dict_lookup(&fonts, name);
1537 /* fix the layout. Only needed for old fonts */
1539 for(t=0;t<font->numchars;t++) {
1540 font->glyph[t].advance = 0;
1543 swf_FontCreateLayout(font);
1546 swf_FontReduce_swfc(font);
1547 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1548 swf_FontSetDefine2(tag, font);
1550 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1552 swf_SetU16(tag, id);
1553 swf_SetString(tag, name);
1561 typedef struct _sound_t
1567 void s_sound(const char*name, const char*filename)
1569 struct WAV wav, wav2;
1573 unsigned numsamples = 1;
1574 unsigned blocksize = 1152;
1577 if(dict_lookup(&sounds, name))
1578 syntaxerror("sound %s defined twice", name);
1580 if(wav_read(&wav, filename))
1583 wav_convert2mono(&wav, &wav2, 44100);
1584 samples = (U16*)wav2.data;
1585 numsamples = wav2.size/2;
1587 #ifdef WORDS_BIGENDIAN
1589 for(t=0;t<numsamples;t++)
1590 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1594 if(mp3_read(&mp3, filename))
1596 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1602 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1607 if(numsamples%blocksize != 0)
1609 // apply padding, so that block is a multiple of blocksize
1610 int numblocks = (numsamples+blocksize-1)/blocksize;
1613 numsamples2 = numblocks * blocksize;
1614 samples2 = malloc(sizeof(U16)*numsamples2);
1615 memcpy(samples2, samples, numsamples*sizeof(U16));
1616 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1617 numsamples = numsamples2;
1622 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1623 swf_SetU16(tag, id); //id
1626 swf_SetSoundDefineMP3(
1627 tag, mp3.data, mp3.size,
1634 swf_SetSoundDefine(tag, samples, numsamples);
1637 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1638 swf_SetU16(tag, id);
1639 swf_SetString(tag, name);
1640 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1642 swf_SetU16(tag, id);
1643 swf_SetString(tag, name);
1646 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1650 dict_put(&sounds, name, sound);
1658 static char* gradient_getToken(const char**p)
1662 while(**p && strchr(" \t\n\r", **p)) {
1666 while(**p && !strchr(" \t\n\r", **p)) {
1669 result = malloc((*p)-start+1);
1670 memcpy(result,start,(*p)-start+1);
1671 result[(*p)-start] = 0;
1675 float parsePercent(const char*str);
1676 RGBA parseColor(const char*str);
1678 GRADIENT parseGradient(const char*str)
1682 const char* p = str;
1683 memset(&gradient, 0, sizeof(GRADIENT));
1684 gradient.ratios = rfx_calloc(16*sizeof(U8));
1685 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1689 char*posstr,*colorstr;
1692 posstr = gradient_getToken(&p);
1698 pos = (int)(parsePercent(posstr)*255.0);
1703 rfx_free(gradient.ratios);
1704 rfx_free(gradient.rgba);
1706 syntaxerror("Error in shape data: Color expected after %s", posstr);
1708 colorstr = gradient_getToken(&p);
1709 color = parseColor(colorstr);
1710 if(gradient.num == 16)
1712 warning("gradient record too big- max size is 16, rest ignored");
1715 gradient.ratios[gradient.num] = pos;
1716 gradient.rgba[gradient.num] = color;
1725 FILTERLIST* parseFilters(char* list)
1727 if (!strcmp(list, "no_filters"))
1730 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1732 char* f_start = list;
1736 f_end = strchr(f_start, ',');
1739 f = dict_lookup(&filters, f_start);
1743 syntaxerror("unknown filter %s", f_start);
1745 if (f_list->num == 8)
1747 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1750 f_list->filter[f_list->num] = f;
1755 f_start = f_end + 1;
1763 void s_gradient(const char*name, const char*text, int radial, int rotate)
1765 gradient_t* gradient;
1766 gradient = malloc(sizeof(gradient_t));
1767 memset(gradient, 0, sizeof(gradient_t));
1768 gradient->gradient = parseGradient(text);
1769 gradient->radial = radial;
1770 gradient->rotate = rotate;
1772 dict_put(&gradients, name, gradient);
1775 void s_gradientglow(const char*name, const char*gradient, float blurx, float blury,
1776 float angle, float distance, float strength, char innershadow,
1777 char knockout, char composite, char ontop, int passes)
1779 if(dict_lookup(&filters, name))
1780 syntaxerror("filter %s defined twice", name);
1782 gradient_t* g = dict_lookup(&gradients, gradient);
1784 syntaxerror("unknown gradient %s", gradient);
1788 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1789 filter->type = FILTERTYPE_GRADIENTGLOW;
1790 filter->gradient = &g->gradient;
1791 filter->blurx = blurx;
1792 filter->blury = blury;
1793 filter->strength = strength;
1794 filter->angle = angle;
1795 filter->distance = distance;
1796 filter->innershadow = innershadow;
1797 filter->knockout = knockout;
1798 filter->composite = composite;
1799 filter->ontop = ontop;
1800 filter->passes = passes;
1802 dict_put(&filters, name, filter);
1805 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)
1807 if(dict_lookup(&filters, name))
1808 syntaxerror("filter %s defined twice", name);
1811 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1812 filter->type = FILTERTYPE_DROPSHADOW;
1813 filter->color= color;
1814 filter->blurx = blurx;
1815 filter->blury = blury;
1816 filter->strength = strength;
1817 filter->angle = angle;
1818 filter->distance = distance;
1819 filter->innershadow = innershadow;
1820 filter->knockout = knockout;
1821 filter->composite = composite;
1822 filter->passes = passes;
1824 dict_put(&filters, name, filter);
1827 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)
1829 if(dict_lookup(&filters, name))
1830 syntaxerror("filter %s defined twice", name);
1833 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1834 filter->type = FILTERTYPE_BEVEL;
1835 filter->shadow = shadow;
1836 filter->highlight = highlight;
1837 filter->blurx = blurx;
1838 filter->blury = blury;
1839 filter->strength = strength;
1840 filter->angle = angle;
1841 filter->distance = distance;
1842 filter->innershadow = innershadow;
1843 filter->knockout = knockout;
1844 filter->composite = composite;
1845 filter->ontop = ontop;
1846 filter->passes = passes;
1848 dict_put(&filters, name, filter);
1851 void s_blur(const char*name, double blurx, double blury, int passes)
1853 if(dict_lookup(&filters, name))
1854 syntaxerror("filter %s defined twice", name);
1856 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1857 filter->type = FILTERTYPE_BLUR;
1858 filter->blurx = blurx;
1859 filter->blury = blury;
1860 filter->passes = passes;
1862 dict_put(&filters, name, filter);
1865 void s_action(const char*text)
1868 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1872 syntaxerror("Couldn't compile ActionScript");
1875 tag = swf_InsertTag(tag, ST_DOACTION);
1877 swf_ActionSet(tag, a);
1882 void s_initaction(const char*character, const char*text)
1886 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1890 syntaxerror("Couldn't compile ActionScript");
1893 c = (character_t*)dict_lookup(&characters, character);
1895 tag = swf_InsertTag(tag, ST_DOINITACTION);
1896 swf_SetU16(tag, c->id);
1897 swf_ActionSet(tag, a);
1902 int s_swf3action(const char*name, const char*action)
1905 instance_t* object = 0;
1907 object = (instance_t*)dict_lookup(&instances, name);
1908 if(!object && name && *name) {
1909 /* we have a name, but couldn't find it. Abort. */
1912 a = action_SetTarget(0, name);
1913 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1914 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1915 else if(!strcmp(action, "stop")) a = action_Stop(a);
1916 else if(!strcmp(action, "play")) a = action_Play(a);
1917 a = action_SetTarget(a, "");
1920 tag = swf_InsertTag(tag, ST_DOACTION);
1921 swf_ActionSet(tag, a);
1926 void s_outline(const char*name, const char*format, const char*source)
1928 if(dict_lookup(&outlines, name))
1929 syntaxerror("outline %s defined twice", name);
1938 //swf_Shape10DrawerInit(&draw, 0);
1939 swf_Shape11DrawerInit(&draw, 0);
1941 draw_string(&draw, source);
1943 shape = swf_ShapeDrawerToShape(&draw);
1944 bounds = swf_ShapeDrawerGetBBox(&draw);
1945 draw.dealloc(&draw);
1947 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1948 outline->shape = shape;
1949 outline->bbox = bounds;
1951 dict_put(&outlines, name, outline);
1954 int s_playsound(const char*name, int loops, int nomultiple, int stop)
1960 sound = dict_lookup(&sounds, name);
1964 tag = swf_InsertTag(tag, ST_STARTSOUND);
1965 swf_SetU16(tag, sound->id); //id
1966 memset(&info, 0, sizeof(info));
1969 info.nomultiple = nomultiple;
1970 swf_SetSoundInfo(tag, &info);
1974 void s_includeswf(const char*name, const char*filename)
1982 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1983 f = open(filename,O_RDONLY|O_BINARY);
1985 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1986 s_box(name, 0, 0, black, 20, 0);
1989 if (swf_ReadSWF(f,&swf)<0) {
1990 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1991 s_box(name, 0, 0, black, 20, 0);
1996 /* FIXME: The following sets the bounding Box for the character.
1997 It is wrong for two reasons:
1998 a) It may be too small (in case objects in the movie clip at the borders)
1999 b) it may be too big (because the poor movie never got autocropped)
2003 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2004 swf_SetU16(tag, id);
2005 swf_SetU16(tag, swf.frameCount);
2007 swf_Relocate(&swf, idmap);
2009 ftag = swf.firstTag;
2013 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2014 if(cutout[t] == ftag->id) {
2018 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2020 if(ftag->id == ST_END)
2025 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2026 /* We simply dump all tags right after the sprite
2027 header, relying on the fact that swf_OptimizeTagOrder() will
2028 sort things out for us later.
2029 We also rely on the fact that the imported SWF is well-formed.
2031 tag = swf_InsertTag(tag, ftag->id);
2032 swf_SetBlock(tag, ftag->data, ftag->len);
2038 syntaxerror("Included file %s contains errors", filename);
2039 tag = swf_InsertTag(tag, ST_END);
2043 s_addcharacter(name, id, tag, r);
2046 SRECT s_getCharBBox(const char*name)
2048 character_t* c = dict_lookup(&characters, name);
2049 if(!c) syntaxerror("character '%s' unknown(2)", name);
2052 SRECT s_getInstanceBBox(const char*name)
2054 instance_t * i = dict_lookup(&instances, name);
2056 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2058 if(!c) syntaxerror("internal error(5)");
2061 void s_getParameters(const char*name, parameters_t* p)
2063 instance_t * i = dict_lookup(&instances, name);
2065 syntaxerror("instance '%s' unknown(10)", name);
2066 if (change_sets_all)
2067 readParameters(i->history, p, currentframe);
2072 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2074 history_begin(i->history, "x", currentframe, tag, p->x);
2075 history_begin(i->history, "y", currentframe, tag, p->y);
2076 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2077 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2078 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2079 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2080 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2081 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2082 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2083 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2084 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2085 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2086 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2087 history_begin(i->history, "shear", currentframe, tag, p->shear);
2088 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2089 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2090 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2091 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2092 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2093 history_beginFilter(i->history, currentframe, tag, p->filters);
2094 history_begin(i->history, "flags", currentframe, tag, 0);
2097 void s_startclip(const char*instance, const char*character, parameters_t p)
2099 character_t* c = dict_lookup(&characters, character);
2103 syntaxerror("character %s not known", character);
2105 i = s_addinstance(instance, c, currentdepth);
2107 m = s_instancepos(i->character->size, &p);
2109 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2110 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2111 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2113 stack[stackpos].tag = tag;
2114 stack[stackpos].type = 2;
2117 setStartparameters(i, &p, tag);
2124 swf_SetTagPos(stack[stackpos].tag, 0);
2125 swf_GetPlaceObject(stack[stackpos].tag, &p);
2126 p.clipdepth = currentdepth;
2128 swf_ClearTag(stack[stackpos].tag);
2129 swf_SetPlaceObject(stack[stackpos].tag, &p);
2133 void s_put(const char*instance, const char*character, parameters_t p)
2135 character_t* c = dict_lookup(&characters, character);
2139 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2141 i = s_addinstance(instance, c, currentdepth);
2143 m = s_instancepos(i->character->size, &p);
2145 if(p.blendmode || p.filters)
2147 if(stack[0].swf->fileVersion < 8)
2150 warning("blendmodes only supported for flash version>=8");
2152 warning("filters only supported for flash version>=8");
2154 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2157 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2158 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2159 setStartparameters(i, &p, tag);
2163 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2166 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2168 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2169 if (p.set & SF_SCALEX)
2170 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2171 if (p.set & SF_SCALEY)
2172 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2173 if (p.set & SF_CX_R)
2175 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2176 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2178 if (p.set & SF_CX_G)
2180 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2181 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2183 if (p.set & SF_CX_B)
2185 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2186 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2188 if (p.set & SF_CX_A)
2190 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2191 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2193 if (p.set & SF_ROTATE)
2194 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2195 if (p.set & SF_SHEAR)
2196 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2197 if (p.set & SF_PIVOT)
2199 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2200 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2204 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2205 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2207 if (p.set & SF_BLEND)
2208 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2209 if (p.set & SF_FILTER)
2210 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2213 void s_jump(const char* instance, parameters_t p)
2215 instance_t* i = dict_lookup(&instances, instance);
2217 syntaxerror("instance %s not known", instance);
2218 recordChanges(i->history, p, CF_JUMP, 0);
2221 void s_change(const char*instance, parameters_t p, interpolation_t* inter)
2223 instance_t* i = dict_lookup(&instances, instance);
2225 syntaxerror("instance %s not known", instance);
2226 recordChanges(i->history, p, CF_CHANGE, inter);
2229 void s_sweep(const char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2231 instance_t* i = dict_lookup(&instances, instance);
2233 syntaxerror("instance %s not known", instance);
2234 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2237 void s_toggle(const char* instance, U16 flagsOn, U16 flagsOff)
2239 instance_t* i = dict_lookup(&instances, instance);
2241 syntaxerror("instance %s not known", instance);
2242 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2245 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2248 void s_delinstance(const char*instance)
2250 instance_t* i = dict_lookup(&instances, instance);
2252 syntaxerror("instance %s not known", instance);
2254 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2255 swf_SetU16(tag, i->depth);
2256 dict_del(&instances, instance);
2260 void s_schange(const char*instance, parameters_t p, interpolation_t* inter)
2262 instance_t* i = dict_lookup(&instances, instance);
2264 syntaxerror("instance %s not known", instance);
2265 recordChanges(i->history, p, CF_SCHANGE, inter);
2271 syntaxerror(".end unexpected");
2272 switch (stack[stackpos-1].type)
2287 syntaxerror("internal error 1");
2291 // ------------------------------------------------------------------------
2293 typedef int command_func_t(map_t*args);
2295 SRECT parseBox(const char*str)
2297 SRECT r = {0,0,0,0};
2298 float xmin, xmax, ymin, ymax;
2299 char*x = strchr(str, 'x');
2301 if(!strcmp(str, "autocrop")) {
2302 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2306 d1 = strchr(x+1, ':');
2308 d2 = strchr(d1+1, ':');
2310 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2314 else if(d1 && !d2) {
2315 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2321 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2326 r.xmin = (SCOORD)(xmin*20);
2327 r.ymin = (SCOORD)(ymin*20);
2328 r.xmax = (SCOORD)(xmax*20);
2329 r.ymax = (SCOORD)(ymax*20);
2332 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2335 float parseFloat(const char*str)
2339 int parseInt(const char*str)
2344 if(str[0]=='+' || str[0]=='-')
2348 if(str[t]<'0' || str[t]>'9')
2349 syntaxerror("Not an Integer: \"%s\"", str);
2352 static double parseRawTwip(const char*str)
2356 if(str[0]=='+' || str[0]=='-') {
2361 dot = strchr(str, '.');
2365 return sign*parseInt(str);
2367 char* old = strdup(str);
2368 int l=strlen(dot+1);
2371 for(s=str;s<dot-1;s++) {
2372 if(*s<'0' || *s>'9')
2375 syntaxerror("Not a coordinate: \"%s\"", str);
2379 if(*s<'0' || *s>'9')
2382 syntaxerror("Not a coordinate: \"%s\"", str);
2385 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2386 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2389 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2393 return sign*(atoi(str));
2395 return sign*(atoi(str)+0.1*atoi(dot));
2397 return sign*(atoi(str)+0.01*atoi(dot));
2402 static dict_t defines;
2403 static int defines_initialized = 0;
2404 static mem_t define_values;
2406 static double parseNameOrTwip(const char*s)
2410 if(defines_initialized) {
2411 l = (int)dict_lookup(&defines, s);
2414 return *(int*)&define_values.buffer[l-1];
2416 return parseRawTwip(s);
2420 /* automatically generated by yiyiyacc, http://www.quiss.org/yiyiyacc/ */
2421 static double parseExpression(char*s)
2424 memset(chr2index, -1, sizeof(chr2index));
2431 chr2index['\0'] = 7;
2439 int left[10]={11,8,8,8,8,9,9,9,10,10}; //production left side
2440 int plen[10]={1,3,2,3,1,3,3,1,1,3}; //production size
2441 int table[18][12] = {
2442 {0, 4, 0, 0, 5, 6, 0, 0, 1, 2, 3, 0},
2443 {7, 8, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0},
2444 {-4, -4, 9, 10, 0, 0, -4, -4, 0, 0, 0, 0},
2445 {-7, -7, -7, -7, 0, 0, -7, -7, 0, 0, 0, 0},
2446 {0, 0, 0, 0, 5, 6, 0, 0, 0, 11, 3, 0},
2447 {-8, -8, -8, -8, 0, 0, -8, -8, 0, 0, 0, 0},
2448 {0, 4, 0, 0, 5, 6, 0, 0, 12, 2, 3, 0},
2449 {0, 0, 0, 0, 5, 6, 0, 0, 0, 13, 3, 0},
2450 {0, 0, 0, 0, 5, 6, 0, 0, 0, 14, 3, 0},
2451 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 15, 0},
2452 {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 16, 0},
2453 {-2, -2, 9, 10, 0, 0, -2, -2, 0, 0, 0, 0},
2454 {7, 8, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0},
2455 {-1, -1, 9, 10, 0, 0, -1, -1, 0, 0, 0, 0},
2456 {-3, -3, 9, 10, 0, 0, -3, -3, 0, 0, 0, 0},
2457 {-5, -5, -5, -5, 0, 0, -5, -5, 0, 0, 0, 0},
2458 {-6, -6, -6, -6, 0, 0, -6, -6, 0, 0, 0, 0},
2459 {-9, -9, -9, -9, 0, 0, -9, -9, 0, 0, 0, 0}};
2467 fprintf(stderr, "Error in expression\n");
2471 if(chr2index[*p]<0) {
2472 action = table[stack[stackpos-1]][4];
2474 while(chr2index[*pnext]<0)
2478 value = parseNameOrTwip(p);
2482 action = table[stack[stackpos-1]][chr2index[*p]];
2485 if(action == accept) {
2486 return values[stack[stackpos-1]];
2487 } else if(action>0) { // shift
2489 fprintf(stderr, "Stack overflow while parsing expression\n");
2492 values[stackpos]=value;
2493 stack[stackpos++]=action;
2495 } else if(action<0) { // reduce
2496 stackpos-=plen[-action];
2497 stack[stackpos] = table[stack[stackpos-1]][left[-action]];
2500 values[stackpos] = values[stackpos+0] + values[stackpos+2];
2503 values[stackpos] = 0 - values[stackpos+1];
2506 values[stackpos] = values[stackpos+0] - values[stackpos+2];
2509 values[stackpos] = values[stackpos+0] * values[stackpos+2];
2512 values[stackpos] = values[stackpos+0] / values[stackpos+2];
2515 values[stackpos] = values[stackpos+1];
2520 fprintf(stderr, "Syntax error in expression\n");
2526 int parseTwip(const char*str)
2528 char*str2 = (char*)str;
2529 int v = (int)(parseExpression(str2)*20);
2533 int parseArc(const char* str)
2535 if (!strcmp(str, "short"))
2537 if (!strcmp(str, "long"))
2539 syntaxerror("invalid value for the arc parameter: %s", str);
2543 int parseDir(const char* str)
2545 if (!strcmp(str, "clockwise"))
2547 if (!strcmp(str, "counterclockwise"))
2549 syntaxerror("invalid value for the dir parameter: %s", str);
2553 int isPoint(const char*str)
2555 if(strchr(str, '('))
2561 SPOINT parsePoint(const char*str)
2565 int l = strlen(str);
2566 char*comma = strchr(str, ',');
2567 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2568 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2569 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2570 p.x = parseTwip(tmp);
2571 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2572 p.y = parseTwip(tmp);
2576 int parseColor2(const char*str, RGBA*color)
2578 int l = strlen(str);
2582 struct {unsigned char r,g,b;char*name;} colors[] =
2583 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2584 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2585 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2586 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2587 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2588 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2589 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2590 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2591 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2592 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2593 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2594 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2598 if(str[0]=='#' && (l==7 || l==9)) {
2599 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2601 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2603 color->r = r; color->g = g; color->b = b; color->a = a;
2606 int len=strlen(str);
2608 if(strchr(str, '/')) {
2609 len = strchr(str, '/')-str;
2610 sscanf(str+len+1,"%02x", &alpha);
2612 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2613 if(!strncmp(str, colors[t].name, len)) {
2618 color->r = r; color->g = g; color->b = b; color->a = a;
2624 RGBA parseColor(const char*str)
2627 if(!parseColor2(str, &c))
2628 syntaxerror("Expression '%s' is not a color", str);
2632 typedef struct _muladd {
2637 MULADD parseMulAdd(const char*str)
2640 char* str2 = (char*)malloc(strlen(str)+5);
2647 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2648 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2649 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2650 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2651 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2652 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2653 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2654 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2655 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2656 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2658 syntaxerror("'%s' is not a valid color transform expression", str);
2660 m.add = (int)(add*256);
2661 m.mul = (int)(mul*256);
2666 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2668 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2669 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2671 if(a<-32768) a=-32768;
2672 if(a>32767) a=32767;
2673 if(m<-32768) m=-32768;
2674 if(m>32767) m=32767;
2680 float parsePxOrPercent(const char*fontname, const char*str)
2682 int l = strlen(str);
2683 if(strchr(str, '%'))
2684 return parsePercent(str);
2685 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2686 float p = atof(str);
2687 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2689 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2693 float parsePercent(const char*str)
2695 int l = strlen(str);
2699 return atoi(str)/100.0;
2701 syntaxerror("Expression '%s' is not a percentage", str);
2704 int isPercent(const char*str)
2706 return str[strlen(str)-1]=='%';
2708 int parseNewSize(const char*str, int size)
2711 return parsePercent(str)*size;
2713 return (int)(atof(str)*20);
2716 int isColor(char*str)
2719 return parseColor2(str, &c);
2722 static const char* lu(map_t* args, char*name)
2724 const char* value = map_lookup(args, name);
2726 map_dump(args, stdout, "");
2727 syntaxerror("internal error 2: value %s should be set", name);
2732 static int c_flash(map_t*args)
2734 const char* filename = map_lookup(args, "filename");
2735 const char* compressstr = lu(args, "compress");
2736 const char* change_modestr = lu(args, "change-sets-all");
2737 const char* exportstr = lu(args, "export");
2738 SRECT bbox = parseBox(lu(args, "bbox"));
2739 int version = parseInt(lu(args, "version"));
2740 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2741 RGBA color = parseColor(lu(args, "background"));
2744 if(!filename || !*filename) {
2745 /* for compatibility */
2746 filename = map_lookup(args, "name");
2747 if(!filename || !*filename) {
2750 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2751 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2755 if(!filename || override_outputname)
2756 filename = outputname;
2758 if(!strcmp(compressstr, "default"))
2759 compress = version>=6;
2760 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2762 else if(!strcmp(compressstr, "no"))
2764 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2766 if(!strcmp(change_modestr, "yes"))
2767 change_sets_all = 1;
2769 if(strcmp(change_modestr, "no"))
2770 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2772 do_exports=atoi(exportstr);
2774 s_swf(filename, bbox, version, fps, compress, color);
2777 int isRelative(const char*str)
2779 return !strncmp(str, "<plus>", 6) ||
2780 !strncmp(str, "<minus>", 7);
2782 const char* getOffset(const char*str)
2784 if(!strncmp(str, "<plus>", 6))
2786 if(!strncmp(str, "<minus>", 7))
2788 syntaxerror("internal error (347)");
2791 int getSign(const char*str)
2793 if(!strncmp(str, "<plus>", 6))
2795 if(!strncmp(str, "<minus>", 7))
2797 syntaxerror("internal error (348)");
2801 static dict_t points;
2802 static mem_t mpoints;
2803 static int points_initialized = 0;
2805 static int c_interpolation(map_t *args)
2808 const char* name = lu(args, "name");
2809 if (dict_lookup(&interpolations, name))
2810 syntaxerror("interpolation %s defined twice", name);
2812 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2813 const char* functionstr = lu(args, "function");
2814 inter->function = 0;
2815 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2816 if (!strcmp(functionstr,interpolationFunctions[i]))
2818 inter->function = i + 1;
2821 if (!inter->function)
2822 syntaxerror("unkown interpolation function %s", functionstr);
2823 inter->speed = parseFloat(lu(args, "speed"));
2824 inter->amplitude = parseTwip(lu(args, "amplitude"));
2825 inter->growth = parseFloat(lu(args, "growth"));
2826 inter->bounces = parseInt(lu(args, "bounces"));
2827 inter->damping = parseFloat(lu(args, "damping"));
2828 inter->slope = parseFloat(lu(args, "slope"));
2830 dict_put(&interpolations, name, inter);
2834 SPOINT getPoint(SRECT r, const char*name)
2837 if(!strcmp(name, "center")) {
2839 p.x = (r.xmin + r.xmax)/2;
2840 p.y = (r.ymin + r.ymax)/2;
2843 if (!strcmp(name, "bottom-center")) {
2845 p.x = (r.xmin + r.xmax)/2;
2849 if (!strcmp(name, "top-center")) {
2851 p.x = (r.xmin + r.xmax)/2;
2855 if (!strcmp(name, "top-left")) {
2861 if (!strcmp(name, "top-right")) {
2867 if (!strcmp(name, "bottom-right")) {
2873 if (!strcmp(name, "bottom-left")) {
2879 if (!strcmp(name, "left-center")) {
2882 p.y = (r.ymin + r.ymax)/2;
2885 if (!strcmp(name, "right-center")) {
2888 p.y = (r.ymin + r.ymax)/2;
2893 if(points_initialized)
2894 l = (int)dict_lookup(&points, name);
2896 syntaxerror("Invalid point: \"%s\".", name);
2898 return *(SPOINT*)&mpoints.buffer[l-1];
2902 static int texture2(const char*name, const char*object, map_t*args, int errors)
2905 const char*xstr = map_lookup(args, "x");
2906 const char*ystr = map_lookup(args, "y");
2907 const char*widthstr = map_lookup(args, "width");
2908 const char*heightstr = map_lookup(args, "height");
2909 const char*scalestr = map_lookup(args, "scale");
2910 const char*scalexstr = map_lookup(args, "scalex");
2911 const char*scaleystr = map_lookup(args, "scaley");
2912 const char*rotatestr = map_lookup(args, "rotate");
2913 const char* shearstr = map_lookup(args, "shear");
2914 const char* radiusstr = map_lookup(args, "r");
2916 float scalex = 1.0, scaley = 1.0;
2917 float rotate=0, shear=0;
2919 if(!*xstr && !*ystr) {
2921 syntaxerror("x and y must be set");
2924 if(*scalestr && (*scalexstr || *scaleystr)) {
2925 syntaxerror("scale and scalex/scaley can't both be set");
2928 if((*widthstr || *heightstr) && *radiusstr) {
2929 syntaxerror("width/height and radius can't both be set");
2932 widthstr = radiusstr;
2933 heightstr = radiusstr;
2935 if(!*xstr) xstr="0";
2936 if(!*ystr) ystr="0";
2937 if(!*rotatestr) rotatestr="0";
2938 if(!*shearstr) shearstr="0";
2941 scalex = scaley = parsePercent(scalestr);
2942 } else if(*scalexstr || *scaleystr) {
2943 if(scalexstr) scalex = parsePercent(scalexstr);
2944 if(scaleystr) scaley = parsePercent(scaleystr);
2945 } else if(*widthstr || *heightstr) {
2948 s_getBitmapSize(object, &width, &height);
2950 scalex = (float)parseTwip(widthstr)/(float)width;
2952 scaley = (float)parseTwip(heightstr)/(float)height;
2954 x = parseTwip(xstr);
2955 y = parseTwip(ystr);
2956 rotate = parseFloat(rotatestr);
2957 shear = parseFloat(shearstr);
2959 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2964 static int c_texture(map_t*args)
2966 const char*name = lu(args, "instance");
2967 const char*object = lu(args, "character");
2968 return texture2(name, object, args, 1);
2971 static int c_gradient(map_t*args)
2973 const char*name = lu(args, "name");
2974 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2975 int rotate = parseInt(lu(args, "rotate"));
2979 syntaxerror("colon (:) expected");
2981 if(dict_lookup(&gradients, name))
2982 syntaxerror("gradient %s defined twice", name);
2984 s_gradient(name, text, radial, rotate);
2986 /* check whether we also have placement information,
2987 which would make this a positioned gradient.
2988 If there is placement information, texture2() will
2989 add a texture, which has priority over the gradient.
2991 texture2(name, name, args, 0);
2995 static const char* checkFiltername(map_t* args)
2997 const char* name = lu(args, "name");
2998 if (strchr(name, ','))
2999 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
3003 static int c_blur(map_t*args)
3005 const char*name = checkFiltername(args);
3006 const char*blurstr = lu(args, "blur");
3007 const char*blurxstr = lu(args, "blurx");
3008 const char*blurystr = lu(args, "blury");
3009 float blurx=1.0, blury=1.0;
3011 blurx = parseFloat(blurstr);
3012 blury = parseFloat(blurstr);
3015 blurx = parseFloat(blurxstr);
3017 blury = parseFloat(blurystr);
3018 int passes = parseInt(lu(args, "passes"));
3019 s_blur(name, blurx, blury, passes);
3023 static int c_gradientglow(map_t*args)
3025 const char*name = checkFiltername(args);
3026 const char*gradient = lu(args, "gradient");
3027 const char*blurstr = lu(args, "blur");
3028 const char*blurxstr = lu(args, "blurx");
3029 const char*blurystr = lu(args, "blury");
3030 float blurx=1.0, blury=1.0;
3032 blurx = parseFloat(blurstr);
3033 blury = parseFloat(blurstr);
3036 blurx = parseFloat(blurxstr);
3038 blury = parseFloat(blurystr);
3040 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3041 float distance = parseFloat(lu(args, "distance"));
3042 float strength = parseFloat(lu(args, "strength"));
3043 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3044 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3045 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3046 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3047 int passes = parseInt(lu(args, "passes"));
3049 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3053 static int c_dropshadow(map_t*args)
3055 const char*name = checkFiltername(args);
3056 RGBA color = parseColor(lu(args, "color"));
3057 const char*blurstr = lu(args, "blur");
3058 const char*blurxstr = lu(args, "blurx");
3059 const char*blurystr = lu(args, "blury");
3060 float blurx=1.0, blury=1.0;
3062 blurx = parseFloat(blurstr);
3063 blury = parseFloat(blurstr);
3066 blurx = parseFloat(blurxstr);
3068 blury = parseFloat(blurystr);
3070 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3071 float distance = parseFloat(lu(args, "distance"));
3072 float strength = parseFloat(lu(args, "strength"));
3073 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3074 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3075 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3076 int passes = parseInt(lu(args, "passes"));
3078 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3082 static int c_bevel(map_t*args)
3084 const char*name = checkFiltername(args);
3085 RGBA shadow = parseColor(lu(args, "shadow"));
3086 RGBA highlight = parseColor(lu(args, "highlight"));
3087 const char*blurstr = lu(args, "blur");
3088 const char*blurxstr = lu(args, "blurx");
3089 const char*blurystr = lu(args, "blury");
3090 float blurx=1.0, blury=1.0;
3092 blurx = parseFloat(blurstr);
3093 blury = parseFloat(blurstr);
3096 blurx = parseFloat(blurxstr);
3098 blury = parseFloat(blurystr);
3100 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3101 float distance = parseFloat(lu(args, "distance"));
3102 float strength = parseFloat(lu(args, "strength"));
3103 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3104 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3105 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3106 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3107 int passes = parseInt(lu(args, "passes"));
3109 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3113 static int c_define(map_t*args)
3115 const char*name = lu(args, "name");
3116 const char*value = lu(args, "value");
3118 if(!defines_initialized) {
3119 dict_init(&defines, 16);
3120 mem_init(&define_values);
3121 defines_initialized = 1;
3123 int val = parseTwip(value);
3124 int pos = mem_put(&define_values, &val, sizeof(val));
3125 dict_put(&defines, name, (void*)(pos+1));
3128 static int c_point(map_t*args)
3130 const char*name = lu(args, "name");
3133 if(!points_initialized) {
3134 dict_init(&points, 16);
3136 points_initialized = 1;
3138 p.x = parseTwip(lu(args, "x"));
3139 p.y = parseTwip(lu(args, "y"));
3140 pos = mem_put(&mpoints, &p, sizeof(p));
3141 dict_put(&points, name, (void*)(pos+1));
3144 static int c_play(map_t*args)
3146 const char*name = lu(args, "name");
3147 const char*loop = lu(args, "loop");
3148 const char*nomultiple = lu(args, "nomultiple");
3150 if(!strcmp(nomultiple, "nomultiple"))
3153 nm = parseInt(nomultiple);
3155 if(s_playsound(name, parseInt(loop), nm, 0)) {
3157 } else if(s_swf3action(name, "play")) {
3163 static int c_stop(map_t*args)
3165 const char*name = map_lookup(args, "name");
3167 if(s_playsound(name, 0,0,1))
3169 else if(s_swf3action(name, "stop"))
3171 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3175 static int c_nextframe(map_t*args)
3177 const char*name = lu(args, "name");
3179 if(s_swf3action(name, "nextframe")) {
3182 syntaxerror("I don't know anything about movie \"%s\"", name);
3186 static int c_previousframe(map_t*args)
3188 const char*name = lu(args, "name");
3190 if(s_swf3action(name, "previousframe")) {
3193 syntaxerror("I don't know anything about movie \"%s\"", name);
3197 static int c_movement(map_t*args, int type)
3199 const char*instance = lu(args, "name");
3201 const char* xstr="";
3202 const char* ystr="";
3207 xstr = lu(args, "x");
3208 ystr = lu(args, "y");
3210 s_getParameters(instance, &p);
3215 if(isRelative(xstr))
3217 if(type == PT_PUT || type == PT_STARTCLIP)
3218 syntaxerror("relative x values not allowed for initial put or startclip");
3219 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3223 p.x = parseTwip(xstr);
3229 if(isRelative(ystr))
3231 if(type == PT_PUT || type == PT_STARTCLIP)
3232 syntaxerror("relative y values not allowed for initial put or startclip");
3233 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3237 p.y = parseTwip(ystr);
3242 if (change_sets_all)
3250 const char* interstr = lu(args, "interpolation");
3251 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3253 syntaxerror("unkown interpolation %s", interstr);
3254 s_change(instance, p, inter);
3259 const char* interstr = lu(args, "interpolation");
3260 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3262 syntaxerror("unkown interpolation %s", interstr);
3263 s_schange(instance, p, inter);
3268 const char* rstr = lu(args, "r");
3269 int radius = parseTwip(rstr);
3271 syntaxerror("sweep not possible: radius must be greater than 0.");
3272 const char* dirstr = lu(args, "dir");
3273 int clockwise = parseDir(dirstr);
3274 const char* arcstr = lu(args, "arc");
3275 int short_arc = parseArc(arcstr);
3276 const char* interstr = lu(args, "interpolation");
3277 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3279 syntaxerror("unkown interpolation %s", interstr);
3280 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3287 static int c_placement(map_t*args, int type)
3289 const char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3290 const char*character = 0;
3292 const char* luminancestr = lu(args, "luminance");
3293 const char* scalestr = lu(args, "scale");
3294 const char* scalexstr = lu(args, "scalex");
3295 const char* scaleystr = lu(args, "scaley");
3296 const char* rotatestr = lu(args, "rotate");
3297 const char* shearstr = lu(args, "shear");
3298 const char* xstr="", *pivotstr="";
3299 const char* ystr="", *anglestr="";
3300 const char*above = lu(args, "above"); /*FIXME*/
3301 const char*below = lu(args, "below");
3302 const char* rstr = lu(args, "red");
3303 const char* gstr = lu(args, "green");
3304 const char* bstr = lu(args, "blue");
3305 const char* astr = lu(args, "alpha");
3306 const char* pinstr = lu(args, "pin");
3307 const char* as = map_lookup(args, "as");
3308 const char* blendmode = lu(args, "blend");
3309 const char* filterstr = lu(args, "filter");
3320 { // (?) .rotate or .arcchange
3321 pivotstr = lu(args, "pivot");
3322 anglestr = lu(args, "angle");
3326 xstr = lu(args, "x");
3327 ystr = lu(args, "y");
3331 luminance = parseMulAdd(luminancestr);
3335 luminance.mul = 256;
3340 if(scalexstr[0]||scaleystr[0])
3341 syntaxerror("scalex/scaley and scale cannot both be set");
3342 scalexstr = scaleystr = scalestr;
3345 if(type == PT_PUT || type == PT_STARTCLIP) {
3347 character = lu(args, "character");
3348 parameters_clear(&p);
3349 } else if (type == PT_BUTTON) {
3350 character = lu(args, "name");
3351 parameters_clear(&p);
3354 s_getParameters(instance, &p);
3360 if(isRelative(xstr))
3362 if(type == PT_PUT || type == PT_STARTCLIP)
3363 syntaxerror("relative x values not allowed for initial put or startclip");
3364 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3368 p.x = parseTwip(xstr);
3374 if(isRelative(ystr))
3376 if(type == PT_PUT || type == PT_STARTCLIP)
3377 syntaxerror("relative y values not allowed for initial put or startclip");
3378 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3382 p.y = parseTwip(ystr);
3387 /* scale, scalex, scaley */
3389 oldbbox = s_getCharBBox(character);
3391 oldbbox = s_getInstanceBBox(instance);
3392 oldwidth = oldbbox.xmax - oldbbox.xmin;
3393 oldheight = oldbbox.ymax - oldbbox.ymin;
3400 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3401 set = set | SF_SCALEX;
3409 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3410 set = set | SF_SCALEY;
3416 if(isRelative(rotatestr))
3417 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3419 p.rotate = parseFloat(rotatestr);
3420 set = set | SF_ROTATE;
3426 if(isRelative(shearstr))
3427 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3429 p.shear = parseFloat(shearstr);
3430 set = set | SF_SHEAR;
3435 if(isPoint(pivotstr))
3436 p.pivot = parsePoint(pivotstr);
3438 p.pivot = getPoint(oldbbox, pivotstr);
3439 set = set | SF_PIVOT;
3445 p.pin = parsePoint(pinstr);
3447 p.pin = getPoint(oldbbox, pinstr);
3451 /* color transform */
3453 if(rstr[0] || luminancestr[0])
3457 r = parseMulAdd(rstr);
3460 r.add = p.cxform.r0;
3461 r.mul = p.cxform.r1;
3463 r = mergeMulAdd(r, luminance);
3464 p.cxform.r0 = r.mul;
3465 p.cxform.r1 = r.add;
3466 set = set | SF_CX_R;
3468 if(gstr[0] || luminancestr[0])
3472 g = parseMulAdd(gstr);
3475 g.add = p.cxform.g0;
3476 g.mul = p.cxform.g1;
3478 g = mergeMulAdd(g, luminance);
3479 p.cxform.g0 = g.mul;
3480 p.cxform.g1 = g.add;
3481 set = set | SF_CX_G;
3483 if(bstr[0] || luminancestr[0])
3487 b = parseMulAdd(bstr);
3490 b.add = p.cxform.b0;
3491 b.mul = p.cxform.b1;
3493 b = mergeMulAdd(b, luminance);
3494 p.cxform.b0 = b.mul;
3495 p.cxform.b1 = b.add;
3496 set = set | SF_CX_B;
3500 MULADD a = parseMulAdd(astr);
3501 p.cxform.a0 = a.mul;
3502 p.cxform.a1 = a.add;
3503 set = set | SF_CX_A;
3510 for(t = 0; blendModeNames[t]; t++)
3512 if(!strcmp(blendModeNames[t], blendmode))
3520 syntaxerror("unknown blend mode: '%s'", blendmode);
3522 p.blendmode = blend;
3523 set = set | SF_BLEND;
3528 p.filters = parseFilters((char*)filterstr);
3529 set = set | SF_FILTER;
3532 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3533 warning("As of version 0.8.2 using the .change command to modify an \
3534 object's position on the stage is considered deprecated. Future \
3535 versions may consider x and y parameters for the .change command \
3536 to be illegal; please use the .move command.");
3538 if (change_sets_all)
3545 s_put(instance, character, p);
3549 const char* interstr = lu(args, "interpolation");
3550 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3552 syntaxerror("unkown interpolation %s", interstr);
3553 s_change(instance, p, inter);
3558 const char* interstr = lu(args, "interpolation");
3559 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3561 syntaxerror("unkown interpolation %s", interstr);
3562 s_schange(instance, p, inter);
3566 s_jump(instance, p);
3569 s_startclip(instance, character, p);
3573 s_buttonput(character, as, p);
3575 s_buttonput(character, "shape", p);
3581 static int c_put(map_t*args)
3583 c_placement(args, PT_PUT);
3586 static int c_change(map_t*args)
3588 if (currentframe == 0)
3589 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3590 c_placement(args, PT_CHANGE);
3593 static int c_schange(map_t*args)
3595 c_placement(args, PT_SCHANGE);
3598 static int c_move(map_t* args)
3600 c_movement(args, PT_MOVE);
3603 static int c_smove(map_t* args)
3605 c_movement(args, PT_SMOVE);
3608 static int c_sweep(map_t* args)
3610 c_movement(args, PT_SWEEP);
3613 static int c_arcchange(map_t*args)
3615 c_placement(args, 0);
3618 static int c_jump(map_t*args)
3620 c_placement(args, PT_JUMP);
3623 static int c_startclip(map_t*args)
3625 c_placement(args, PT_STARTCLIP);
3628 static int c_show(map_t*args)
3630 c_placement(args, PT_BUTTON);
3633 static int c_toggle(map_t* args)
3635 const char*instance = lu(args, "name");
3636 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3637 const char* alignstr = lu(args, "fixed_alignment");
3638 if (!strcmp(alignstr, "on"))
3639 flagsOn += IF_FIXED_ALIGNMENT;
3641 if (!strcmp(alignstr, "off"))
3642 flagsOff -= IF_FIXED_ALIGNMENT;
3644 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3645 s_toggle(instance, flagsOn, flagsOff);
3648 static int c_del(map_t*args)
3650 const char*instance = lu(args, "name");
3651 s_delinstance(instance);
3654 static int c_end(map_t*args)
3659 static int c_sprite(map_t*args)
3661 const char* name = lu(args, "name");
3662 const char* scalinggrid = lu(args, "scalinggrid");
3664 if(scalinggrid && *scalinggrid) {
3665 SRECT r = parseBox(scalinggrid);
3672 static int c_frame(map_t*args)
3674 const char*framestr = lu(args, "n");
3675 const char*cutstr = lu(args, "cut");
3677 const char*name = lu(args, "name");
3678 const char*anchor = lu(args, "anchor");
3681 if(!strcmp(anchor, "anchor") && !*name)
3686 if(strcmp(cutstr, "no"))
3688 if(isRelative(framestr)) {
3689 frame = s_getframe();
3690 if(getSign(framestr)<0)
3691 syntaxerror("relative frame expressions must be positive");
3692 frame += parseInt(getOffset(framestr));
3695 frame = parseInt(framestr);
3696 if(s_getframe() >= frame
3697 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3698 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3700 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3703 static int c_primitive(map_t*args)
3705 const char*name = lu(args, "name");
3706 const char*command = lu(args, "commandname");
3707 int width=0, height=0, r=0;
3708 int linewidth = parseTwip(lu(args, "line"));
3709 const char*colorstr = lu(args, "color");
3710 RGBA color = parseColor(colorstr);
3711 const char*fillstr = lu(args, "fill");
3716 const char* outline=0;
3718 if(!strcmp(command, "circle"))
3720 else if(!strcmp(command, "filled"))
3724 width = parseTwip(lu(args, "width"));
3725 height = parseTwip(lu(args, "height"));
3726 } else if (type==1) {
3727 r = parseTwip(lu(args, "r"));
3728 } else if (type==2) {
3729 outline = lu(args, "outline");
3732 if(!strcmp(fillstr, "fill"))
3734 if(!strcmp(fillstr, "none"))
3736 if(width<0 || height<0 || linewidth<0 || r<0)
3737 syntaxerror("values width, height, line, r must be positive");
3739 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3740 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3741 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3745 static int c_textshape(map_t*args)
3747 const char*name = lu(args, "name");
3748 const char*text = lu(args, "text");
3749 const char*font = lu(args, "font");
3750 float size = parsePxOrPercent(font, lu(args, "size"));
3752 s_textshape(name, font, size, text);
3756 static int c_swf(map_t*args)
3758 const char*name = lu(args, "name");
3759 const char*filename = lu(args, "filename");
3760 const char*command = lu(args, "commandname");
3761 if(!strcmp(command, "shape"))
3762 warning("Please use .swf instead of .shape");
3763 s_includeswf(name, filename);
3767 static int c_font(map_t*args)
3769 const char*name = lu(args, "name");
3770 const char*filename = lu(args, "filename");
3771 s_font(name, filename);
3775 static int c_sound(map_t*args)
3777 const char*name = lu(args, "name");
3778 const char*filename = lu(args, "filename");
3779 s_sound(name, filename);
3783 static int c_text(map_t*args)
3785 const char*name = lu(args, "name");
3786 const char*text = lu(args, "text");
3787 const char*font = lu(args, "font");
3788 float size = parsePxOrPercent(font, lu(args, "size"));
3789 RGBA color = parseColor(lu(args, "color"));
3790 s_text(name, font, text, (int)(size*100), color);
3794 static int c_soundtrack(map_t*args)
3799 static int c_quicktime(map_t*args)
3801 const char*name = lu(args, "name");
3802 const char*url = lu(args, "url");
3803 s_quicktime(name, url);
3807 static int c_image(map_t*args)
3809 const char*command = lu(args, "commandname");
3810 const char*name = lu(args, "name");
3811 const char*filename = lu(args, "filename");
3812 if(!strcmp(command,"jpeg")) {
3813 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3814 s_image(name, "jpeg", filename, quality);
3816 s_image(name, "png", filename, 0);
3821 static int c_outline(map_t*args)
3823 const char*name = lu(args, "name");
3824 const char*format = lu(args, "format");
3828 syntaxerror("colon (:) expected");
3830 s_outline(name, format, text);
3834 int fakechar(map_t*args)
3836 const char*name = lu(args, "name");
3837 s_box(name, 0, 0, black, 20, 0);
3841 static int c_egon(map_t*args) {return fakechar(args);}
3842 static int c_button(map_t*args) {
3843 const char*name = lu(args, "name");
3847 static int current_button_flags = 0;
3848 static int c_on_press(map_t*args)
3850 const char*position = lu(args, "position");
3851 const char*action = "";
3852 if(!strcmp(position, "inside")) {
3853 current_button_flags |= BC_OVERUP_OVERDOWN;
3854 } else if(!strcmp(position, "outside")) {
3855 //current_button_flags |= BC_IDLE_OUTDOWN;
3856 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3857 } else if(!strcmp(position, "anywhere")) {
3858 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3861 if(type == RAWDATA) {
3863 s_buttonaction(current_button_flags, action);
3864 current_button_flags = 0;
3870 static int c_on_release(map_t*args)
3872 const char*position = lu(args, "position");
3873 const char*action = "";
3874 if(!strcmp(position, "inside")) {
3875 current_button_flags |= BC_OVERDOWN_OVERUP;
3876 } else if(!strcmp(position, "outside")) {
3877 current_button_flags |= BC_OUTDOWN_IDLE;
3878 } else if(!strcmp(position, "anywhere")) {
3879 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3882 if(type == RAWDATA) {
3884 s_buttonaction(current_button_flags, action);
3885 current_button_flags = 0;
3891 static int c_on_move_in(map_t*args)
3893 const char*position = lu(args, "state");
3894 const char*action = "";
3895 if(!strcmp(position, "pressed")) {
3896 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3897 } else if(!strcmp(position, "not_pressed")) {
3898 current_button_flags |= BC_IDLE_OVERUP;
3899 } else if(!strcmp(position, "any")) {
3900 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3903 if(type == RAWDATA) {
3905 s_buttonaction(current_button_flags, action);
3906 current_button_flags = 0;
3912 static int c_on_move_out(map_t*args)
3914 const char*position = lu(args, "state");
3915 const char*action = "";
3916 if(!strcmp(position, "pressed")) {
3917 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3918 } else if(!strcmp(position, "not_pressed")) {
3919 current_button_flags |= BC_OVERUP_IDLE;
3920 } else if(!strcmp(position, "any")) {
3921 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3924 if(type == RAWDATA) {
3926 s_buttonaction(current_button_flags, action);
3927 current_button_flags = 0;
3933 static int c_on_key(map_t*args)
3935 const char*key = lu(args, "key");
3936 const char*action = "";
3937 if(strlen(key)==1) {
3940 current_button_flags |= 0x4000 + (key[0]*0x200);
3942 syntaxerror("invalid character: %c"+key[0]);
3947 <ctrl-x> = 0x200*(x-'a')
3951 syntaxerror("invalid key: %s",key);
3954 if(type == RAWDATA) {
3956 s_buttonaction(current_button_flags, action);
3957 current_button_flags = 0;
3964 static int c_edittext(map_t*args)
3966 //"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"},
3967 const char*name = lu(args, "name");
3968 const char*font = lu(args, "font");
3969 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3970 int width = parseTwip(lu(args, "width"));
3971 int height = parseTwip(lu(args, "height"));
3972 const char*text = lu(args, "text");
3973 RGBA color = parseColor(lu(args, "color"));
3974 int maxlength = parseInt(lu(args, "maxlength"));
3975 const char*variable = lu(args, "variable");
3976 const char*passwordstr = lu(args, "password");
3977 const char*wordwrapstr = lu(args, "wordwrap");
3978 const char*multilinestr = lu(args, "multiline");
3979 const char*htmlstr = lu(args, "html");
3980 const char*noselectstr = lu(args, "noselect");
3981 const char*readonlystr = lu(args, "readonly");
3982 const char*borderstr = lu(args, "border");
3983 const char*autosizestr = lu(args, "autosize");
3984 const char*alignstr = lu(args, "align");
3988 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3989 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3990 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3991 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3992 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3993 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3994 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3995 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3996 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3997 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3998 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3999 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
4000 else syntaxerror("Unknown alignment: %s", alignstr);
4002 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
4006 static int c_morphshape(map_t*args) {return fakechar(args);}
4007 static int c_movie(map_t*args) {return fakechar(args);}
4009 static char* readfile(char*filename)
4011 FILE*fi = fopen(filename, "rb");
4015 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
4016 fseek(fi, 0, SEEK_END);
4018 fseek(fi, 0, SEEK_SET);
4019 text = rfx_alloc(l+1);
4020 fread(text, l, 1, fi);
4026 static int c_action(map_t*args)
4028 const char* filename = map_lookup(args, "filename");
4029 if(!filename ||!*filename) {
4031 if(type != RAWDATA) {
4032 syntaxerror("colon (:) expected");
4036 s_action(readfile((char*)filename));
4042 static int c_initaction(map_t*args)
4044 const char* character = lu(args, "name");
4045 const char* filename = map_lookup(args, "filename");
4046 if(!filename ||!*filename) {
4048 if(type != RAWDATA) {
4049 syntaxerror("colon (:) expected");
4051 s_initaction(character, text);
4053 s_initaction(character, readfile((char*)filename));
4061 command_func_t* func;
4064 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1"},
4065 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
4066 // "import" type stuff
4067 {"swf", c_swf, "name filename"},
4068 {"shape", c_swf, "name filename"},
4069 {"jpeg", c_image, "name filename quality=80%"},
4070 {"png", c_image, "name filename"},
4071 {"movie", c_movie, "name filename"},
4072 {"sound", c_sound, "name filename"},
4073 {"font", c_font, "name filename glyphs="},
4074 {"soundtrack", c_soundtrack, "filename"},
4075 {"quicktime", c_quicktime, "url"},
4077 // generators of primitives
4079 {"define", c_define, "name value=0"},
4080 {"point", c_point, "name x=0 y=0"},
4081 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4082 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4083 {"outline", c_outline, "name format=simple"},
4084 {"textshape", c_textshape, "name font size=100% text"},
4087 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4088 {"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"},
4089 {"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"},
4090 {"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"},
4092 // character generators
4093 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4094 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4095 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4097 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4098 {"text", c_text, "name text font size=100% color=white"},
4099 {"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="},
4100 {"morphshape", c_morphshape, "name start end"},
4101 {"button", c_button, "name"},
4102 {"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="},
4103 {"on_press", c_on_press, "position=inside"},
4104 {"on_release", c_on_release, "position=anywhere"},
4105 {"on_move_in", c_on_move_in, "state=not_pressed"},
4106 {"on_move_out", c_on_move_out, "state=not_pressed"},
4107 {"on_key", c_on_key, "key=any"},
4110 {"play", c_play, "name loop=0 @nomultiple=0"},
4111 {"stop", c_stop, "name= "},
4112 {"nextframe", c_nextframe, "name"},
4113 {"previousframe", c_previousframe, "name"},
4115 // object placement tags
4116 {"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="},
4117 {"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="},
4118 {"move", c_move, "name x= y= interpolation=linear"},
4119 {"smove", c_smove, "name x= y= interpolation=linear"},
4120 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4121 {"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"},
4122 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4123 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4124 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4125 {"del", c_del, "name"},
4126 // virtual object placement
4127 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4129 {"toggle", c_toggle, "name fixed_alignment="},
4131 // commands which start a block
4132 //startclip (see above)
4133 {"sprite", c_sprite, "name scalinggrid="},
4134 {"action", c_action, "filename="},
4135 {"initaction", c_initaction, "name filename="},
4141 static map_t parseArguments(char*command, char*pattern)
4157 string_set(&t1, "commandname");
4158 string_set(&t2, command);
4159 map_put(&result, t1, t2);
4161 if(!pattern || !*pattern)
4168 if(!strncmp("<i> ", x, 3)) {
4170 if(type == COMMAND || type == RAWDATA) {
4172 syntaxerror("character name expected");
4174 name[pos].str = "instance";
4176 value[pos].str = text;
4177 value[pos].len = strlen(text);
4181 if(type == ASSIGNMENT)
4184 name[pos].str = "character";
4186 value[pos].str = text;
4187 value[pos].len = strlen(text);
4195 isboolean[pos] = (x[0] =='@');
4208 name[pos].len = d-x;
4213 name[pos].len = e-x;
4214 value[pos].str = e+1;
4215 value[pos].len = d-e-1;
4223 /* for(t=0;t<len;t++) {
4224 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4225 isboolean[t]?"(boolean)":"");
4230 if(type == RAWDATA || type == COMMAND) {
4235 // first, search for boolean arguments
4236 for(pos=0;pos<len;pos++)
4238 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4240 if(type == ASSIGNMENT)
4242 value[pos].str = text;
4243 value[pos].len = strlen(text);
4244 /*printf("setting boolean parameter %s (to %s)\n",
4245 strdup_n(name[pos], namelen[pos]),
4246 strdup_n(value[pos], valuelen[pos]));*/
4251 // second, search for normal arguments
4253 for(pos=0;pos<len;pos++)
4255 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4256 (type != ASSIGNMENT && !set[pos])) {
4258 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4260 if(type == ASSIGNMENT)
4263 value[pos].str = text;
4264 value[pos].len = strlen(text);
4266 printf("setting parameter %s (to %s)\n",
4267 strdup_n(name[pos].str, name[pos].len),
4268 strdup_n(value[pos].str, value[pos].len));
4274 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4278 for(t=0;t<len;t++) {
4279 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4282 for(t=0;t<len;t++) {
4283 if(value[t].str && value[t].str[0] == '*') {
4284 //relative default- take value from some other parameter
4286 for(s=0;s<len;s++) {
4287 if(value[s].len == value[t].len-1 &&
4288 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4289 value[t].str = value[s].str;
4292 if(value[t].str == 0) {
4294 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4298 /* ok, now construct the dictionary from the parameters */
4302 map_put(&result, name[t], value[t]);
4306 static void parseArgumentsForCommand(char*command)
4311 msg("<verbose> parse Command: %s (line %d)", command, line);
4313 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4314 if(!strcmp(arguments[t].command, command)) {
4316 /* ugly hack- will be removed soon (once documentation and .sc generating
4317 utilities have been changed) */
4318 if(!strcmp(command, "swf") && !stackpos) {
4319 warning("Please use .flash instead of .swf- this will be mandatory soon");
4324 args = parseArguments(command, arguments[t].arguments);
4330 syntaxerror("command %s not known", command);
4333 // catch missing .flash directives at the beginning of a file
4334 if(strcmp(command, "flash") && !stackpos)
4336 syntaxerror("No movie defined- use .flash first");
4341 printf(".%s\n", command);fflush(stdout);
4342 map_dump(&args, stdout, "\t");fflush(stdout);
4346 (*arguments[nr].func)(&args);
4348 if(!strcmp(command, "action") || !strcmp(command, "initaction") ||
4349 !strcmp(command, "outline") || !strcmp(command, "gradient")) {
4351 if(type != RAWDATA) {
4352 syntaxerror("colon (:) expected");
4361 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4362 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4363 * No syntax checking is done */
4364 static void analyseArgumentsForCommand(char*command)
4368 const char* fontfile;
4370 U8* glyphs_to_include;
4371 msg("<verbose> analyse Command: %s (line %d)", command, line);
4373 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4375 if(!strcmp(arguments[t].command, command))
4377 args = parseArguments(command, arguments[t].arguments);
4383 printf(".%s\n", command);fflush(stdout);
4384 map_dump(&args, stdout, "\t");fflush(stdout);
4386 const char* name = lu(&args, "name");
4387 if (!strcmp(command, "font"))
4389 if(dict_lookup(&fonts, name))
4390 syntaxerror("font %s defined twice", name);
4393 fontfile = lu(&args, "filename");
4394 font = swf_LoadFont(fontfile);
4396 warning("Couldn't open font file \"%s\"", fontfile);
4397 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4398 memset(font, 0, sizeof(SWFFONT));
4402 swf_FontPrepareForEditText(font);
4403 glyphs_to_include = (U8*)lu(&args, "glyphs");
4404 if (!strcmp(glyphs_to_include, "all"))
4406 swf_FontUseAll(font);
4407 font->use->glyphs_specified = 1;
4411 if (strcmp (glyphs_to_include, ""))
4413 swf_FontUseUTF8(font, glyphs_to_include);
4414 font->use->glyphs_specified = 1;
4417 swf_FontInitUsage(font);
4420 dict_put(&fonts, name, font);
4424 SWFFONT* font = dict_lookup(&fonts, lu(&args, "font"));
4426 //that's ok... it might be an edittext with a system font
4427 //syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4429 if (font->use && !font->use->glyphs_specified)
4431 if (!strcmp(command, "edittext"))
4433 swf_FontUseAll(font);
4434 font->use->glyphs_specified = 1;
4437 swf_FontUseUTF8(font, (U8*)lu(&args, "text"));
4444 void skipParameters()
4448 while (type != COMMAND);
4452 void findFontUsage()
4454 char* fontRelated = "font;text;textshape;edittext;";
4455 while(!noMoreTokens())
4459 syntaxerror("command expected");
4460 if (strstr(fontRelated, text))
4461 analyseArgumentsForCommand(text);
4463 if(strcmp(text, "end"))
4472 dict_init(&fonts, 16);
4473 cleanUp = &freeFontDictionary;
4477 int main (int argc,char ** argv)
4480 processargs(argc, argv);
4481 initLog(0,-1,0,0,-1,verbose);
4484 args_callback_usage(argv[0]);
4488 file = generateTokens(filename);
4490 fprintf(stderr, "parser returned error.\n");
4497 while(!noMoreTokens()) {
4500 syntaxerror("command expected");
4501 parseArgumentsForCommand(text);