Index: commandline.doc ================================================================== --- commandline.doc +++ commandline.doc @@ -40,10 +40,13 @@ -n Create a new puzzle set. The .xclass and .class files should already exist; the .level and .solution files should not already exist, and will be created with minimal data. +-p + Start the picture editor. + -r Open in read-only mode. -t Enable tracing. Index: compile ================================================================== --- compile +++ compile @@ -1,22 +1,22 @@ #!/bin/bash -- set -e test -f CFLAGS || echo xxx > CFLAGS -test "xx$CFLAGS" = "x`cat CFLAGS`" || rm bindings.o class.o picture.o function.o exec.o game.o edit.o || true +test "xx$CFLAGS" = "x`cat CFLAGS`" || rm bindings.o class.o picture.o function.o exec.o game.o edit.o picedit.o || true echo "x$CFLAGS" > CFLAGS test "x$EXE" = "x" && EXE=~/bin/heromesh echo 'Flags: ' "$CFLAGS" echo 'Target filename: ' "$EXE" test instruc -nt instruc.h && node instruc.js > instruc.h test instruc.js -nt instruc.h && node instruc.js > instruc.h test names.js -nt names.h && node names.js > names.h test quarks -nt quarks.h && node quarks.js > quarks.h test quarks.js -nt quarks.h && node quarks.js > quarks.h -test heromesh.h -nt "$EXE" && rm bindings.o class.o picture.o function.o exec.o game.o edit.o || true +test heromesh.h -nt "$EXE" && rm bindings.o class.o picture.o function.o exec.o game.o edit.o picedit.o || true test instruc.h -nt "$EXE" && rm class.o exec.o || true test pcfont.h -nt "$EXE" && rm picture.o || true -test quarks.h -nt "$EXE" && rm bindings.o edit.o exec.o game.o picture.o || true +test quarks.h -nt "$EXE" && rm bindings.o edit.o exec.o game.o picture.o picedit.o || true echo '* bindings' test bindings.c -nt bindings.o && bash bindings.c echo '* class' test class.c -nt class.o && bash class.c echo '* function' @@ -27,8 +27,10 @@ test exec.c -nt exec.o && bash exec.c echo '* game' test game.c -nt game.o && bash game.c echo '* edit' test edit.c -nt edit.o && bash edit.c +echo '* picedit' +test picedit.c -nt picedit.o && bash picedit.c echo '* main' bash main.c echo 'DONE' Index: heromesh.h ================================================================== --- heromesh.h +++ heromesh.h @@ -88,10 +88,14 @@ extern SDL_Surface*screen; extern Uint16 picture_size; extern int left_margin; +void init_palette(void); +void init_screen(void); +void load_pictures(void); + // Use only when screen is unlocked void draw_picture(int x,int y,Uint16 img); void draw_cell(int x,int y); // Use only when screen is locked @@ -98,11 +102,10 @@ void draw_text(int x,int y,const unsigned char*t,int bg,int fg); void draw_key(int x,int y,int k,int bg,int fg); const char*screen_prompt(const char*txt); int screen_message(const char*txt); -void load_pictures(void); int scrollbar(int*cur,int page,int max,SDL_Event*ev,SDL_Rect*re); void draw_popup(const unsigned char*txt); int modal_draw_popup(const unsigned char*txt); @@ -267,5 +270,9 @@ // == edit == void run_editor(void); void write_empty_level_set(FILE*); +// == picedit == + +void run_picture_editor(void); + Index: main.c ================================================================== --- main.c +++ main.c @@ -1,7 +1,7 @@ #if 0 -gcc ${CFLAGS:--s -O2} -o ${EXE:-~/bin/heromesh} main.c class.o picture.o bindings.o function.o exec.o game.o edit.o smallxrm.o sqlite3.o `sdl-config --cflags --libs` -ldl -lpthread +gcc ${CFLAGS:--s -O2} -o ${EXE:-~/bin/heromesh} main.c class.o picture.o bindings.o function.o exec.o game.o edit.o picedit.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. @@ -865,10 +865,11 @@ if(main_options['n']) { if(main_options['r']) fatal("Switches -r and -n are conflicting\n"); main_options['x']=1; } if(main_options['a']) main_options['r']=main_options['x']=1; + if(main_options['p']) main_options['r']=1; if(!main_options['c']) load_options(); if(argc>optind) read_options(argc-optind,argv+optind); *optionquery=xrm_make_quark(globalclassname,0)?:xrm_anyq; #ifdef __GNUC__ stack_protect_mark=__builtin_frame_address(0); @@ -879,10 +880,14 @@ return 0; } init_sql(); load_key_bindings(); init_screen(); + if(main_options['p']) { + run_picture_editor(); + return 0; + } load_pictures(); if(main_options['T']) { test_mode(); return 0; } Index: man6/heromesh.6 ================================================================== --- man6/heromesh.6 +++ man6/heromesh.6 @@ -30,10 +30,12 @@ .IP -e Start the level editor. .IP -n Create a new puzzle set. The class definition file and image set must already exist. +.IP -p +Start the picture editor. .IP -r Open in read-only mode. .IP -t Enable message tracing. .IP -v ADDED picedit.c Index: picedit.c ================================================================== --- picedit.c +++ picedit.c @@ -0,0 +1,215 @@ +#if 0 +gcc ${CFLAGS:--s -O2} -c -Wno-multichar picedit.c `sdl-config --cflags` +exit +#endif + +/* + This program is part of Free Hero Mesh and is public domain. +*/ + +#include "SDL.h" +#include +#include +#include +#include "sqlite3.h" +#include "smallxrm.h" +#include "heromesh.h" +#include "quarks.h" +#include "cursorshapes.h" + +typedef struct { + Uint8 size; + Uint8 data[0]; +} Picture; + +static int load_picture_file(void) { + sqlite3_stmt*st=0; + FILE*fp; + char*nam; + char*buf=0; + int r=0; + int i,j; + i=sqlite3_exec(userdb, + "BEGIN;" + "CREATE TEMPORARY TABLE `PICEDIT`(`ID` INTEGER PRIMARY KEY,`NAME` TEXT NOT NULL COLLATE NOCASE,`TYPE` INT,`DATA` BLOB);" + "CREATE INDEX `PICEDIT_I1` ON `PICEDIT`(`NAME`,`TYPE`);" + ,0,0,0); + if(i) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb)); + nam=sqlite3_mprintf("%s.xclass",basefilename); + if(!nam) fatal("Allocation failed\n"); + fprintf(stderr,"Loading pictures...\n"); + fp=fopen(nam,"r"); + sqlite3_free(nam); + if(!fp) { + nam=0; + fprintf(stderr,"%m\n"); + goto done; + } + nam=malloc(256); + if(!nam) fatal("Allocation failed\n"); + i=sqlite3_prepare_v2(userdb,"INSERT INTO `PICEDIT`(`NAME`,`TYPE`,`DATA`) VALUES(?1,?2,?3);",-1,&st,0); + if(i) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb)); + while(!feof(fp)) { + i=0; + while(j=fgetc(fp)) { + if(j==EOF) goto done; + if(i<255) nam[i++]=j; + } + nam[i]=0; + sqlite3_reset(st); + sqlite3_bind_text(st,1,nam,i,SQLITE_TRANSIENT); + sqlite3_bind_int(st,2,j=(i>4 && !memcmp(".IMG",nam+i-4,4)?1:0)); + r+=j; + i=fgetc(fp)<<16; + i|=fgetc(fp)<<24; + i|=fgetc(fp)<<0; + i|=fgetc(fp)<<8; + if(!i) continue; + buf=realloc(buf,i); + if(!buf) fatal("Allocation failed\n"); + fread(buf,1,i,fp); + sqlite3_bind_blob(st,3,buf,i,SQLITE_TRANSIENT); + while((i=sqlite3_step(st))==SQLITE_ROW); + if(i!=SQLITE_DONE) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb)); + } +done: + if(st) sqlite3_finalize(st); + if(fp) fclose(fp); + free(nam); + free(buf); + fprintf(stderr,"Done\n"); + return r; +} + +static void save_picture_file(void) { + sqlite3_stmt*st; + FILE*fp; + char*s=sqlite3_mprintf("%s.xclass",basefilename); + int i; + const char*nam; + const char*buf; + if(!s) fatal("Allocation failed\n"); + fprintf(stderr,"Saving pictures...\n"); + fp=fopen(s,"w"); + if(!fp) fatal("Cannot open picture file for writing: %m\n"); + sqlite3_free(s); + i=sqlite3_prepare_v2(userdb,"SELECT `NAME`,`DATA` FROM `PICEDIT`;",-1,&st,0); + if(i) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb)); + while((i=sqlite3_step(st))==SQLITE_ROW) { + nam=sqlite3_column_text(st,0); + buf=sqlite3_column_blob(st,1); + i=sqlite3_column_bytes(st,1); + if(!nam) continue; + fwrite(nam,1,strlen(nam)+1,fp); + fputc(i>>16,fp); + fputc(i>>24,fp); + fputc(i>>0,fp); + fputc(i>>8,fp); + if(i) fwrite(buf,1,i,fp); + } + if(i!=SQLITE_DONE) fprintf(stderr,"SQL error (%d): %s\n",i,sqlite3_errmsg(userdb)); +done: + if(st) sqlite3_finalize(st); + if(fp) fclose(fp); + fprintf(stderr,"Done\n"); +} + +static sqlite3_int64 ask_picture_id(const char*t) { + sqlite3_stmt*st; + const char*r=screen_prompt(t); + int i; + sqlite3_int64 id=0; + if(!r || !*r) return 0; + i=sqlite3_prepare_v2(userdb,"SELECT `ID` FROM `PICEDIT` WHERE `NAME` = (?1 || '.IMG');",-1,&st,0); + if(i) { + screen_message(sqlite3_errmsg(userdb)); + return 0; + } + sqlite3_bind_text(st,1,r,-1,0); + i=sqlite3_step(st); + if(i==SQLITE_ROW) id=sqlite3_column_int64(st,0); + if(i==SQLITE_DONE) screen_message("Picture not found"); + sqlite3_finalize(st); + return id; +} + +static void edit_picture(sqlite3_int64 id) { + +} + +static void set_caption(void) { + char buf[256]; + snprintf(buf,255,"Free Hero Mesh - %s - Picture",basefilename); + SDL_WM_SetCaption(buf,buf); +} + +void run_picture_editor(void) { + sqlite3_int64*ids; + SDL_Event ev; + SDL_Rect r; + sqlite3_stmt*st; + int sc=0; + int max=load_picture_file(); + int i,n; + init_palette(); + set_cursor(XC_arrow); + set_caption(); + i=sqlite3_prepare_v3(userdb,"SELECT `ID`,SUBSTR(`NAME`,1,LENGTH(`NAME`)-4),`TYPE` FROM `PICEDIT` WHERE `TYPE` ORDER BY `NAME` LIMIT ?1 OFFSET ?2;",-1,SQLITE_PREPARE_PERSISTENT,&st,0); + if(i) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb)); + ids=calloc(screen->h/8,sizeof(sqlite3_int64)); + if(!ids) fatal("Allocation failed\n"); + redraw: + sqlite3_reset(st); + if(sc>max-screen->h/8) sc=max-screen->h/8; + if(sc<0) sc=0; + sqlite3_bind_int(st,1,screen->h/8-1); + sqlite3_bind_int(st,2,sc); + SDL_LockSurface(screen); + r.x=r.y=0; r.w=screen->w; r.h=screen->h; + SDL_FillRect(screen,&r,0xF0); + draw_text(0,0," Save/Quit Add Delete Edit",0xF0,0xFB); + n=0; + while((i=sqlite3_step(st))==SQLITE_ROW) { + ids[n++]=sqlite3_column_int64(st,0); + draw_text(16,8*n,sqlite3_column_text(st,1),0xF0,0xF7); + if(8*n+8>screen->h-8) break; + } + SDL_UnlockSurface(screen); + sqlite3_reset(st); + r.y=8; r.h-=8; + scrollbar(&sc,r.h/8,max,0,&r); + SDL_Flip(screen); + while(SDL_WaitEvent(&ev)) { + if(ev.type!=SDL_VIDEOEXPOSE && scrollbar(&sc,screen->h/8,max,&ev,&r)) goto redraw; + switch(ev.type) { + case SDL_QUIT: + return; + case SDL_KEYDOWN: + switch(ev.key.keysym.sym) { + case SDLK_ESCAPE: + if(!(ev.key.keysym.mod&(KMOD_SHIFT|KMOD_CTRL))) save_picture_file(); + return; + case SDLK_q: + if(!(ev.key.keysym.mod&KMOD_CTRL)) break; + if(!(ev.key.keysym.mod&KMOD_SHIFT)) save_picture_file(); + return; + case SDLK_HOME: sc=0; goto redraw; + case SDLK_UP: if(sc) --sc; goto redraw; + case SDLK_DOWN: ++sc; goto redraw; + case SDLK_END: sc=max-screen->h/8; goto redraw; + case SDLK_PAGEUP: sc-=screen->h/8-1; goto redraw; + case SDLK_PAGEDOWN: sc+=screen->h/8-1; goto redraw; + case SDLK_F3: + *ids=ask_picture_id("Edit:"); + if(*ids) edit_picture(*ids); + goto redraw; + } + break; + case SDL_MOUSEMOTION: + set_cursor(XC_arrow); + break; + case SDL_VIDEOEXPOSE: + goto redraw; + } + } +} Index: picture.c ================================================================== --- picture.c +++ picture.c @@ -50,11 +50,11 @@ // "000000 0000AA 00AA00 00AAAA AA0000 AA00AA AAAA00 AAAAAA " "555555 5555FF 55FF55 55FFFF FF5555 FF55FF FFFF55 FFFFFF " ; -static void init_palette(void) { +void init_palette(void) { double gamma; int usegamma=1; int i,j; SDL_Color pal[256]; FILE*fp=0;