33 struct tile
* undo
; /* writes to undo */
34 struct tile
* redo
; /* writes to redo */
41 /* application state variables */
42 int toggle_background
= 1;
43 int toggle_bgtiles
= 1;
44 int toggle_fgtiles
= 1;
45 int toggle_shapes
= 0;
49 static int camera_x
= 0;
50 static int camera_y
= 0;
52 const char shapechars
[20] = "Mmw12345678abcd";
54 char my_file
[256] = "";
55 char my_file_old
[256] = "";
56 char bgimage_file
[256] = "";
57 char fgtiles_file
[256] = "";
58 char bgtiles_file
[256] = "";
59 char zone_path
[256] = "";
66 int select_enable
= 0;
72 struct tile
* raw_tiles
= NULL
;
76 int show_favorites
= 0;
77 int bg_favorites
[7] = {0,1,2,3,4,5,6};
78 int fg_favorites
[7] = {0,1,2,3,4,5,6};
88 int background_dialog
= 0;
89 int tileset_dialog
= 0;
91 int save_as_dialog
= 0;
93 int confirm_save_dialog
= 0;
100 int tile_panel_set
= 0;
101 int tile_panel_page
= 0;
102 int tile_panel_offset
= 0;
104 char save_as_buf
[256] = "";
106 char open_buf
[256] = "";
108 char generic_buf
[256] = "";
111 char gfx_path_buf
[256] = "";
112 char stage_path_buf
[256] = "";
118 void update_window_name(){
120 SDL_WM_SetCaption("unnamed", NULL
);
123 SDL_WM_SetCaption(my_file
, NULL
);
128 void select_bgfile(char* path
){
129 strcpy(bgimage_file
, path
);
132 void set_zone_path(char* path
){
133 strncpy(zone_path
, path
, 256);
135 if(zone_path
[strlen(zone_path
)-1] != '/'){
136 strncat(zone_path
, "/", 256);
141 int file_exists(char* path
){
142 FILE* f
= fopen(path
, "r");
152 char* compute_stage_path(char* stage
){
153 strcpy(stage_path_buf
, zone_path
);
154 strcat(stage_path_buf
, "stages/");
155 strcat(stage_path_buf
, stage
);
156 return stage_path_buf
;
159 char* compute_gfx_path(char* gfxfile
){
160 strcpy(gfx_path_buf
, zone_path
);
161 strcat(gfx_path_buf
, "gfx/");
162 strcat(gfx_path_buf
, gfxfile
);
170 /* base access methods */
171 struct tile
* initialize_raw(int w
, int h
){
174 struct tile blank
= {'0', 0, 0};
175 struct tile
* ptr
= malloc(w
*h
*sizeof(struct tile
));
178 *(ptr
+ i
+ j
*w
) = blank
;
191 raw_tiles
= initialize_raw(20, 15);
202 update_window_name();
205 struct tile
raw_read(int x
, int y
){
206 struct tile blank
= {'0', 0, 0};
207 if(x
< 0 || y
< 0 || x
>= raw_w
|| y
>= raw_h
){
211 return *(raw_tiles
+ x
+ raw_w
*y
);
216 int new_w
= raw_w
* 3;
217 int new_h
= raw_h
* 3;
218 struct tile
* new_tiles
= initialize_raw(new_w
, new_h
);
224 for(j
=raw_h
; j
<2*raw_h
; j
++){
225 for(i
=raw_w
; i
<2*raw_w
; i
++){
226 ptr
= new_tiles
+ i
+ j
*(3*raw_w
);
227 t
= raw_read(i
-raw_w
, j
-raw_h
);
237 raw_tiles
= new_tiles
;
240 int out_of_bounds(int x
, int y
){
241 if(x
< 0 || y
< 0 || x
>= raw_w
|| y
>= raw_h
)
247 void detect_size(int* w
, int* h
){
248 //see the minimum size necessary for the area
252 void raw_write(int x
, int y
, int layer
, int value
){
253 while(out_of_bounds(x
, y
)){
260 //shift x y by expand shift
261 //shift x and y by origin
263 struct tile
* ptr
= raw_tiles
+ x
+ raw_w
*y
;
275 void draw_background(){
276 int W
= gfx_width(bgimage
);
277 int H
= gfx_height(bgimage
);
278 draw_gfx_raw(bgimage
, 0, 0, 0, 0, W
, H
);
282 int x0
= camera_x
+ origin_x
;
283 int y0
= camera_y
+ origin_y
;
292 if(toggle_background
)
295 for(j
=0; j
<(15+5); j
++){
297 for(i
=0; i
<(20+8); i
++){
303 draw_gfx_raw(bgtiles
, i
*16, j
*16, gx
, gy
, 16, 16);
307 draw_gfx_raw(fgtiles
, i
*16, j
*16, gx
, gy
, 16, 16);
308 gy
= 16*(t
.shape
/ 16);
309 gx
= 16*(t
.shape
% 16);
311 draw_gfx_raw(shapes
, i
*16, j
*16, gx
, gy
, 16, 16);
317 /* determine an optimal size for the stage */
318 void raw_optimize(int* ox
, int* oy
, int* ow
, int* oh
){
327 for(i
=0; i
<(raw_w
*raw_h
); i
++){
330 fg
= raw_tiles
[i
].fg
;
331 bg
= raw_tiles
[i
].bg
;
332 shape
= raw_tiles
[i
].shape
;
333 if((fg
!= 0 || bg
!= 0 || shape
!= '0')){
334 if(x
> xmax
) xmax
= x
;
335 if(x
< xmin
) xmin
= x
;
336 if(y
> ymax
) ymax
= y
;
337 if(y
< ymin
) ymin
= y
;
341 if(ymax
- ymin
+ 1 <= 15) *oh
= 15;
342 else *oh
= (ymax
- ymin
+ 1);
344 if(xmax
- xmin
+ 1 <= 20) *ow
= 20;
345 else *ow
= (xmax
- xmin
+ 1);
351 int raw_save(char* path
){
352 /* save current stage to a stage file */
353 /* overwrites if already exists, no confirmation */
357 struct tile
* ptr
= raw_tiles
;
359 int opt_x
, opt_y
, opt_w
, opt_h
;
362 FILE* f
= fopen(path
, "w");
364 console_printf("error saving file");
368 raw_optimize(&opt_x
, &opt_y
, &opt_w
, &opt_h
);
370 fprintf(f
, "%d %d %d %d\n", opt_w
, opt_h
, origin_x
-opt_x
, origin_y
-opt_y
);
371 fprintf(f
, "%s\n", bgimage_file
);
372 fprintf(f
, "%s\n", fgtiles_file
);
373 fprintf(f
, "%s\n", bgtiles_file
);
375 for(i
=0; i
<(raw_w
*raw_h
); i
++){
376 x
= (i
% raw_w
) - origin_x
;
377 y
= (i
/ raw_w
) - origin_y
;
380 shape
= ptr
[i
].shape
;
382 if(fg
!= 0 || bg
!= 0 || shape
!= '0'){
383 fprintf(f
, "%d %d %d %d %c\n", x
, y
, fg
, bg
, shape
);
392 void save(char* stagename
){
393 char* path
= compute_stage_path(stagename
);
394 if(raw_save(path
) < 0){
395 console_printf("%s NOT saved", stagename
);
398 console_printf("%s saved", stagename
);
403 int raw_open(char* stagename
){
408 char file1
[256] = "";
409 char file2
[256] = "";
410 char file3
[256] = "";
411 struct tile
* new_tiles
= NULL
;
413 char* path
= compute_stage_path(stagename
);
415 r
= loader_open(path
);
417 console_printf("Can't open %s", path
);
421 if(loader_scanline(r
, "%d %d %d %d", &w
, &h
, &ox
, &oy
) < 4){
422 printf("scan error\n");
428 loader_readline(r
, file1
, 256) ||
429 loader_readline(r
, file2
, 256) ||
430 loader_readline(r
, file3
, 256)
432 printf("scan error\n");
437 new_tiles
= initialize_raw(w
, h
);
438 while(loader_scanline(r
, "%d %d %d %d %c", &x
, &y
, &fg
, &bg
, &shape
) == 5){
439 ptr
= new_tiles
+ (x
+ox
) + (y
+oy
)*w
;
445 /* load the graphics */
446 path
= compute_gfx_path(file1
);
447 if(file1
[0] != 0 && file_exists(path
)) bgimage
= load_bitmap(path
);
450 path
= compute_gfx_path(file2
);
451 if(file2
[0] != 0 && file_exists(path
)) bgtiles
= load_bitmap(path
);
454 path
= compute_gfx_path(file3
);
455 if(file3
[0] != 0 && file_exists(path
)) fgtiles
= load_bitmap(path
);
464 raw_tiles
= new_tiles
;
466 strcpy(bgimage_file
, file1
);
467 strcpy(bgtiles_file
, file2
);
468 strcpy(fgtiles_file
, file3
);
470 strcpy(my_file
, stagename
);
480 struct undo_step
* undo_stack
;
481 struct undo_step
* undo_ptr
;
483 /* undo operations */
485 //do the undo_ptr->undo operations
486 //move undo_ptr down one
490 //if at top of stack, do nothing
492 //do the undo_ptr->redo operations
493 //move undo_ptr up one
496 void undo_record(struct edit
* edits
){
497 //eliminate undo_ptr->redo and all previous edit structs
498 //change the undo_stack
500 //store the edits in undo_ptr->redo
501 //calculate the undo operation XXX
502 //push a new edit struct
504 //store the undo operation in undo_ptr->undo
511 /* medium level editting commands */
512 void write_one_tile(int x
, int y
, int layer
, int value
){
513 //write x y layer value
516 void write_many_tiles(struct edit
* edits
){
521 void edit_one_tile(int x
, int y
, int layer
, int value
){
523 //create a tile struct
527 void edit_many_tiles(struct edit
* edits
){
532 void add_to_clipboard(struct edit
* edits
){
533 //makes a tile struct and appends to clipboard
536 void clear_clipboard(){
537 //clear the clipboard
540 struct tile
* read_tile(int x
, int y
){
547 /* high level gui commands */
555 int value
= brush_tile
;
556 int layer
= brush_layer
;
558 if(layer
== 1) favs
= bg_favorites
;
559 if(layer
== 2) favs
= fg_favorites
;
562 if(favs
[i
] == value
){
582 void start_box(int x
, int y
){
586 void move_box(int x
, int y
){
598 void append_to_box(int x
, int y
){
602 struct tile
* box_select(){
607 void move_paste(int x
, int y
){
632 void draw_tile_panel(){
638 draw_black_rect(0,0,9*16,20*16);
639 draw_gfx_raw(tools
, 0, 14*16, 4*16, 0, 16, 16);
640 draw_gfx_raw(tools
, 16, 14*16, 5*16, 0, 16, 16);
641 draw_gfx_raw(tools
, 2*16, 14*16, 6*16, 0, 16, 16);
642 draw_gfx_raw(tools
, 7*16, 14*16, 7*16, 0, 16, 16);
644 if(tile_panel_page
== 0) tile_panel_offset
= 0;
645 if(tile_panel_page
== 1) tile_panel_offset
= 112;
646 if(tile_panel_page
== 2) tile_panel_offset
= 144;
648 if(tile_panel_set
== 0) gfx
= fgtiles
;
649 if(tile_panel_set
== 1) gfx
= bgtiles
;
651 for(i
=0; i
<112; i
++){
657 draw_gfx_raw(gfx
, x
, y
, gx
, gy
+tile_panel_offset
, 16, 16);
665 draw_black_rect(16, 16, 17*16, 11*16);
667 /* fg tile tool and favorites */
668 draw_gfx_raw(tools
, 2*16, 2*16, 0, 0, 16, 16);
671 gx
= 16*(fg_favorites
[i
] % 16);
672 gy
= 16*(fg_favorites
[i
] / 16);
673 draw_gfx_raw(fgtiles
, 16*(i
+4), 2*16, gx
, gy
, 16, 16);
676 /* bg tile tool and favorites */
677 draw_gfx_raw(tools
, 2*16, 4*16, 16, 0, 16, 16);
680 gx
= 16*(bg_favorites
[i
] % 16);
681 gy
= 16*(bg_favorites
[i
] / 16);
682 draw_gfx_raw(bgtiles
, 16*(i
+4), 4*16, gx
, gy
, 16, 16);
687 gx
= 16*(shapechars
[i
] % 16);
688 gy
= 16*(shapechars
[i
] / 16);
689 draw_gfx_raw(shapes
, 16*(i
+2), 6*16, gx
, gy
, 16, 16);
692 draw_gfx_raw(tools
, 2*16, 8*16, 2*16, 0, 16, 16);
693 draw_gfx_raw(tools
, 4*16, 8*16, 3*16, 0, 16, 16);
709 console_printf("save as: %s", save_as_buf
);
713 console_printf("open file: %s", open_buf
);
725 if(brush_layer
== 1){
726 console_printf("bg tileset: %s", generic_buf
);
728 else if(brush_layer
== 2){
729 console_printf("fg tileset: %s", generic_buf
);
733 if(background_dialog
){
734 console_printf("background image: %s", generic_buf
);
738 console_printf("path to zone: %s", generic_buf
);
752 /* dialog input handlers */
753 void pixel_to_tile(int mx
, int my
, int* x
, int* y
){
754 map_pixel(mx
, my
, x
, y
);
759 void zone_press(SDLKey key
, Uint16 c
){
761 if(generic_buf
[0] == 0){
762 console_printf("No name? Nevermind then.");
765 set_zone_path(generic_buf
);
766 console_printf("zone set to %s", zone_path
);
780 generic_buf
[generic_ptr
] = 0;
786 if(generic_ptr
< 255){
787 generic_buf
[generic_ptr
] = c
;
789 generic_buf
[generic_ptr
] = 0;
795 void tileset_press(SDLKey key
, Uint16 c
){
797 if(generic_buf
[0] == 0){
798 console_printf("No name? Nevermind then.");
801 char* path
= compute_gfx_path(generic_buf
);
802 int gfx
= load_bitmap(path
);
804 console_printf("file not found");
807 if(brush_layer
== 1){
808 strcpy(bgtiles_file
, generic_buf
);
809 bgtiles
= load_bitmap(path
);
811 else if(brush_layer
== 2){
812 strcpy(fgtiles_file
, generic_buf
);
813 fgtiles
= load_bitmap(path
);
829 generic_buf
[generic_ptr
] = 0;
835 if(generic_ptr
< 255){
836 generic_buf
[generic_ptr
] = c
;
838 generic_buf
[generic_ptr
] = 0;
843 void background_press(SDLKey key
, Uint16 c
){
845 if(generic_buf
[0] == 0){
846 console_printf("No name? Nevermind then.");
849 char* path
= compute_gfx_path(generic_buf
);
850 int gfx
= load_bitmap(path
);
852 console_printf("file not found");
855 strcpy(bgimage_file
, generic_buf
);
856 bgimage
= load_bitmap(path
);
861 background_dialog
= 0;
866 background_dialog
= 0;
871 generic_buf
[generic_ptr
] = 0;
877 if(generic_ptr
< 255){
878 generic_buf
[generic_ptr
] = c
;
880 generic_buf
[generic_ptr
] = 0;
886 int tile_panel_click(int mx
, int my
){
889 pixel_to_tile(mx
, my
, &x
, &y
);
910 if(y
>= 0 && y
< 14){
912 brush_tile
= x
+ y
*8 + tile_panel_offset
;
921 void tile_panel_press(SDLKey key
, Uint16 c
){
934 void tools_press(SDLKey key
, Uint16 c
){
938 void tools_click(int mx
, int my
){
942 pixel_to_tile(mx
, my
, &x
, &y
);
950 if(x
>= 4 && x
<= 10){
954 brush_tile
= fg_favorites
[x
-4];
965 if(x
>= 4 && x
<= 10){
969 brush_tile
= bg_favorites
[x
-4];
975 if(x
>= 2 && x
<= 16){
978 brush_tile
= shapechars
[x
-2];
983 if(x
== 2) printf("big eraser\n");
984 if(x
== 4) printf("eye dropper\n");
991 void open_press(SDLKey key
, Uint16 c
){
995 if(open_buf
[0] == 0){
996 console_printf("No name? Nevermind then.");
999 if(raw_open(open_buf
) < 0){
1000 console_printf("ERROR when opening %s", open_buf
);
1003 console_printf("%s opened", open_buf
);
1004 update_window_name();
1019 open_buf
[open_ptr
] = 0;
1024 open_buf
[open_ptr
] = c
;
1026 open_buf
[open_ptr
] = 0;
1032 void confirm_save_press(SDLKey key
, Uint16 c
){
1033 if(c
== 'y' || c
== 'Y'){
1034 console_printf("You're the boss. Overwriting %s", my_file
);
1036 update_window_name();
1039 strcpy(my_file
, my_file_old
); /* ! */
1040 console_printf("Operation cancelled");
1043 confirm_save_dialog
= 0;
1046 void save_as_press(SDLKey key
, Uint16 c
){
1051 if(save_as_buf
[0] == 0){
1052 console_printf("No name? Nevermind then.");
1055 strcpy(my_file_old
, my_file
); /* ! */
1056 strcpy(my_file
, save_as_buf
); /* ! */
1058 /* see if file exists */
1059 path
= compute_stage_path(save_as_buf
);
1060 if(file_exists(path
)){
1061 console_printf("ALERT: really overwrite %s? (Y/N)", my_file
);
1062 confirm_save_dialog
= 1;
1065 update_window_name();
1079 if(save_as_ptr
> 0){
1081 save_as_buf
[save_as_ptr
] = 0;
1085 if(save_as_ptr
< 255){
1086 save_as_buf
[save_as_ptr
] = c
;
1088 save_as_buf
[save_as_ptr
] = 0;
1093 void quit_press(SDLKey key
, Uint16 c
){
1094 if(c
== 'y' || c
== 'Y'){
1098 console_printf("OK");
1108 void keydown(SDLKey key
, SDLMod mod
, Uint16 c
){
1111 save_as_press(key
, c
);
1116 if(confirm_save_dialog
){
1117 confirm_save_press(key
, c
);
1135 tools_press(key
, c
);
1141 tile_panel_press(key
, c
);
1146 tileset_press(key
, c
);
1151 if(background_dialog
){
1152 background_press(key
, c
);
1166 console_printf("undo"); break;
1169 console_printf("redo"); break;
1171 toggle_background
= !toggle_background
;
1172 console_printf("background %s", onoff(toggle_background
));
1175 toggle_bgtiles
= !toggle_bgtiles
;
1176 console_printf("bg tiles %s", onoff(toggle_bgtiles
));
1179 toggle_fgtiles
= !toggle_fgtiles
;
1180 console_printf("fg tiles %s", onoff(toggle_fgtiles
));
1183 toggle_shapes
= !toggle_shapes
;
1184 console_printf("shapes %s", onoff(toggle_shapes
));
1187 if(mod
& (KMOD_LCTRL
|KMOD_RCTRL
)){
1188 if(my_file
[0] == 0){
1206 console_printf("name: %s", my_file
);
1207 console_printf("zone: %s", zone_path
);
1208 console_printf("size: %d x %d", raw_w
, raw_h
);
1209 console_printf("background: %s", bgimage_file
);
1210 console_printf("bg tileset: %s", bgtiles_file
);
1211 console_printf("fg tileset: %s", fgtiles_file
);
1215 console_printf("Really quit? (Y/N)");
1224 console_printf("arrow keys - move");
1225 console_printf("left mouse - draw");
1226 console_printf("right mouse - erase");
1227 console_printf("space - open toolbox");
1228 console_printf("ctrl+s - save");
1229 console_printf("w - save as");
1230 console_printf("o - open");
1231 console_printf("n - new file");
1232 console_printf("z - change zone");
1233 console_printf("1 2 3 4 - toggle layers");
1234 console_printf("i - file info");
1235 console_printf("F1 h ? - this help");
1236 console_printf("ESCAPE q - quit / cancel");
1237 console_printf("F5 - select background");
1238 console_printf("F6 - select bg tileset");
1239 console_printf("F7 - select fg tileset");
1240 console_printf("e - choose eyedropper");
1241 console_printf("x - choose eraser");
1244 background_dialog
= 1;
1254 case SDLK_LEFT
: camera_x
--; break;
1255 case SDLK_RIGHT
: camera_x
++; break;
1256 case SDLK_UP
: camera_y
--; break;
1257 case SDLK_DOWN
: camera_y
++; break;
1263 /* temporary controls */
1264 case SDLK_9
: brush_tile
--; brush_tile
%= 256; break;
1265 case SDLK_0
: brush_tile
++; brush_tile
%= 256; break;
1266 case SDLK_8
: brush_layer
= 2; break;
1267 case SDLK_7
: brush_layer
= 1; break;
1282 B - change background
1291 F2 - change fg tileset
1292 F3 - change bg tileset
1297 void translate_pointer(int mx
, int my
, int *x
, int *y
){
1299 map_pixel(mx
, my
, &a
, &b
);
1300 *x
= a
/16 + camera_x
+ origin_x
;
1301 *y
= b
/16 + camera_y
+ origin_y
;
1305 void mousedown(int mx
, int my
, int button
){
1307 hold LMB - draw single tiles / deselect
1308 shift LMB - start box select
1309 ctrl LMB - append single tiles to selection
1310 RMB - display tilesets
1311 hold MMB - choose where to paste (release to execute, esc to cancel)
1313 SDLMod mod
= SDL_GetModState();
1316 translate_pointer(mx
, my
, &x
, &y
);
1319 tools_click(mx
, my
);
1324 if(tile_panel_click(mx
, my
)){
1331 raw_write(x
, y
, brush_layer
, brush_tile
);
1335 else if(button
== 3){
1337 if(brush_layer
== 3){
1338 raw_write(x
, y
, 3, '0');
1341 raw_write(x
, y
, brush_layer
, 0);
1348 void mouseup(int x
, int y
, int button
){
1351 shift LMB - append box to selection
1365 void mousemove(int mx
, int my
, int xrel
, int yrel
){
1372 translate_pointer(mx
, my
, &x
, &y
);
1375 raw_write(x
, y
, brush_layer
, brush_tile
);
1379 if(brush_layer
== 3){
1380 raw_write(x
, y
, 3, '0');
1383 raw_write(x
, y
, brush_layer
, 0);
1392 if(SDL_WaitEvent(&e
) == 0){
1393 printf("SDL_WaitEvent encountered an error (%s)\n", SDL_GetError());
1398 case SDL_QUIT
: return 1;
1399 case SDL_KEYDOWN
: keydown(e
.key
.keysym
.sym
, e
.key
.keysym
.mod
, e
.key
.keysym
.unicode
); return 0;
1400 case SDL_MOUSEMOTION
:
1401 mousemove(e
.motion
.x
, e
.motion
.y
, e
.motion
.xrel
, e
.motion
.yrel
);
1403 case SDL_MOUSEBUTTONDOWN
: mousedown(e
.button
.x
, e
.button
.y
, e
.button
.button
); return 0;
1404 case SDL_MOUSEBUTTONUP
: mouseup(e
.button
.x
, e
.button
.y
, e
.button
.button
); return 0;
1416 int main(int argc
, char* argv
[]){
1417 video_init(argc
, argv
);
1421 raw_tiles
= initialize_raw(raw_w
, raw_h
);
1423 update_window_name();
1425 shapes
= load_bitmap("gfx/shapes.tga");
1426 tools
= load_bitmap("gfx/tools.tga");
1428 loader_data_mode(0);
1429 // bgimage = load_bitmap("azone/gfx/background.tga");
1430 // loader_data_mode(0);
1431 // fgtiles = load_bitmap("barf.tga");
1432 // loader_data_mode(1);
1433 // fgtiles = load_bitmap("azone/gfx/barf.tga");
1434 // bgtiles = load_bitmap("azone/gfx/test.tga");
1436 set_zone_path("azone");
1441 SDL_EnableUNICODE(1);
1442 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY
, SDL_DEFAULT_REPEAT_INTERVAL
);
1446 while(check_events() == 0 && panic_flag
== 0);