"new level" action
[vrlugburz] / tools / dunger / src / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <GL/glut.h>
5 #include <utk/cubertk.h>
6 #include <drawtext.h>
7 #include "level.h"
8 #include "lview.h"
9
10 static int init(void);
11 static void cleanup(void);
12 static void display(void);
13 static void reshape(int x, int y);
14 static void keyb(unsigned char key, int x, int y);
15 static void keyup(unsigned char key, int x, int y);
16 static void mouse(int bn, int st, int x, int y);
17 static void motion(int x, int y);
18
19 static void cb_new(utk_event *ev, void *data);
20 static void cb_open(utk_event *ev, void *data);
21 static void cb_save(utk_event *ev, void *data);
22
23 static void cb_cancel(utk_event *ev, void *data);
24 static void cb_new_ok(utk_event *ev, void *data);
25
26 static int parse_args(int argc, char **argv);
27
28
29 static void ucolor(int r, int g, int b, int a);
30 static void uclip(int x1, int y1, int x2, int y2);
31 static void uimage(int x, int y, const void *pix, int xsz, int ysz);
32 static void urect(int x1, int y1, int x2, int y2);
33 static void uline(int x1, int y1, int x2, int y2, int width);
34 static void utext(int x, int y, const char *txt, int sz);
35 static int utextspacing(void);
36 static int utextwidth(const char *txt, int sz);
37
38
39 int win_width, win_height;
40 int view_width, view_height;
41 float view_panx, view_pany, view_zoom = 1.0f;
42
43 static int bnstate[8];
44 int mousex, mousey, clickx, clicky;
45
46 static float uiscale = 1.0f;
47 #define UISPLIT 150
48 int splitx;
49
50 #define FONTSZ  16
51 static struct dtx_font *uifont;
52 static utk_widget *uiroot, *uiwin_new;
53 static utk_widget *uigrab;
54 static utk_widget *cbox_newsz;
55
56 static struct level *lvl;
57
58
59 int main(int argc, char **argv)
60 {
61         glutInit(&argc, argv);
62
63         if(parse_args(argc, argv) == -1) {
64                 return 1;
65         }
66
67         glutInitWindowSize(1280, 800);
68         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_MULTISAMPLE);
69         glutCreateWindow("dunger");
70
71         win_width = glutGet(GLUT_WINDOW_WIDTH);
72         win_height = glutGet(GLUT_WINDOW_HEIGHT);
73
74         glutDisplayFunc(display);
75         glutReshapeFunc(reshape);
76         glutKeyboardFunc(keyb);
77         glutKeyboardUpFunc(keyup);
78         glutMouseFunc(mouse);
79         glutMotionFunc(motion);
80         glutPassiveMotionFunc(motion);
81
82         if(init() == -1) {
83                 return 1;
84         }
85         atexit(cleanup);
86
87         glutMainLoop();
88         return 0;
89 }
90
91
92 static int init(void)
93 {
94         int pad;
95         utk_widget *win, *hbox, *vbox;
96
97         glEnable(GL_MULTISAMPLE);
98
99         glClearColor(0.15, 0.15, 0.15, 1);
100
101         if(!(uifont = dtx_open_font("uifont.ttf", 0))) {
102                 fprintf(stderr, "failed to open uifont.ttf\n");
103                 return -1;
104         }
105         dtx_prepare_range(uifont, FONTSZ, ' ', 'z');
106         dtx_use_font(uifont, FONTSZ);
107
108         if(!(uiroot = utk_init(win_width / uiscale, win_height / uiscale))) {
109                 fprintf(stderr, "failed to initialized ubertk\n");
110                 return -1;
111         }
112         utk_set_color_func(ucolor);
113         utk_set_clip_func(uclip);
114         utk_set_image_func(uimage);
115         utk_set_rect_func(urect);
116         utk_set_line_func(uline);
117         utk_set_text_func(utext);
118         utk_set_text_spacing_func(utextspacing);
119         utk_set_text_width_func(utextwidth);
120
121         win = utk_vbox(uiroot, 0, UTK_DEF_SPACING);
122         utk_set_pos(win, 15, 15);
123         utk_button(win, "New", 0, 0, cb_new, 0);
124         utk_button(win, "Open ...", 0, 0, cb_open, 0);
125         utk_button(win, "Save ...", 0, 0, cb_save, 0);
126
127         uiwin_new = utk_window(uiroot, (win_width - 220) / 2, (win_height - 150) / 2,
128                         220, 150, "New level");
129         vbox = utk_vbox(uiwin_new, UTK_DEF_PADDING, UTK_DEF_SPACING);
130         {
131                 const char *items[] = {"small (16x16)", "medium (24x24)", "large (32x32)"};
132                 cbox_newsz = utk_combobox_items(vbox, items, sizeof items / sizeof *items, 0, 0);
133                 utk_select(cbox_newsz, 2);
134         }
135         hbox = utk_hbox(vbox, UTK_DEF_PADDING, UTK_DEF_SPACING);
136         utk_button(hbox, "OK", 0, 0, cb_new_ok, 0);
137         utk_button(hbox, "Cancel", 0, 0, cb_cancel, uiwin_new);
138         pad = utk_get_padding(uiwin_new);
139         utk_set_size(uiwin_new, utk_get_width(vbox) + pad * 2.0f, utk_get_height(vbox) + pad * 2.0f);
140
141
142         if(!(lvl = create_level(32, 32))) {
143                 fprintf(stderr, "failed to create level\n");
144                 return -1;
145         }
146         if(init_lview(lvl) == -1) {
147                 return -1;
148         }
149
150         splitx = UISPLIT * uiscale;
151         view_width = win_width - splitx;
152         view_height = win_height;
153
154         return 0;
155 }
156
157 static void cleanup(void)
158 {
159         destroy_lview();
160         free_level(lvl);
161         dtx_close_font(uifont);
162         utk_close(uiroot);
163 }
164
165 static void display(void)
166 {
167         glClear(GL_COLOR_BUFFER_BIT);
168
169         glMatrixMode(GL_MODELVIEW);
170         glLoadIdentity();
171
172         /* draw view */
173
174         glMatrixMode(GL_PROJECTION);
175         glLoadIdentity();
176         glOrtho(0, view_width, 0, view_height, -1, 1);
177         glViewport(splitx, 0, view_width, view_height);
178
179         glBegin(GL_QUADS);
180         glColor3f(0.1, 0.1, 0.1);
181         glVertex2f(0, 0);
182         glVertex2f(view_width, 0);
183         glVertex2f(view_width, view_height);
184         glVertex2f(0, view_height);
185         glEnd();
186
187         draw_lview();
188
189         /* draw UI */
190
191         glMatrixMode(GL_PROJECTION);
192         glLoadIdentity();
193         glOrtho(0, win_width, win_height, 0, -1, 1);
194         glViewport(0, 0, win_width, win_height);
195
196         glBegin(GL_QUADS);
197         glColor3f(0.25, 0.25, 0.25);
198         glVertex2f(0, 0);
199         glVertex2f(splitx, 0);
200         glVertex2f(splitx, win_height);
201         glVertex2f(0, win_height);
202         glEnd();
203         utk_draw(uiroot);
204
205
206         glutSwapBuffers();
207 }
208
209 static void reshape(int x, int y)
210 {
211         win_width = x;
212         win_height = y;
213
214         if(uiroot) {
215                 utk_set_size(uiroot, x / uiscale, y / uiscale);
216         }
217
218         lview_viewport(splitx, 0, x - splitx, y);
219 }
220
221 static void keyb(unsigned char key, int x, int y)
222 {
223         switch(key) {
224         case 27:
225                 if(uigrab) {
226                         utk_hide(uigrab);
227                         uigrab = 0;
228                 } else {
229                         exit(0);
230                 }
231                 return;
232
233         default:
234                 break;
235         }
236
237         utk_keyboard_event(key, 1);
238         glutPostRedisplay();
239 }
240
241 static void keyup(unsigned char key, int x, int y)
242 {
243         utk_keyboard_event(key, 0);
244         glutPostRedisplay();
245 }
246
247 static void mouse(int bn, int st, int x, int y)
248 {
249         int bidx = bn - GLUT_LEFT_BUTTON;
250         int press = st == GLUT_DOWN;
251
252         bnstate[bidx] = press;
253         mousex = x;
254         mousey = y;
255
256         if(bn <= 2) {
257                 if(press) {
258                         clickx = x;
259                         clicky = y;
260                 } else {
261                         clickx = clicky = -1;
262                 }
263         } else if(bn == 3) {
264                 if(press) zoom_lview(0.1);
265         } else if(bn == 4) {
266                 if(press) zoom_lview(-0.1);
267         }
268
269         if(!uigrab) {
270                 lview_mbutton(bidx, press, x, y);
271         }
272
273         utk_mbutton_event(bidx, press, x / uiscale, y / uiscale);
274         glutPostRedisplay();
275 }
276
277 static void motion(int x, int y)
278 {
279         int dx, dy;
280         dx = x - mousex;
281         dy = y - mousey;
282         mousex = x;
283         mousey = y;
284
285         if(clickx >= splitx) {
286                 if(bnstate[1]) {
287                         pan_lview(-dx, dy);
288                 }
289         }
290
291         if(!uigrab) {
292                 lview_mouse(x, y);
293         }
294
295         utk_mmotion_event(x / uiscale, y / uiscale);
296         glutPostRedisplay();
297 }
298
299 static void cb_new(utk_event *ev, void *data)
300 {
301         utk_show(uiwin_new);
302         uigrab = uiwin_new;
303 }
304
305 static void cb_new_ok(utk_event *ev, void *data)
306 {
307         static int levsz[] = {16, 24, 32};
308         int sz;
309         struct level *newlvl;
310
311         sz = levsz[utk_get_selected(cbox_newsz)];
312
313         if(!(newlvl = create_level(sz, sz))) {
314                 fprintf(stderr, "failed to create new %dx%d level\n", sz, sz);
315                 /* TODO: messagebox */
316                 return;
317         }
318
319         free_level(lvl);
320         destroy_lview();
321
322         lvl = newlvl;
323         init_lview(newlvl);
324
325         utk_hide(uiwin_new);
326         uigrab = 0;
327 }
328
329 static void cb_open(utk_event *ev, void *data)
330 {
331 }
332
333 static void cb_save(utk_event *ev, void *data)
334 {
335 }
336
337 static void cb_cancel(utk_event *ev, void *data)
338 {
339         utk_hide(data);
340         uigrab = 0;
341 }
342
343 static int parse_args(int argc, char **argv)
344 {
345         int i;
346
347         for(i=1; i<argc; i++) {
348                 if(argv[i][0] == '-') {
349                         if(strcmp(argv[i], "-uiscale") == 0) {
350                                 if(!argv[++i] || !(uiscale = atoi(argv[i]))) {
351                                         fprintf(stderr, "-uiscale should be followed by a positive number\n");
352                                         return -1;
353                                 }
354                         } else if(strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "-h") == 0) {
355                                 printf("Usage: %s [options]\n", argv[0]);
356                                 printf("Options:\n");
357                                 printf(" -uiscale <scale>: UI scale factor (default: 1)\n");
358                                 printf(" -h,-help: print usage and exit\n");
359                                 exit(0);
360                         } else {
361                                 fprintf(stderr, "unknown option: %s\n", argv[i]);
362                                 return -1;
363                         }
364                 } else {
365                         fprintf(stderr, "unexpected argument: %s\n", argv[i]);
366                         return -1;
367                 }
368         }
369         return 0;
370 }
371
372 /* --- ubertk callbacks --- */
373
374 static void ucolor(int r, int g, int b, int a)
375 {
376         glColor4ub(r, g, b, a);
377 }
378
379 static void uclip(int x1, int y1, int x2, int y2)
380 {
381         if(!(x1 | y1 | x2 | y2)) {
382                 glDisable(GL_SCISSOR_TEST);
383         } else {
384                 glEnable(GL_SCISSOR_TEST);
385         }
386
387         x1 *= uiscale;
388         y1 *= uiscale;
389         x2 *= uiscale;
390         y2 *= uiscale;
391
392         glScissor(x1, win_height - y2, x2 - x1, y2 - y1);
393 }
394
395 static void uimage(int x, int y, const void *pix, int xsz, int ysz)
396 {
397         glPixelZoom(1, -1);
398         glRasterPos2f(x * uiscale, y * uiscale);
399         glDrawPixels(xsz, ysz, GL_BGRA, GL_UNSIGNED_BYTE, pix);
400 }
401
402 static void urect(int x1, int y1, int x2, int y2)
403 {
404         glRectf(x1 * uiscale, y1 * uiscale, x2 * uiscale, y2 * uiscale);
405 }
406
407 static void uline(int x1, int y1, int x2, int y2, int width)
408 {
409         glLineWidth(width);
410         glBegin(GL_LINES);
411         glVertex2f(x1 * uiscale, y1 * uiscale);
412         glVertex2f(x2 * uiscale, y2 * uiscale);
413         glEnd();
414 }
415
416 static void utext(int x, int y, const char *txt, int sz)
417 {
418         glMatrixMode(GL_PROJECTION);
419         glPushMatrix();
420         glTranslatef(x * uiscale, (y - dtx_baseline()) * uiscale, 0);
421         glScalef(uiscale, -uiscale, 1);
422
423         dtx_string(txt);
424         dtx_flush();
425
426         glPopMatrix();
427 }
428
429 static int utextspacing(void)
430 {
431         return dtx_line_height();
432 }
433
434 static int utextwidth(const char *txt, int sz)
435 {
436         return dtx_string_width(txt);
437 }