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};
83 int eyedrop_enable
= 0;
89 int background_dialog
= 0;
90 int tileset_dialog
= 0;
92 int save_as_dialog
= 0;
94 int confirm_save_dialog
= 0;
101 int tile_panel_set
= 0;
102 int tile_panel_page
= 0;
103 int tile_panel_offset
= 0;
105 char save_as_buf
[256] = "";
107 char open_buf
[256] = "";
109 char generic_buf
[256] = "";
112 char gfx_path_buf
[256] = "";
113 char stage_path_buf
[256] = "";
119 void update_window_name(){
121 SDL_WM_SetCaption("unnamed", NULL
);
124 SDL_WM_SetCaption(my_file
, NULL
);
129 void select_bgfile(char* path
){
130 strcpy(bgimage_file
, path
);
133 void set_zone_path(char* path
){
134 strncpy(zone_path
, path
, 256);
136 if(zone_path
[strlen(zone_path
)-1] != '/'){
137 strncat(zone_path
, "/", 256);
142 int file_exists(char* path
){
143 FILE* f
= fopen(path
, "r");
153 char* compute_stage_path(char* stage
){
154 strcpy(stage_path_buf
, zone_path
);
155 strcat(stage_path_buf
, "stages/");
156 strcat(stage_path_buf
, stage
);
157 return stage_path_buf
;
160 char* compute_gfx_path(char* gfxfile
){
161 strcpy(gfx_path_buf
, zone_path
);
162 strcat(gfx_path_buf
, "gfx/");
163 strcat(gfx_path_buf
, gfxfile
);
171 /* base access methods */
172 struct tile
* initialize_raw(int w
, int h
){
175 struct tile blank
= {'0', 0, 0};
176 struct tile
* ptr
= malloc(w
*h
*sizeof(struct tile
));
179 *(ptr
+ i
+ j
*w
) = blank
;
192 raw_tiles
= initialize_raw(20, 15);
203 update_window_name();
206 struct tile
raw_read(int x
, int y
){
207 struct tile blank
= {'0', 0, 0};
208 if(x
< 0 || y
< 0 || x
>= raw_w
|| y
>= raw_h
){
212 return *(raw_tiles
+ x
+ raw_w
*y
);
217 int new_w
= raw_w
* 3;
218 int new_h
= raw_h
* 3;
219 struct tile
* new_tiles
= initialize_raw(new_w
, new_h
);
225 for(j
=raw_h
; j
<2*raw_h
; j
++){
226 for(i
=raw_w
; i
<2*raw_w
; i
++){
227 ptr
= new_tiles
+ i
+ j
*(3*raw_w
);
228 t
= raw_read(i
-raw_w
, j
-raw_h
);
238 raw_tiles
= new_tiles
;
241 int out_of_bounds(int x
, int y
){
242 if(x
< 0 || y
< 0 || x
>= raw_w
|| y
>= raw_h
)
248 void detect_size(int* w
, int* h
){
249 //see the minimum size necessary for the area
253 void raw_write(int x
, int y
, int layer
, int value
){
254 while(out_of_bounds(x
, y
)){
261 //shift x y by expand shift
262 //shift x and y by origin
264 struct tile
* ptr
= raw_tiles
+ x
+ raw_w
*y
;
276 void draw_background(){
277 int W
= gfx_width(bgimage
);
278 int H
= gfx_height(bgimage
);
279 draw_gfx_raw(bgimage
, 0, 0, 0, 0, W
, H
);
283 int x0
= camera_x
+ origin_x
;
284 int y0
= camera_y
+ origin_y
;
293 if(toggle_background
)
296 for(j
=0; j
<(15+5); j
++){
298 for(i
=0; i
<(20+8); i
++){
304 draw_gfx_raw(bgtiles
, i
*16, j
*16, gx
, gy
, 16, 16);
308 draw_gfx_raw(fgtiles
, i
*16, j
*16, gx
, gy
, 16, 16);
309 gy
= 16*(t
.shape
/ 16);
310 gx
= 16*(t
.shape
% 16);
312 draw_gfx_raw(shapes
, i
*16, j
*16, gx
, gy
, 16, 16);
318 /* determine an optimal size for the stage */
319 void raw_optimize(int* ox
, int* oy
, int* ow
, int* oh
){
328 for(i
=0; i
<(raw_w
*raw_h
); i
++){
331 fg
= raw_tiles
[i
].fg
;
332 bg
= raw_tiles
[i
].bg
;
333 shape
= raw_tiles
[i
].shape
;
334 if((fg
!= 0 || bg
!= 0 || shape
!= '0')){
335 if(x
> xmax
) xmax
= x
;
336 if(x
< xmin
) xmin
= x
;
337 if(y
> ymax
) ymax
= y
;
338 if(y
< ymin
) ymin
= y
;
342 if(ymax
- ymin
+ 1 <= 15) *oh
= 15;
343 else *oh
= (ymax
- ymin
+ 1);
345 if(xmax
- xmin
+ 1 <= 20) *ow
= 20;
346 else *ow
= (xmax
- xmin
+ 1);
352 int raw_save(char* path
){
353 /* save current stage to a stage file */
354 /* overwrites if already exists, no confirmation */
358 struct tile
* ptr
= raw_tiles
;
360 int opt_x
, opt_y
, opt_w
, opt_h
;
363 FILE* f
= fopen(path
, "w");
365 console_printf("error saving file");
369 raw_optimize(&opt_x
, &opt_y
, &opt_w
, &opt_h
);
371 fprintf(f
, "%d %d %d %d\n", opt_w
, opt_h
, origin_x
-opt_x
, origin_y
-opt_y
);
372 fprintf(f
, "%s\n", bgimage_file
);
373 fprintf(f
, "%s\n", fgtiles_file
);
374 fprintf(f
, "%s\n", bgtiles_file
);
376 for(i
=0; i
<(raw_w
*raw_h
); i
++){
377 x
= (i
% raw_w
) - origin_x
;
378 y
= (i
/ raw_w
) - origin_y
;
381 shape
= ptr
[i
].shape
;
383 if(fg
!= 0 || bg
!= 0 || shape
!= '0'){
384 fprintf(f
, "%d %d %d %d %c\n", x
, y
, fg
, bg
, shape
);
393 void save(char* stagename
){
394 char* path
= compute_stage_path(stagename
);
395 if(raw_save(path
) < 0){
396 console_printf("%s NOT saved", stagename
);
399 console_printf("%s saved", stagename
);
404 int raw_open(char* stagename
){
409 char file1
[256] = "";
410 char file2
[256] = "";
411 char file3
[256] = "";
412 struct tile
* new_tiles
= NULL
;
414 char* path
= compute_stage_path(stagename
);
416 r
= loader_open(path
);
418 console_printf("Can't open %s", path
);
422 if(loader_scanline(r
, "%d %d %d %d", &w
, &h
, &ox
, &oy
) < 4){
423 printf("scan error\n");
429 loader_readline(r
, file1
, 256) ||
430 loader_readline(r
, file2
, 256) ||
431 loader_readline(r
, file3
, 256)
433 printf("scan error\n");
438 new_tiles
= initialize_raw(w
, h
);
439 while(loader_scanline(r
, "%d %d %d %d %c", &x
, &y
, &fg
, &bg
, &shape
) == 5){
440 ptr
= new_tiles
+ (x
+ox
) + (y
+oy
)*w
;
446 /* load the graphics */
447 path
= compute_gfx_path(file1
);
448 if(file1
[0] != 0 && file_exists(path
)) bgimage
= load_bitmap(path
);
451 path
= compute_gfx_path(file2
);
452 if(file2
[0] != 0 && file_exists(path
)) bgtiles
= load_bitmap(path
);
455 path
= compute_gfx_path(file3
);
456 if(file3
[0] != 0 && file_exists(path
)) fgtiles
= load_bitmap(path
);
465 raw_tiles
= new_tiles
;
467 strcpy(bgimage_file
, file1
);
468 strcpy(bgtiles_file
, file2
);
469 strcpy(fgtiles_file
, file3
);
471 strcpy(my_file
, stagename
);
481 struct undo_step
* undo_stack
;
482 struct undo_step
* undo_ptr
;
484 /* undo operations */
486 //do the undo_ptr->undo operations
487 //move undo_ptr down one
491 //if at top of stack, do nothing
493 //do the undo_ptr->redo operations
494 //move undo_ptr up one
497 void undo_record(struct edit
* edits
){
498 //eliminate undo_ptr->redo and all previous edit structs
499 //change the undo_stack
501 //store the edits in undo_ptr->redo
502 //calculate the undo operation XXX
503 //push a new edit struct
505 //store the undo operation in undo_ptr->undo
512 /* medium level editting commands */
513 void write_one_tile(int x
, int y
, int layer
, int value
){
514 //write x y layer value
517 void write_many_tiles(struct edit
* edits
){
522 void edit_one_tile(int x
, int y
, int layer
, int value
){
524 //create a tile struct
528 void edit_many_tiles(struct edit
* edits
){
533 void add_to_clipboard(struct edit
* edits
){
534 //makes a tile struct and appends to clipboard
537 void clear_clipboard(){
538 //clear the clipboard
541 struct tile
* read_tile(int x
, int y
){
548 /* high level gui commands */
556 int value
= brush_tile
;
557 int layer
= brush_layer
;
559 if(layer
== 1) favs
= bg_favorites
;
560 if(layer
== 2) favs
= fg_favorites
;
563 if(favs
[i
] == value
){
583 void start_box(int x
, int y
){
587 void move_box(int x
, int y
){
599 void append_to_box(int x
, int y
){
603 struct tile
* box_select(){
608 void move_paste(int x
, int y
){
633 void draw_tile_panel(){
639 draw_black_rect(0,0,9*16,20*16);
640 draw_gfx_raw(tools
, 0, 14*16, 4*16, 0, 16, 16);
641 draw_gfx_raw(tools
, 16, 14*16, 5*16, 0, 16, 16);
642 draw_gfx_raw(tools
, 2*16, 14*16, 6*16, 0, 16, 16);
643 draw_gfx_raw(tools
, 7*16, 14*16, 7*16, 0, 16, 16);
645 if(tile_panel_page
== 0) tile_panel_offset
= 0;
646 if(tile_panel_page
== 1) tile_panel_offset
= 112;
647 if(tile_panel_page
== 2) tile_panel_offset
= 144;
649 if(tile_panel_set
== 0) gfx
= fgtiles
;
650 if(tile_panel_set
== 1) gfx
= bgtiles
;
652 for(i
=0; i
<112; i
++){
658 draw_gfx_raw(gfx
, x
, y
, gx
, gy
+tile_panel_offset
, 16, 16);
666 draw_black_rect(16, 16, 17*16, 11*16);
668 /* fg tile tool and favorites */
669 draw_gfx_raw(tools
, 2*16, 2*16, 0, 0, 16, 16);
672 gx
= 16*(fg_favorites
[i
] % 16);
673 gy
= 16*(fg_favorites
[i
] / 16);
674 draw_gfx_raw(fgtiles
, 16*(i
+4), 2*16, gx
, gy
, 16, 16);
677 /* bg tile tool and favorites */
678 draw_gfx_raw(tools
, 2*16, 4*16, 16, 0, 16, 16);
681 gx
= 16*(bg_favorites
[i
] % 16);
682 gy
= 16*(bg_favorites
[i
] / 16);
683 draw_gfx_raw(bgtiles
, 16*(i
+4), 4*16, gx
, gy
, 16, 16);
688 gx
= 16*(shapechars
[i
] % 16);
689 gy
= 16*(shapechars
[i
] / 16);
690 draw_gfx_raw(shapes
, 16*(i
+2), 6*16, gx
, gy
, 16, 16);
693 draw_gfx_raw(tools
, 2*16, 8*16, 2*16, 0, 16, 16);
694 draw_gfx_raw(tools
, 4*16, 8*16, 3*16, 0, 16, 16);
710 console_printf("save as: %s", save_as_buf
);
714 console_printf("open file: %s", open_buf
);
726 if(brush_layer
== 1){
727 console_printf("bg tileset: %s", generic_buf
);
729 else if(brush_layer
== 2){
730 console_printf("fg tileset: %s", generic_buf
);
734 if(background_dialog
){
735 console_printf("background image: %s", generic_buf
);
739 console_printf("path to zone: %s", generic_buf
);
753 /* dialog input handlers */
754 void pixel_to_tile(int mx
, int my
, int* x
, int* y
){
755 map_pixel(mx
, my
, x
, y
);
760 void zone_press(SDLKey key
, Uint16 c
){
762 if(generic_buf
[0] == 0){
763 console_printf("No name? Nevermind then.");
766 set_zone_path(generic_buf
);
767 console_printf("zone set to %s", zone_path
);
781 generic_buf
[generic_ptr
] = 0;
787 if(generic_ptr
< 255){
788 generic_buf
[generic_ptr
] = c
;
790 generic_buf
[generic_ptr
] = 0;
796 void tileset_press(SDLKey key
, Uint16 c
){
798 if(generic_buf
[0] == 0){
799 console_printf("No name? Nevermind then.");
802 char* path
= compute_gfx_path(generic_buf
);
803 int gfx
= load_bitmap(path
);
805 console_printf("file not found");
808 if(brush_layer
== 1){
809 strcpy(bgtiles_file
, generic_buf
);
810 bgtiles
= load_bitmap(path
);
812 else if(brush_layer
== 2){
813 strcpy(fgtiles_file
, generic_buf
);
814 fgtiles
= load_bitmap(path
);
830 generic_buf
[generic_ptr
] = 0;
836 if(generic_ptr
< 255){
837 generic_buf
[generic_ptr
] = c
;
839 generic_buf
[generic_ptr
] = 0;
844 void background_press(SDLKey key
, Uint16 c
){
846 if(generic_buf
[0] == 0){
847 console_printf("No name? Nevermind then.");
850 char* path
= compute_gfx_path(generic_buf
);
851 int gfx
= load_bitmap(path
);
853 console_printf("file not found");
856 strcpy(bgimage_file
, generic_buf
);
857 bgimage
= load_bitmap(path
);
862 background_dialog
= 0;
867 background_dialog
= 0;
872 generic_buf
[generic_ptr
] = 0;
878 if(generic_ptr
< 255){
879 generic_buf
[generic_ptr
] = c
;
881 generic_buf
[generic_ptr
] = 0;
887 int tile_panel_click(int mx
, int my
){
890 pixel_to_tile(mx
, my
, &x
, &y
);
911 if(y
>= 0 && y
< 14){
913 brush_tile
= x
+ y
*8 + tile_panel_offset
;
922 void tile_panel_press(SDLKey key
, Uint16 c
){
935 void tools_press(SDLKey key
, Uint16 c
){
939 void tools_click(int mx
, int my
){
943 pixel_to_tile(mx
, my
, &x
, &y
);
951 if(x
>= 4 && x
<= 10){
955 brush_tile
= fg_favorites
[x
-4];
966 if(x
>= 4 && x
<= 10){
970 brush_tile
= bg_favorites
[x
-4];
976 if(x
>= 2 && x
<= 16){
979 brush_tile
= shapechars
[x
-2];
985 printf("big eraser\n");
989 console_printf("eyedropper\n");
997 void open_press(SDLKey key
, Uint16 c
){
1001 if(open_buf
[0] == 0){
1002 console_printf("No name? Nevermind then.");
1005 if(raw_open(open_buf
) < 0){
1006 console_printf("ERROR when opening %s", open_buf
);
1009 console_printf("%s opened", open_buf
);
1010 update_window_name();
1025 open_buf
[open_ptr
] = 0;
1030 open_buf
[open_ptr
] = c
;
1032 open_buf
[open_ptr
] = 0;
1038 void confirm_save_press(SDLKey key
, Uint16 c
){
1039 if(c
== 'y' || c
== 'Y'){
1040 console_printf("You're the boss. Overwriting %s", my_file
);
1042 update_window_name();
1045 strcpy(my_file
, my_file_old
); /* ! */
1046 console_printf("Operation cancelled");
1049 confirm_save_dialog
= 0;
1052 void save_as_press(SDLKey key
, Uint16 c
){
1057 if(save_as_buf
[0] == 0){
1058 console_printf("No name? Nevermind then.");
1061 strcpy(my_file_old
, my_file
); /* ! */
1062 strcpy(my_file
, save_as_buf
); /* ! */
1064 /* see if file exists */
1065 path
= compute_stage_path(save_as_buf
);
1066 if(file_exists(path
)){
1067 console_printf("ALERT: really overwrite %s? (Y/N)", my_file
);
1068 confirm_save_dialog
= 1;
1071 update_window_name();
1085 if(save_as_ptr
> 0){
1087 save_as_buf
[save_as_ptr
] = 0;
1091 if(save_as_ptr
< 255){
1092 save_as_buf
[save_as_ptr
] = c
;
1094 save_as_buf
[save_as_ptr
] = 0;
1099 void quit_press(SDLKey key
, Uint16 c
){
1100 if(c
== 'y' || c
== 'Y'){
1104 console_printf("OK");
1114 void keydown(SDLKey key
, SDLMod mod
, Uint16 c
){
1117 save_as_press(key
, c
);
1122 if(confirm_save_dialog
){
1123 confirm_save_press(key
, c
);
1141 tools_press(key
, c
);
1147 tile_panel_press(key
, c
);
1152 tileset_press(key
, c
);
1157 if(background_dialog
){
1158 background_press(key
, c
);
1172 console_printf("undo"); break;
1175 console_printf("redo"); break;
1177 toggle_background
= !toggle_background
;
1178 console_printf("background %s", onoff(toggle_background
));
1181 toggle_bgtiles
= !toggle_bgtiles
;
1182 console_printf("bg tiles %s", onoff(toggle_bgtiles
));
1185 toggle_fgtiles
= !toggle_fgtiles
;
1186 console_printf("fg tiles %s", onoff(toggle_fgtiles
));
1189 toggle_shapes
= !toggle_shapes
;
1190 console_printf("shapes %s", onoff(toggle_shapes
));
1193 if(mod
& (KMOD_LCTRL
|KMOD_RCTRL
)){
1194 if(my_file
[0] == 0){
1213 console_printf("eyedropper");
1216 console_printf("name: %s", my_file
);
1217 console_printf("zone: %s", zone_path
);
1218 console_printf("size: %d x %d", raw_w
, raw_h
);
1219 console_printf("background: %s", bgimage_file
);
1220 console_printf("bg tileset: %s", bgtiles_file
);
1221 console_printf("fg tileset: %s", fgtiles_file
);
1225 console_printf("Really quit? (Y/N)");
1234 console_printf("arrow keys - move");
1235 console_printf("left mouse - draw");
1236 console_printf("right mouse - erase");
1237 console_printf("space - open toolbox");
1238 console_printf("ctrl+s - save");
1239 console_printf("w - save as");
1240 console_printf("o - open");
1241 console_printf("n - new file");
1242 console_printf("z - change zone");
1243 console_printf("1 2 3 4 - toggle layers");
1244 console_printf("i - file info");
1245 console_printf("F1 h ? - this help");
1246 console_printf("ESCAPE q - quit / cancel");
1247 console_printf("F5 - select background");
1248 console_printf("F6 - select bg tileset");
1249 console_printf("F7 - select fg tileset");
1250 console_printf("e - choose eyedropper");
1251 console_printf("x - choose eraser");
1254 background_dialog
= 1;
1264 case SDLK_LEFT
: camera_x
--; break;
1265 case SDLK_RIGHT
: camera_x
++; break;
1266 case SDLK_UP
: camera_y
--; break;
1267 case SDLK_DOWN
: camera_y
++; break;
1273 /* temporary controls */
1274 case SDLK_9
: brush_tile
--; brush_tile
%= 256; break;
1275 case SDLK_0
: brush_tile
++; brush_tile
%= 256; break;
1276 case SDLK_8
: brush_layer
= 2; break;
1277 case SDLK_7
: brush_layer
= 1; break;
1292 B - change background
1301 F2 - change fg tileset
1302 F3 - change bg tileset
1307 void translate_pointer(int mx
, int my
, int *x
, int *y
){
1309 map_pixel(mx
, my
, &a
, &b
);
1310 *x
= a
/16 + camera_x
+ origin_x
;
1311 *y
= b
/16 + camera_y
+ origin_y
;
1315 void mousedown(int mx
, int my
, int button
){
1317 hold LMB - draw single tiles / deselect
1318 shift LMB - start box select
1319 ctrl LMB - append single tiles to selection
1320 RMB - display tilesets
1321 hold MMB - choose where to paste (release to execute, esc to cancel)
1323 SDLMod mod
= SDL_GetModState();
1327 translate_pointer(mx
, my
, &x
, &y
);
1330 tools_click(mx
, my
);
1335 if(tile_panel_click(mx
, my
)){
1344 if(brush_layer
== 1){
1347 else if(brush_layer
== 2){
1350 else if(brush_layer
== 3){
1351 brush_tile
= t
.shape
;
1356 raw_write(x
, y
, brush_layer
, brush_tile
);
1361 else if(button
== 3){
1363 if(brush_layer
== 3){
1364 raw_write(x
, y
, 3, '0');
1367 raw_write(x
, y
, brush_layer
, 0);
1374 void mouseup(int x
, int y
, int button
){
1377 shift LMB - append box to selection
1391 void mousemove(int mx
, int my
, int xrel
, int yrel
){
1398 translate_pointer(mx
, my
, &x
, &y
);
1401 raw_write(x
, y
, brush_layer
, brush_tile
);
1405 if(brush_layer
== 3){
1406 raw_write(x
, y
, 3, '0');
1409 raw_write(x
, y
, brush_layer
, 0);
1418 if(SDL_WaitEvent(&e
) == 0){
1419 printf("SDL_WaitEvent encountered an error (%s)\n", SDL_GetError());
1424 case SDL_QUIT
: return 1;
1425 case SDL_KEYDOWN
: keydown(e
.key
.keysym
.sym
, e
.key
.keysym
.mod
, e
.key
.keysym
.unicode
); return 0;
1426 case SDL_MOUSEMOTION
:
1427 mousemove(e
.motion
.x
, e
.motion
.y
, e
.motion
.xrel
, e
.motion
.yrel
);
1429 case SDL_MOUSEBUTTONDOWN
: mousedown(e
.button
.x
, e
.button
.y
, e
.button
.button
); return 0;
1430 case SDL_MOUSEBUTTONUP
: mouseup(e
.button
.x
, e
.button
.y
, e
.button
.button
); return 0;
1431 case SDL_VIDEOEXPOSE
: redraw_all();
1443 int main(int argc
, char* argv
[]){
1444 video_init(argc
, argv
);
1448 raw_tiles
= initialize_raw(raw_w
, raw_h
);
1450 update_window_name();
1452 shapes
= load_bitmap("gfx/shapes.tga");
1453 tools
= load_bitmap("gfx/tools.tga");
1455 loader_data_mode(0);
1456 // bgimage = load_bitmap("azone/gfx/background.tga");
1457 // loader_data_mode(0);
1458 // fgtiles = load_bitmap("barf.tga");
1459 // loader_data_mode(1);
1460 // fgtiles = load_bitmap("azone/gfx/barf.tga");
1461 // bgtiles = load_bitmap("azone/gfx/test.tga");
1463 set_zone_path("azone");
1468 SDL_EnableUNICODE(1);
1469 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY
, SDL_DEFAULT_REPEAT_INTERVAL
);
1473 while(check_events() == 0 && panic_flag
== 0);