ADDED heromesh.h Index: heromesh.h ================================================================== --- heromesh.h +++ heromesh.h @@ -0,0 +1,20 @@ +/* + This file is part of Free Hero Mesh and is public domain. +*/ + +// main.c + +extern sqlite3*userdb; +extern xrm_db*resourcedb; +extern const char*basefilename; +extern xrm_quark optionquery[16]; + +// picture.c + +extern SDL_Surface*screen; +extern Uint16 picture_size; + +void draw_picture(int x,int y,Uint16 img); +void draw_text(int x,int y,const unsigned char*t,int bg,int fg); +void load_pictures(void); + Index: main.c ================================================================== --- main.c +++ main.c @@ -1,15 +1,16 @@ #if 0 -gcc -s -O2 -o ~/bin/heromesh main.c smallxrm.o sqlite3.o `sdl-config --cflags --libs` -ldl -lpthread +gcc -s -O2 -o ~/bin/heromesh main.c picture.o smallxrm.o sqlite3.o `sdl-config --cflags --libs` -ldl -lpthread exit #endif /* This program is part of Free Hero Mesh and is public domain. */ #define _BSD_SOURCE +#define HEROMESH_MAIN #include "SDL.h" #include #include #include #include @@ -16,11 +17,11 @@ #include "sqlite3.h" #include "smallxrm.h" #include "names.h" #include "quarks.h" #include "cursorshapes.h" -#include "pcfont.h" +#include "heromesh.h" typedef struct { char cmd; union { int n; @@ -43,25 +44,25 @@ "PRAGMA RECURSIVE_TRIGGERS(1);" "CREATE TABLE IF NOT EXISTS `USERCACHEINDEX`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT, `LVLTIME` INT, `SOLTIME` INT, `VERSION` INT);" "CREATE TEMPORARY TABLE `PICTURES`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT, `OFFSET` INT);" ; -static sqlite3*userdb; -static SDL_Cursor*cursor[77]; -static xrm_db*resourcedb; -static SDL_Surface*screen; -static const char*basefilename; +sqlite3*userdb; +xrm_db*resourcedb; +const char*basefilename; +xrm_quark optionquery[16]; + static const char*globalclassname; +static SDL_Cursor*cursor[77]; static FILE*levelfp; static FILE*solutionfp; -static xrm_quark optionquery[16]; static FILE*hamarc_fp; static long hamarc_pos; -static Uint16 picture_size; -static SDL_Surface*picture_surface; static KeyBinding*editor_bindings[SDLK_LAST]; static KeyBinding*game_bindings[SDLK_LAST]; +static KeyBinding*editor_mouse_bindings[4]; +static KeyBinding*game_mouse_bindings[4]; #define fatal(...) do{ fprintf(stderr,__VA_ARGS__); exit(1); }while(0) #define boolxrm(a,b) (*a=='1'||*a=='y'||*a=='t'||*a=='Y'||*a=='T'?1:*a=='0'||*a=='n'||*a=='f'||*a=='N'||*a=='F'?0:b) static void hamarc_begin(FILE*fp,const char*name) { @@ -130,125 +131,10 @@ optionquery[1]=Q_sqlInit; v=xrm_get_resource(resourcedb,optionquery,optionquery,2); if(v && sqlite3_exec(userdb,v,0,0,&s)) fatal("Failed to execute user-defined SQL statements (%s)\n",s?:"unknown error"); } -static void draw_picture(int x,int y,Uint16 img) { - // To be called only when screen is unlocked! - SDL_Rect src={(img&15)*picture_size,(img>>4)*picture_size,picture_size,picture_size}; - SDL_Rect dst={x,y,picture_size,picture_size}; - SDL_BlitSurface(picture_surface,&src,screen,&dst); -} - -static void draw_text(int x,int y,const unsigned char*t,int bg,int fg) { - // To be called only when screen is locked! - int len=strlen(t); - Uint8*pix=screen->pixels; - Uint8*p; - Uint16 pitch=screen->pitch; - int xx,yy; - const unsigned char*f; - if(x+8*len>screen->w) len=(screen->w-x)>>3; - if(len<=0 || y+8>screen->h) return; - pix+=y*pitch+x; - while(*t) { - f=fontdata+(*t<<3); - for(yy=0;yy<8;yy++) { - for(xx=0;xx<8;xx++) p[xx]=(*f<255) fatal("Invalid picture size %d\n",i); - wantsize[nwantsize++]=i; - v+=j; - } - sqlite3_exec(userdb,"BEGIN;",0,0,0); - if(sqlite3_prepare(userdb,"INSERT INTO `PICTURES`(`ID`,`NAME`,`OFFSET`) VALUES(?1,?2,?3);",-1,&st,0)) - fatal("Unable to prepare SQL statement while loading pictures: %s\n",sqlite3_errmsg(userdb)); - nam=malloc(256); - if(!nam) fatal("Allocation failed\n"); - n=0; - memset(havesize,0,256*sizeof(Uint16)); - while(!feof(fp)) { - i=0; - while(j=fgetc(fp)) { - if(j==EOF) goto nomore1; - if(i<255) nam[i++]=j; - } - nam[i]=0; - if(i>4 && !memcmp(".IMG",nam+i-4,4)) { - j=1; - if(n++==32768) fatal("Too many pictures\n"); - sqlite3_reset(st); - sqlite3_bind_int(st,1,n); - sqlite3_bind_text(st,2,nam,i,SQLITE_TRANSIENT); - sqlite3_bind_int64(st,3,ftell(fp)+4); - while((i=sqlite3_step(st))==SQLITE_ROW); - if(i!=SQLITE_DONE) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb)); - } else { - j=0; - } - i=fgetc(fp)<<16; - i|=fgetc(fp)<<24; - i|=fgetc(fp)<<0; - i|=fgetc(fp)<<8; - if(j) { - i-=j=fgetc(fp)&15; - while(j--) ++havesize[fgetc(fp)&255]; - fseek(fp,i-1,SEEK_CUR); - } else { - fseek(fp,i,SEEK_CUR); - } - } -nomore1: - if(!n) fatal("Cannot find any pictures in this puzzle set\n"); - free(nam); - sqlite3_finalize(st); - rewind(fp); - for(i=0;i<256;i++) havesize[i]=(havesize[i]==n)?1:0; - picture_size=decide_picture_size(nwantsize,wantsize,havesize); - - fclose(fp); - sqlite3_exec(userdb,"COMMIT;",0,0,0); -} - static void set_cursor(int id) { id>>=1; if(!cursor[id]) cursor[id]=SDL_CreateCursor((void*)cursorimg+(id<<6),(void*)cursorimg+(id<<6)+32,16,16,cursorhot[id]>>4,cursorhot[id]&15); SDL_SetCursor(cursor[id]); } @@ -326,10 +212,16 @@ optionquery[1]=Q_editKey; \ if(s=xrm_get_resource(resourcedb,optionquery,optionquery,n)) set_key_binding(editor_bindings+quark_to_key[q-FirstKeyQuark],m,s); \ optionquery[1]=Q_gameKey; \ if(s=xrm_get_resource(resourcedb,optionquery,optionquery,n)) set_key_binding(game_bindings+quark_to_key[q-FirstKeyQuark],m,s); \ } while(0) +#define SetMouseBinding(o,n,m) do { \ + optionquery[1]=Q_editClick; \ + if(s=xrm_get_resource(resourcedb,optionquery,optionquery,n)) set_key_binding(editor_mouse_bindings+o,m,s); \ + optionquery[1]=Q_gameClick; \ + if(s=xrm_get_resource(resourcedb,optionquery,optionquery,n)) set_key_binding(game_mouse_bindings+o,m,s); \ +} while(0) static void load_key_bindings(void) { xrm_quark q; const char*s; for(q=FirstKeyQuark;q<=LastKeyQuark;q++) { optionquery[2]=optionquery[3]=optionquery[4]=q; @@ -353,10 +245,40 @@ SetKeyBinding(5,MOD_CTRL|MOD_SHIFT); optionquery[2]=Q_meta; SetKeyBinding(5,MOD_META|MOD_SHIFT); #endif } + optionquery[2]=optionquery[3]=Q_left; + SetMouseBinding(SDL_BUTTON_LEFT,3,0); + optionquery[2]=Q_shift; + SetMouseBinding(SDL_BUTTON_LEFT,4,MOD_SHIFT); + optionquery[2]=Q_ctrl; + SetMouseBinding(SDL_BUTTON_LEFT,4,MOD_CTRL); + optionquery[2]=Q_alt; + SetMouseBinding(SDL_BUTTON_LEFT,4,MOD_ALT); + optionquery[2]=Q_meta; + SetMouseBinding(SDL_BUTTON_LEFT,4,MOD_META); + optionquery[2]=optionquery[3]=Q_middle; + SetMouseBinding(SDL_BUTTON_MIDDLE,3,0); + optionquery[2]=Q_shift; + SetMouseBinding(SDL_BUTTON_MIDDLE,4,MOD_SHIFT); + optionquery[2]=Q_ctrl; + SetMouseBinding(SDL_BUTTON_MIDDLE,4,MOD_CTRL); + optionquery[2]=Q_alt; + SetMouseBinding(SDL_BUTTON_MIDDLE,4,MOD_ALT); + optionquery[2]=Q_meta; + SetMouseBinding(SDL_BUTTON_MIDDLE,4,MOD_META); + optionquery[2]=optionquery[3]=Q_right; + SetMouseBinding(SDL_BUTTON_RIGHT,3,0); + optionquery[2]=Q_shift; + SetMouseBinding(SDL_BUTTON_RIGHT,4,MOD_SHIFT); + optionquery[2]=Q_ctrl; + SetMouseBinding(SDL_BUTTON_RIGHT,4,MOD_CTRL); + optionquery[2]=Q_alt; + SetMouseBinding(SDL_BUTTON_RIGHT,4,MOD_ALT); + optionquery[2]=Q_meta; + SetMouseBinding(SDL_BUTTON_RIGHT,4,MOD_META); } int main(int argc,char**argv) { if(argc<2) fatal("usage: %s basename [options...]\n",argc?argv[0]:"heromesh"); if(xrm_init(realloc)) fatal("Failed to initialize resource manager\n"); ADDED picture.c Index: picture.c ================================================================== --- picture.c +++ picture.c @@ -0,0 +1,289 @@ +#if 0 +gcc -s -O2 -c -Wno-unused-result picture.c `sdl-config --cflags` +exit +#endif + +/* + This program is part of Free Hero Mesh and is public domain. +*/ + +#define _BSD_SOURCE +#include "SDL.h" +#include +#include +#include +#include +#include "sqlite3.h" +#include "smallxrm.h" +#include "pcfont.h" +#include "quarks.h" +#include "heromesh.h" + +#define fatal(...) do{ fprintf(stderr,__VA_ARGS__); exit(1); }while(0) + +SDL_Surface*screen; +Uint16 picture_size; + +static SDL_Surface*picts; +static Uint8*curpic; + +static const char default_palette[]= + "C020FF " + "000000 222222 333333 444444 555555 666666 777777 888888 999999 AAAAAA BBBBBB CCCCCC DDDDDD EEEEEE FFFFFF " + "281400 412300 5F3200 842100 A05000 C35F14 E1731E FF8232 FF9141 FFA050 FFAF5F FFBE73 FFD282 FFE191 FFF0A0 " + "321E1E 412220 5F2830 823040 A03A4C BE4658 E15464 FF6670 FF7F7B FF8E7F FF9F7F FFAF7F FFBF7F FFCF7F FFDF7F " + "280D0D 401515 602020 802A2A A03535 C04040 E04A4A FF5555 FF6764 FF6F64 FF7584 FF849D FF94B7 FF9FD1 FFAEEA " + "901400 A02000 B03000 C04000 D05000 E06000 F07000 FF8000 FF9000 FFA000 FFB000 FFC000 FFD000 FFE000 FFF000 " + "280000 400000 600000 800000 A00000 C00000 E00000 FF0000 FF2828 FF4040 FF6060 FF8080 FFA0A0 FFC0C0 FFE0E0 " + "280028 400040 600060 800080 A000A0 C000C0 E000E0 FF00FF FF28FF FF40FF FF60FF FF80FF FFA0FF FFC0FF FFE0FF " + "281428 402040 603060 804080 A050A0 C060C0 E070E0 FF7CFF FF8CFF FF9CFF FFACFF FFBCFF FFCCFF FFDCFF FFECFF " + "280050 350566 420A7C 4F0F92 5C14A8 6919BE 761ED4 8323EA 9028FF A040FF B060FF C080FF D0A0FF E0C0FF F0E0FF " + "000028 000040 000060 000080 0000A0 0000C0 0000E0 0000FF 0A28FF 284AFF 466AFF 678AFF 87AAFF A7CAFF C7EBFF " + "0F1E1E 142323 193232 1E4141 285050 325F5F 377373 418282 469191 50A0A0 5AAFAF 5FC3C3 69D2D2 73E1E1 78F0F0 " + "002828 004040 006060 008080 00A0A0 00C0C0 00E0E0 00FFFF 28FFFF 40FFFF 60FFFF 80FFFF A0FFFF C0FFFF E0FFFF " + "002800 004000 006000 008000 00A000 00C000 00E000 00FF00 28FF28 40FF40 60FF60 80FF80 A0FFA0 C0FFC0 E0FFE0 " + "002110 234123 325F32 418241 50A050 5FC35F 73E173 85FF7A 91FF6E A0FF5F B4FF50 C3FF41 D2FF32 E1FF23 F0FF0F " + "282800 404000 606000 808000 A0A000 C0C000 E0E000 FFFF00 FFFF28 FFFF40 FFFF60 FFFF80 FFFFA0 FFFFC0 FFFFE0 " + // + "442100 00FF55 0055FF FF5500 55FF00 FF0055 5500FF CA8B25 F078F0 F0F078 FF7F00 DD6D01 7AFF00 111111 " + // + "000000 0000AA 00AA00 00AAAA AA0000 AA00AA AAAA00 AAAAAA " + "555555 5555FF 55FF55 55FFFF FF5555 FF55FF FFFF55 FFFFFF " +; + +static void init_palette(void) { + double gamma; + int usegamma=1; + int i,j; + SDL_Color pal[256]; + FILE*fp=0; + const char*v; + optionquery[2]=Q_gamma; + gamma=strtod(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"0",0); + if(gamma<=0.0 || gamma==1.0) usegamma=0; + optionquery[2]=Q_palette; + v=xrm_get_resource(resourcedb,optionquery,optionquery,2); + if(v && *v) { + fp=fopen(v,"r"); + if(!fp) fatal("Unable to load palette file '%s'\n%m",v); + } + for(i=0;i<256;i++) { + if(fp) { + if(fscanf(fp,"%2hhX%2hhX%2hhX ",&pal[i].r,&pal[i].g,&pal[i].b)!=3) fatal("Invalid palette file\n"); + } else { + sscanf(default_palette+i*7,"%2hhX%2hhX%2hhX ",&pal[i].r,&pal[i].g,&pal[i].b); + } + if(usegamma) { + j=(int)pow(pal[i].r+0.3,gamma); pal[i].r=j<0?0:j>255?255:j; + j=(int)pow(pal[i].g+0.3,gamma); pal[i].g=j<0?0:j>255?255:j; + j=(int)pow(pal[i].b+0.3,gamma); pal[i].b=j<0?0:j>255?255:j; + } + } + if(fp) fclose(fp); + SDL_SetColors(screen,pal,0,256); + SDL_SetColors(picts,pal,0,256); +} + +void draw_picture(int x,int y,Uint16 img) { + // To be called only when screen is unlocked! + SDL_Rect src={(img&15)*picture_size,(img>>4)*picture_size,picture_size,picture_size}; + SDL_Rect dst={x,y,picture_size,picture_size}; + SDL_BlitSurface(picts,&src,screen,&dst); +} + +void draw_text(int x,int y,const unsigned char*t,int bg,int fg) { + // To be called only when screen is locked! + int len=strlen(t); + Uint8*pix=screen->pixels; + Uint8*p; + Uint16 pitch=screen->pitch; + int xx,yy; + const unsigned char*f; + if(x+8*len>screen->w) len=(screen->w-x)>>3; + if(len<=0 || y+8>screen->h) return; + pix+=y*pitch+x; + while(*t) { + f=fontdata+(*t<<3); + for(yy=0;yy<8;yy++) { + for(xx=0;xx<8;xx++) p[xx]=(*f<=size?p[-size]:0; + *p++=c; + } +} + +static void load_one_picture(FILE*fp,Uint16 img,int alt) { + int i,j,k,pitch,which,meth,size; + Uint8 buf[32]; + Uint8*pix; + *buf=fgetc(fp); + j=*buf&15; + fread(buf+1,1,j+(j>>1),fp); + k=0; + for(i=1;i<=j;i++) if(buf[i]==picture_size) ++k; + alt%=k; + for(i=1;i<=j;i++) if(buf[i]==picture_size && !alt--) break; + which=i; + i=1; + while(which--) load_one_picture_sub(fp,size=buf[i],meth=(i==1?*buf>>4:buf[(*buf&15)+1+((i-2)>>1)]>>(i&1?4:0))&15),i++; + if(meth==5 || meth==6) meth^=3; + SDL_LockSurface(picts); + pitch=picts->pitch; + pix=picts->pixels+((img&15)+pitch*(img>>4))*picture_size; + if(meth==15) meth=0; + for(i=0;i255) fatal("Invalid picture size %d\n",i); + wantsize[nwantsize++]=i; + v+=j; + } + sqlite3_exec(userdb,"BEGIN;",0,0,0); + if(sqlite3_prepare_v2(userdb,"INSERT INTO `PICTURES`(`ID`,`NAME`,`OFFSET`) VALUES(?1,?2,?3);",-1,&st,0)) + fatal("Unable to prepare SQL statement while loading pictures: %s\n",sqlite3_errmsg(userdb)); + nam=malloc(256); + if(!nam) fatal("Allocation failed\n"); + n=0; + memset(havesize,0,256*sizeof(Uint16)); + while(!feof(fp)) { + i=0; + while(j=fgetc(fp)) { + if(j==EOF) goto nomore1; + if(i<255) nam[i++]=j; + } + nam[i]=0; + if(i>4 && !memcmp(".IMG",nam+i-4,4)) { + j=1; + if(n++==32768) fatal("Too many pictures\n"); + sqlite3_reset(st); + sqlite3_bind_int(st,1,n); + sqlite3_bind_text(st,2,nam,i,SQLITE_TRANSIENT); + sqlite3_bind_int64(st,3,ftell(fp)+4); + while((i=sqlite3_step(st))==SQLITE_ROW); + if(i!=SQLITE_DONE) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb)); + } else { + j=0; + } + i=fgetc(fp)<<16; + i|=fgetc(fp)<<24; + i|=fgetc(fp)<<0; + i|=fgetc(fp)<<8; + if(j) { + i-=j=fgetc(fp)&15; + while(j--) ++havesize[fgetc(fp)&255]; + fseek(fp,i-1,SEEK_CUR); + } else { + fseek(fp,i,SEEK_CUR); + } + } +nomore1: + if(!n) fatal("Cannot find any pictures in this puzzle set\n"); + free(nam); + sqlite3_finalize(st); + rewind(fp); + for(i=255;i;--i) if(havesize[i]) { + curpic=malloc(i*i); + break; + } + if(!curpic) fatal("Allocation failed\n"); + for(i=0;i<256;i++) havesize[i]=(havesize[i]==n)?1:0; + picture_size=decide_picture_size(nwantsize,wantsize,havesize); + if(sqlite3_prepare_v2(userdb,"SELECT `ID`, `OFFSET` FROM `PICTURES`;",-1,&st,0)) + fatal("Unable to prepare SQL statement while loading pictures: %s\n",sqlite3_errmsg(userdb)); + optionquery[2]=Q_screenFlags; + v=xrm_get_resource(resourcedb,optionquery,optionquery,2); + i=v&&strchr(v,'h'); + picts=SDL_CreateRGBSurface((i?SDL_HWSURFACE:SDL_SWSURFACE)|SDL_SRCCOLORKEY,picture_size<<4,picture_size*((n+15)>>4),8,0,0,0,0); + if(!picts) fatal("Error allocating surface for pictures: %s\n",SDL_GetError()); + init_palette(); + for(i=0;ix.trim()).filter(x=>x&&x[0]!="!"); quarks.forEach((x,y)=>console.log("#define Q_"+x+" "+(y+2))); console.log("static const char*const global_quarks[]={"); quarks.forEach(x=>console.log(" \""+x+"\",")); -console.log("0}; static const SDLKey quark_to_key[Q_undo+1-Q_backspace]={"); +console.log("0};\n#ifdef HEROMESH_MAIN\nstatic const SDLKey quark_to_key[Q_undo+1-Q_backspace]={"); quarks.slice(quarks.indexOf("backspace"),quarks.indexOf("undo")+1).forEach(x=>console.log("SDLK_"+x[x.length==1?"toLowerCase":"toUpperCase"]()+",")); -console.log("};\n#define FirstKeyQuark Q_backspace\n#define LastKeyQuark Q_undo"); +console.log("};\n#define FirstKeyQuark Q_backspace\n#define LastKeyQuark Q_undo\n#endif");