X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fswfc.c;h=ad923d3f9b3f908075151b381aaaa7d618fd9ead;hb=1b376de4a5d3ee2905cf962ecbde7766616d5347;hp=49897efa2515506ac6b242433d4e146dba9987cf;hpb=2a0b7ebc3a3e0ec8ee4190afa094b407d90ef065;p=swftools.git diff --git a/src/swfc.c b/src/swfc.c index 49897ef..ad923d3 100644 --- a/src/swfc.c +++ b/src/swfc.c @@ -42,12 +42,12 @@ static char * outputname = "output.swf"; static int verbose = 2; static int override_outputname = 0; -static struct options_t options[] = -{ - {"o","output"}, - {"v","verbose"}, - {"V","version"}, - {0,0} +static struct options_t options[] = { +{"h", "help"}, +{"V", "version"}, +{"v", "verbose"}, +{"o", "output"}, +{0,0} }; int args_callback_option(char*name,char*val) @@ -75,12 +75,16 @@ int args_callback_longoption(char*name,char*val) { return args_long2shortoption(options, name, val); } -void args_callback_usage(char*name) +void args_callback_usage(char *name) { - printf("Usage: %s [-o filename] file.sc\n", name); - printf("\t-v , --verbose\t\t\t Be more verbose\n"); - printf("\t-o , --output filename\t\t set output filename (default: output.swf)\n"); - printf("\t-V , --version\t\t\t Print program version and exit\n"); + printf("\n"); + printf("Usage: %s [-o file.swf] file.sc\n", name); + printf("\n"); + printf("-h , --help Print short help message and exit\n"); + printf("-V , --version Print version info and exit\n"); + printf("-v , --verbose Increase verbosity. \n"); + printf("-o , --output Set output file to .\n"); + printf("\n"); } int args_callback_command(char*name,char*val) { @@ -161,7 +165,7 @@ static int noMoreTokens() struct _character; static struct level { - int type; //0=swf, 1=sprite, 2=clip + int type; //0=swf, 1=sprite, 2=clip, 3=button /* for swf (0): */ SWF*swf; @@ -349,12 +353,12 @@ static void makeMatrix(MATRIX*m, parameters_t*p) m->ty = p->y - h.y; } -static MATRIX s_instancepos(instance_t*i, parameters_t*p) +static MATRIX s_instancepos(SRECT rect, parameters_t*p) { MATRIX m; SRECT r; makeMatrix(&m, p); - r = swf_TurnRect(i->character->size, &m); + r = swf_TurnRect(rect, &m); if(currentrect.xmin == 0 && currentrect.ymin == 0 && currentrect.xmax == 0 && currentrect.ymax == 0) currentrect = r; @@ -431,6 +435,123 @@ void s_sprite(char*name) incrementid(); } +typedef struct _buttonrecord +{ + U16 id; + MATRIX matrix; + CXFORM cxform; + char set; +} buttonrecord_t; + +typedef struct _button +{ + int endofshapes; + int nr_actions; + buttonrecord_t records[4]; +} button_t; + +static button_t mybutton; + +void s_button(char*name) +{ + tag = swf_InsertTag(tag, ST_DEFINEBUTTON2); + swf_SetU16(tag, id); //id + swf_ButtonSetFlags(tag, 0); //menu=no + + memset(&mybutton, 0, sizeof(mybutton)); + + memset(&stack[stackpos], 0, sizeof(stack[0])); + stack[stackpos].type = 3; + stack[stackpos].tag = tag; + stack[stackpos].id = id; + stack[stackpos].name = strdup(name); + stack[stackpos].oldrect = currentrect; + memset(¤trect, 0, sizeof(currentrect)); + + stackpos++; + incrementid(); +} +void s_buttonput(char*character, char*as, parameters_t p) +{ + character_t* c = dictionary_lookup(&characters, character); + MATRIX m; + int flags = 0; + buttonrecord_t r; + if(!c) { + syntaxerror("character %s not known (in .shape %s)", character, character); + } + if(mybutton.endofshapes) { + syntaxerror("a .do may not precede a .show", character, character); + } + + m = s_instancepos(c->size, &p); + + r.id = c->id; + r.matrix = m; + r.cxform = p.cxform; + r.set = 1; + + if(strstr(as, "idle")) mybutton.records[0]=r; + if(strstr(as, "hover")) mybutton.records[1]=r; + if(strstr(as, "pressed")) mybutton.records[2]=r; + if(strstr(as, "area")) mybutton.records[3]=r; +} +static void setbuttonrecords(TAG*tag) +{ + int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT}; + if(!mybutton.endofshapes) { + int t; + + if(!mybutton.records[3].set) { + memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t)); + } + + for(t=0;t<4;t++) { + if(mybutton.records[t].set) + swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform); + } + swf_SetU8(tag,0); // end of button records + mybutton.endofshapes = 1; + } +} + +void s_buttonaction(int flags, char*action) +{ + ActionTAG* a = 0; + if(flags==0) { + return; + } + setbuttonrecords(stack[stackpos-1].tag); + + a = swf_ActionCompile(text, stack[0].swf->fileVersion); + if(!a) { + syntaxerror("Couldn't compile ActionScript"); + } + + swf_ButtonSetCondition(stack[stackpos-1].tag, flags); + swf_ActionSet(stack[stackpos-1].tag, a); + mybutton.nr_actions++; + + swf_ActionFree(a); +} + +static void s_endButton() +{ + SRECT r; + setbuttonrecords(stack[stackpos-1].tag); + stackpos--; + + swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions); + + r = currentrect; + + tag = stack[stackpos].tag; + currentrect = stack[stackpos].oldrect; + + s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r); + free(stack[stackpos].name); +} + TAG* removeFromTo(TAG*from, TAG*to) { TAG*save = from->prev; @@ -492,8 +613,9 @@ static void s_endSWF() swf_OptimizeTagOrder(swf); - if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) + if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) { swf->movieSize = currentrect; /* "autocrop" */ + } if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) { swf->movieSize.xmax += 20; /* 1 by 1 pixels */ @@ -772,22 +894,30 @@ void s_image(char*name, char*type, char*filename, int quality) s_box(name, 0, 0, black, 20, 0); return; } - tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2); - swf_SetU16(tag, imageID); + if(type=="jpeg") { +#ifndef HAVE_LIBJPEG + warning("no jpeg support compiled in"); + s_box(name, 0, 0, black, 20, 0); + return; +#else + tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2); + swf_SetU16(tag, imageID); - if(swf_SetJPEGBits(tag, filename, quality) < 0) { - syntaxerror("Image \"%s\" not found, or contains errors", filename); - } + if(swf_SetJPEGBits(tag, filename, quality) < 0) { + syntaxerror("Image \"%s\" not found, or contains errors", filename); + } - swf_GetJPEGSize(filename, &width, &height); + swf_GetJPEGSize(filename, &width, &height); - r.xmin = 0; - r.ymin = 0; - r.xmax = width*20; - r.ymax = height*20; + r.xmin = 0; + r.ymin = 0; + r.xmax = width*20; + r.ymax = height*20; - s_addimage(name, id, tag, r); - incrementid(); + s_addimage(name, id, tag, r); + incrementid(); +#endif + } /* step 2: the character */ tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?) @@ -953,6 +1083,9 @@ void s_action(const char*text) { ActionTAG* a = 0; a = swf_ActionCompile(text, stack[0].swf->fileVersion); + if(!a) { + syntaxerror("Couldn't compile ActionScript"); + } tag = swf_InsertTag(tag, ST_DOACTION); @@ -961,6 +1094,27 @@ void s_action(const char*text) swf_ActionFree(a); } +int s_swf3action(char*name, char*action) +{ + ActionTAG* a = 0; + instance_t* object = dictionary_lookup(&instances, name); + if(!object) { + return 0; + } + a = action_SetTarget(0, name); + if(!strcmp(action, "nextframe")) a = action_NextFrame(a); + else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a); + else if(!strcmp(action, "stop")) a = action_Stop(a); + else if(!strcmp(action, "play")) a = action_Play(a); + a = action_SetTarget(a, ""); + a = action_End(a); + + tag = swf_InsertTag(tag, ST_DOACTION); + swf_ActionSet(tag, a); + swf_ActionFree(a); + return 1; +} + void s_outline(char*name, char*format, char*source) { outline_t* outline; @@ -990,12 +1144,12 @@ void s_outline(char*name, char*format, char*source) dictionary_put2(&outlines, name, outline); } -void s_playsound(char*name, int loops, int nomultiple, int stop) +int s_playsound(char*name, int loops, int nomultiple, int stop) { sound_t* sound = dictionary_lookup(&sounds, name); SOUNDINFO info; if(!sound) - syntaxerror("Don't know anything about sound \"%s\"", name); + return 0; tag = swf_InsertTag(tag, ST_STARTSOUND); swf_SetU16(tag, sound->id); //id @@ -1004,6 +1158,7 @@ void s_playsound(char*name, int loops, int nomultiple, int stop) info.loops = loops; info.nomultiple = nomultiple; swf_SetSoundInfo(tag, &info); + return 1; } void s_includeswf(char*name, char*filename) @@ -1105,7 +1260,7 @@ void s_startclip(char*instance, char*character, parameters_t p) } i = s_addinstance(instance, c, currentdepth); i->parameters = p; - m = s_instancepos(i, &p); + m = s_instancepos(i->character->size, &p); tag = swf_InsertTag(tag, ST_PLACEOBJECT2); /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */ @@ -1142,7 +1297,7 @@ void s_put(char*instance, char*character, parameters_t p) i = s_addinstance(instance, c, currentdepth); i->parameters = p; - m = s_instancepos(i, &p); + m = s_instancepos(i->character->size, &p); tag = swf_InsertTag(tag, ST_PLACEOBJECT2); swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance); @@ -1160,7 +1315,7 @@ void s_jump(char*instance, parameters_t p) } i->parameters = p; - m = s_instancepos(i, &p); + m = s_instancepos(i->character->size, &p); tag = swf_InsertTag(tag, ST_PLACEOBJECT2); swf_ObjectMove(tag, i->depth, &m, &p.cxform); @@ -1218,7 +1373,7 @@ void s_change(char*instance, parameters_t p2) return; } - m = s_instancepos(i, &p2); + m = s_instancepos(i->character->size, &p2); tag = swf_InsertTag(tag, ST_PLACEOBJECT2); swf_ObjectMove(tag, i->depth, &m, &p2.cxform); i->parameters = p2; @@ -1236,7 +1391,7 @@ void s_change(char*instance, parameters_t p2) TAG*lt; frame ++; p = s_interpolate(&p1, &p2, frame, allframes); - m = s_instancepos(i, &p); //needed? + m = s_instancepos(i->character->size, &p); //needed? lt = swf_InsertTag(t, ST_PLACEOBJECT2); i->lastFrame = currentframe; swf_ObjectMove(lt, i->depth, &m, &p.cxform); @@ -1275,6 +1430,8 @@ void s_end() s_endSprite(); else if(stack[stackpos-1].type == 2) s_endClip(); + else if(stack[stackpos-1].type == 3) + s_endButton(); else syntaxerror("internal error 1"); } @@ -1639,7 +1796,7 @@ static int c_point(map_t*args) } static int c_play(map_t*args) { - char*name = lu(args, "sound"); + char*name = lu(args, "name"); char*loop = lu(args, "loop"); char*nomultiple = lu(args, "nomultiple"); int nm = 0; @@ -1648,14 +1805,46 @@ static int c_play(map_t*args) else nm = parseInt(nomultiple); - s_playsound(name, parseInt(loop), nm, 0); + if(s_playsound(name, parseInt(loop), nm, 0)) { + return 0; + } else if(s_swf3action(name, "play")) { + return 0; + } return 0; } static int c_stop(map_t*args) { - char*name = lu(args, "sound"); - s_playsound(name, 0,0,1); + char*name = lu(args, "name"); + + if(s_playsound(name, 0,0,1)) { + return 0; + } else if(s_swf3action(name, "stop")) { + return 0; + } + syntaxerror("I don't know anything about sound/movie \"%s\"", name); + return 0; +} + +static int c_nextframe(map_t*args) +{ + char*name = lu(args, "name"); + + if(s_swf3action(name, "nextframe")) { + return 0; + } + syntaxerror("I don't know anything about movie \"%s\"", name); + return 0; +} + +static int c_previousframe(map_t*args) +{ + char*name = lu(args, "name"); + + if(s_swf3action(name, "previousframe")) { + return 0; + } + syntaxerror("I don't know anything about movie \"%s\"", name); return 0; } @@ -1679,6 +1868,7 @@ static int c_placement(map_t*args, int type) char* bstr = lu(args, "blue"); char* astr = lu(args, "alpha"); char* pinstr = lu(args, "pin"); + char* as = map_lookup(args, "as"); MULADD r,g,b,a; float oldwidth; float oldheight; @@ -1686,7 +1876,7 @@ static int c_placement(map_t*args, int type) MULADD luminance; parameters_t p; - if(type==5) { + if(type==9) { // (?) .rotate or .arcchange pivotstr = lu(args, "pivot"); anglestr = lu(args, "angle"); } else { @@ -1710,6 +1900,10 @@ static int c_placement(map_t*args, int type) // put or startclip character = lu(args, "character"); parameters_clear(&p); + } else if (type == 5) { + character = lu(args, "name"); + parameters_clear(&p); + // button's show } else { p = s_getParameters(instance); } @@ -1830,14 +2024,21 @@ static int c_placement(map_t*args, int type) if(type == 0) s_put(instance, character, p); - if(type == 1) + else if(type == 1) s_change(instance, p); - if(type == 2) + else if(type == 2) s_qchange(instance, p); - if(type == 3) + else if(type == 3) s_jump(instance, p); - if(type == 4) + else if(type == 4) s_startclip(instance, character, p); + else if(type == 5) { + if(as && as[0]) { + s_buttonput(character, as, p); + } else { + s_buttonput(character, "shape", p); + } + } return 0; } static int c_put(map_t*args) @@ -1870,6 +2071,11 @@ static int c_startclip(map_t*args) c_placement(args, 4); return 0; } +static int c_show(map_t*args) +{ + c_placement(args, 5); + return 0; +} static int c_del(map_t*args) { char*instance = lu(args, "name"); @@ -1962,8 +2168,6 @@ static int c_textshape(map_t*args) return 0; } - - static int c_swf(map_t*args) { char*name = lu(args, "name"); @@ -2043,29 +2247,140 @@ int fakechar(map_t*args) static int c_egon(map_t*args) {return fakechar(args);} static int c_button(map_t*args) { + char*name = lu(args, "name"); + s_button(name); + return 0; +} +static int current_button_flags = 0; +static int c_on_press(map_t*args) +{ + char*position = lu(args, "position"); char*action = ""; + if(!strcmp(position, "inside")) { + current_button_flags |= BC_OVERUP_OVERDOWN; + } else if(!strcmp(position, "outside")) { + //current_button_flags |= BC_IDLE_OUTDOWN; + syntaxerror("IDLE_OVERDOWN not supported by SWF"); + } else if(!strcmp(position, "anywhere")) { + current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN; + } readToken(); - if(type == RAWDATA) + if(type == RAWDATA) { action = text; + s_buttonaction(current_button_flags, action); + current_button_flags = 0; + } else pushBack(); - - return fakechar(args); + return 0; } +static int c_on_release(map_t*args) +{ + char*position = lu(args, "position"); + char*action = ""; + if(!strcmp(position, "inside")) { + current_button_flags |= BC_OVERDOWN_OVERUP; + } else if(!strcmp(position, "outside")) { + current_button_flags |= BC_OUTDOWN_IDLE; + } else if(!strcmp(position, "anywhere")) { + current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE; + } + readToken(); + if(type == RAWDATA) { + action = text; + s_buttonaction(current_button_flags, action); + current_button_flags = 0; + } + else + pushBack(); + return 0; +} +static int c_on_move_in(map_t*args) +{ + char*position = lu(args, "state"); + char*action = ""; + if(!strcmp(position, "pressed")) { + current_button_flags |= BC_OUTDOWN_OVERDOWN; + } else if(!strcmp(position, "not_pressed")) { + current_button_flags |= BC_IDLE_OVERUP; + } else if(!strcmp(position, "any")) { + current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN; + } + readToken(); + if(type == RAWDATA) { + action = text; + s_buttonaction(current_button_flags, action); + current_button_flags = 0; + } + else + pushBack(); + return 0; +} +static int c_on_move_out(map_t*args) +{ + char*position = lu(args, "state"); + char*action = ""; + if(!strcmp(position, "pressed")) { + current_button_flags |= BC_OVERDOWN_OUTDOWN; + } else if(!strcmp(position, "not_pressed")) { + current_button_flags |= BC_OVERUP_IDLE; + } else if(!strcmp(position, "any")) { + current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE; + } + readToken(); + if(type == RAWDATA) { + action = text; + s_buttonaction(current_button_flags, action); + current_button_flags = 0; + } + else + pushBack(); + return 0; +} +static int c_on_key(map_t*args) +{ + char*key = lu(args, "key"); + char*action = ""; + if(strlen(key)==1) { + /* ascii */ + if(key[0]>=32) { + current_button_flags |= 0x4000 + (key[0]*0x200); + } else { + syntaxerror("invalid character: %c"+key[0]); + return 1; + } + } else { + /* TODO: + = 0x200*(x-'a') + esc = = 0x3600 + space = = 0x4000; + */ + syntaxerror("invalid key: %s",key); + } + readToken(); + if(type == RAWDATA) { + action = text; + s_buttonaction(current_button_flags, action); + current_button_flags = 0; + } + else + pushBack(); + return 0; +} + static int c_edittext(map_t*args) {return fakechar(args);} static int c_morphshape(map_t*args) {return fakechar(args);} static int c_movie(map_t*args) {return fakechar(args);} -static int c_buttonsounds(map_t*args) {return 0;} -static int c_buttonput(map_t*args) {return 0;} static int c_texture(map_t*args) {return 0;} static int c_action(map_t*args) { readToken(); - if(type != RAWDATA) + if(type != RAWDATA) { syntaxerror("colon (:) expected"); + } s_action(text); @@ -2102,27 +2417,32 @@ static struct { {"filled", c_primitive, "name outline color=white line=1 @fill=none"}, {"egon", c_egon, "name vertices color=white line=1 @fill=none"}, - {"button", c_button, "name shape over=*shape press=*shape area=*shape"}, {"text", c_text, "name text font size=100% color=white"}, {"edittext", c_edittext, "name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"}, {"morphshape", c_morphshape, "name start end"}, + {"button", c_button, "name"}, + {"show", c_show, "name x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below= as="}, + {"on_press", c_on_press, "position=inside"}, + {"on_release", c_on_release, "position=anywhere"}, + {"on_move_in", c_on_move_out, "state=not_pressed"}, + {"on_move_out", c_on_move_out, "state=not_pressed"}, + {"on_key", c_on_key, "key=any"}, - {"buttonsounds", c_buttonsounds, "name press=0 release=0 enter=0 leave=0"}, - // control tags - {"play", c_play, "sound loop=0 @nomultiple=0"}, - {"stop", c_stop, "sound"}, + {"play", c_play, "name loop=0 @nomultiple=0"}, + {"stop", c_stop, "name"}, + {"nextframe", c_nextframe, "name"}, + {"previousframe", c_previousframe, "name"}, // object placement tags - {"put", c_put, " x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="}, - {"startclip", c_startclip, " x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="}, - {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="}, - {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="}, - {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="}, - {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="}, + {"put", c_put, " x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="}, + {"startclip", c_startclip, " x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="}, + {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="}, + {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="}, + {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="}, + {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="}, {"del", c_del, "name"}, // virtual object placement - {"buttonput", c_buttonput, " x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex=100% scaley=100% shear=0 rotate=0 above= below="}, {"texture", c_texture, " x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"}, // commands which start a block @@ -2305,6 +2625,7 @@ static void parseArgumentsForCommand(char*command) map_t args; int nr = -1; msg(" parse Command: %s (line %d)", command, line); + for(t=0;t