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