Free Hero Mesh

Check-in [6e1b1bf6d3]
Login
This is a mirror of the main repository for Free Hero Mesh. New tickets and changes will not be accepted at this mirror.
Overview
Comment:Start to implement the picture editor
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 6e1b1bf6d34dc95688f260c0e8b115a39ab0dc5b
User & Date: user on 2021-01-11 06:22:26
Other Links: manifest | tags
Context
2021-01-11
07:09
Add keyicons/1.xbm check-in: 7597620f97 user: user tags: trunk
06:22
Start to implement the picture editor check-in: 6e1b1bf6d3 user: user tags: trunk
2021-01-10
23:58
Mention in the documentation about the autotest mode, regular expression to find errors check-in: 839e21c938 user: user tags: trunk
Changes

Modified commandline.doc from [ea8d54a2cc] to [5cf69605ba].

38
39
40
41
42
43
44



45
46
47
48
49
50
51
  Start in the editor instead of game.

-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.




-r
  Open in read-only mode.

-t
  Enable tracing.

-v







>
>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  Start in the editor instead of game.

-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.

-v

Modified compile from [a67bcb4704] to [309c7eb53b].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31


32
33
34
#!/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
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 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
echo '* bindings'
test bindings.c -nt bindings.o && bash bindings.c
echo '* class'
test class.c -nt class.o && bash class.c
echo '* function'
test function.c -nt function.o && bash function.c
echo '* picture'
test picture.c -nt picture.o && bash picture.c
echo '* exec'
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 '* main'
bash main.c
echo 'DONE'



|









|


|














>
>



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/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 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 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 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'
test function.c -nt function.o && bash function.c
echo '* picture'
test picture.c -nt picture.o && bash picture.c
echo '* exec'
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'

Modified heromesh.h from [e8f5d32ef9] to [af1df60f10].

86
87
88
89
90
91
92




93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

// == picture ==

extern SDL_Surface*screen;
extern Uint16 picture_size;
extern int left_margin;





// 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
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);

// == class ==







>
>
>
>










<







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

107
108
109
110
111
112
113

// == picture ==

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
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);


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);

// == class ==
265
266
267
268
269
270
271




void locate_me(int x,int y);

// == edit ==

void run_editor(void);
void write_empty_level_set(FILE*);












>
>
>
>
268
269
270
271
272
273
274
275
276
277
278
void locate_me(int x,int y);

// == edit ==

void run_editor(void);
void write_empty_level_set(FILE*);

// == picedit ==

void run_picture_editor(void);

Modified main.c from [e9e638bdea] to [b062b0f69d].

1
2
3
4
5
6
7
8
9
#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
exit
#endif

/*
  This program is part of Free Hero Mesh and is public domain.
*/


|







1
2
3
4
5
6
7
8
9
#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 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.
*/

863
864
865
866
867
868
869

870
871
872
873
874
875
876
877
878
879
880
881
882
883




884
885
886
887
888
889
890
    globalclassname=globalclassname?globalclassname+1:basefilename;
  }
  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['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);
  set_stack_protection();
#endif
  if(main_options['c']) {
    load_classes();
    return 0;
  }
  init_sql();
  load_key_bindings();
  init_screen();




  load_pictures();
  if(main_options['T']) {
    test_mode();
    return 0;
  }
  init_usercache();
  if(main_options['n']) return 0;







>














>
>
>
>







863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
    globalclassname=globalclassname?globalclassname+1:basefilename;
  }
  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);
  set_stack_protection();
#endif
  if(main_options['c']) {
    load_classes();
    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;
  }
  init_usercache();
  if(main_options['n']) return 0;

Modified man6/heromesh.6 from [b9875397f8] to [a7a48743c1].

28
29
30
31
32
33
34


35
36
37
38
39
40
41
This can be used to verify that the class definition file does not contain syntax errors.
You can also use it with some other options to display details.
.IP -e
Start the level editor.
.IP -n
Create a new puzzle set.
The class definition file and image set must already exist.


.IP -r
Open in read-only mode.
.IP -t
Enable message tracing.
.IP -v
More verbose error logging.
.IP -x







>
>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
This can be used to verify that the class definition file does not contain syntax errors.
You can also use it with some other options to display details.
.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
More verbose error logging.
.IP -x

Added picedit.c version [2a538fb519].















































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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,"<ESC> Save/Quit  <F1> Add  <F2> Delete  <F3> 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;
    }
  }
}

Modified picture.c from [f5de034dcf] to [207559e683].

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  //
  "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[1]=Q_gamma;







|







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  //
  "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 "
;

void init_palette(void) {
  double gamma;
  int usegamma=1;
  int i,j;
  SDL_Color pal[256];
  FILE*fp=0;
  const char*v;
  optionquery[1]=Q_gamma;