more fixes to msx font
[k8-protractor.git] / src / sdltest.c
blob0f32d6938e621a84be99c39d0f78d617d1188bd7
1 /* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar)
2 * Understanding is not required. Only obedience.
4 * This program is free software. It comes without any warranty, to
5 * the extent permitted by applicable law. You can redistribute it
6 * and/or modify it under the terms of the Do What The Fuck You Want
7 * To Public License, Version 2, as published by Sam Hocevar. See
8 * http://www.wtfpl.net/txt/copying/ for more details.
9 */
10 #include <math.h>
11 #include <stdlib.h>
12 #include <stdio.h>
14 #include "SDL.h"
16 #include "videolib/videolib.h"
17 #include "gestureng/gestureng.h"
20 #define FPS (30)
23 static gengesture_t stk;
24 static gengtemplate_t stkpat;
25 static int stkpat_inited = 0;
26 static genglib_t stklib;
27 static char *message = NULL;
28 static SDL_TimerID tid_msghide = 0;
29 static SDL_TimerID tid_frame = 0;
30 static int frame_changed = 0;
33 ////////////////////////////////////////////////////////////////////////////////
34 enum {
35 EVT_SHOW_FRAME = 1,
36 EVT_MESSAGE_RESET
40 ////////////////////////////////////////////////////////////////////////////////
41 static void draw_stroke (const gengesture_t *stk) {
42 if (stk->count > 1) {
43 Uint32 col = rgb2col(255, 255, 0);
44 for (int f = 1; f < stk->count-1; ++f) {
45 int x0 = geng_ptx(stk, f-1);
46 int y0 = geng_pty(stk, f-1);
47 int x1 = geng_ptx(stk, f);
48 int y1 = geng_pty(stk, f);
49 draw_line(x0, y0, x1, y1, col);
55 static void draw_template (const gengtemplate_t stk) {
56 for (int f = 1; f < GENG_PTS_PER_STK; ++f) {
57 int g = 255*f/(GENG_PTS_PER_STK-1), b = 255-(255*f/(GENG_PTS_PER_STK-1));
58 Uint32 col = rgb2col(0, g, b);
59 double x0 = stk[(f-1)*2+0];
60 double y0 = stk[(f-1)*2+1];
61 double x1 = stk[f*2+0];
62 double y1 = stk[f*2+1];
63 x0 = x0*200+400;
64 y0 = y0*200+300;
65 x1 = x1*200+400;
66 y1 = y1*200+300;
67 draw_line(x0, y0, x1, y1, col);
72 ////////////////////////////////////////////////////////////////////////////////
73 static int stklist_curptr = -1;
74 static char **stknames = NULL;
75 static int stknames_count = 0;
76 static int stknames_maxlen = 0;
77 static const char *curstkname = NULL;
80 static void stroke_list_clear (void) {
81 for (int f = stknames_count-1; f >= 0; --f) free(stknames[f]);
82 free(stknames);
83 stklist_curptr = -1;
84 stknames = NULL;
85 stknames_count = 0;
86 stknames_maxlen = 0;
90 static void stroke_list_rebuild (void) {
91 int cmp (const void *ps0, const void *ps1) {
92 const char **s0 = (const char **)ps0;
93 const char **s1 = (const char **)ps1;
94 return strcmp(*s0, *s1);
97 stroke_list_clear();
98 for (int f = 0; f < stklib.count; ++f) {
99 int found = 0;
100 for (int c = 0; c < stknames_count && !found; ++c) if (strcmp(stklib.names[f], stknames[c]) == 0) found = 1;
101 if (!found) {
102 stknames = realloc(stknames, sizeof(stknames[0])*(stknames_count+1));
103 stknames[stknames_count++] = strdup(stklib.names[f]);
104 //fprintf(stderr, "[%s]\n", stknames[stknames_count-1]);
105 if (strlen(stklib.names[f]) > stknames_maxlen) stknames_maxlen = strlen(stklib.names[f]);
108 qsort(stknames, stknames_count, sizeof(stknames[0]), cmp);
109 stknames_maxlen = stknames_maxlen*12+8;
113 static int stroke_list_curptr (int x, int y) {
114 if (x >= 4 && y >= 4 && x < stknames_maxlen-8 && y < stknames_count*16+4) return (y-4)/16;
115 return -1;
119 static void draw_stroke_list (int curptr) {
120 if (stknames_count > 0) {
121 fill_rect(0, 0, stknames_maxlen, stknames_count*16+8, rgb2col(0, 0, 127));
123 for (int f = 0; f < stknames_count; ++f) {
124 Uint32 col, bkcol;
125 if (curstkname != NULL && strcmp(stknames[f], curstkname) == 0) {
126 col = rgb2col(255, 255, 255);
127 bkcol = rgb2col(0, 0, 255);
128 } else {
129 col = rgb2col(255, 127, 0);
130 bkcol = rgb2col(0, 0, 127);
132 if (curptr == f) bkcol = rgb2col(0, 127, 0);
133 fill_rect(0, f*16+4, stknames_maxlen, 16, bkcol);
134 draw_str6(4, f*16+4, stknames[f], col, TRANSPARENT_COLOR);
136 if (stknames_count > 0) {
137 draw_rect(0, 0, stknames_maxlen, stknames_count*16+8, rgb2col(255, 255, 255));
138 draw_rect(1, 1, stknames_maxlen-2, stknames_count*16+6, rgb2col(0, 0, 0));
143 ////////////////////////////////////////////////////////////////////////////////
144 static int show_help = 0;
145 static const char *help_text[] = {
146 "\x1fProtractor demo actions",
147 "\x1f-----------------------",
148 "\3keyboard:\1",
149 " \2F1\1: toggle help",
150 " \2F2\1: save library to '\4strokes.dat\1'",
151 " \2F3\1: replace library with '\4strokes.dat\1'",
152 " \2F8\1: clear library",
153 " \2F10\1: quit",
154 " \2DEL\1: delete selected stroke",
156 "\3mouse:\1",
157 " \2LMB\1: select name or start drawing",
158 " \2RMB\1: register current stroke as template for selected name",
159 " \2MMB\1: register current stroke as template for new name",
163 static int stlen (const char *str) {
164 int len = 0;
165 for (; *str; ++str) if ((unsigned char)(str[0]) >= 32) ++len;
166 return len;
170 static void stdraw (int x, int y, const char *str) {
171 Uint32 fg = rgb2col(255, 255, 255);
172 if (str[0] == '\x1f') {
173 x = (SCR_WIDTH-stlen(str)*12)/2;
174 ++str;
176 for (; *str; ++str) {
177 unsigned char ch = (unsigned char)(str[0]);
178 if (ch < 32) {
179 switch (ch) {
180 case 1: fg = rgb2col(255, 255, 255); break;
181 case 2: fg = rgb2col(0, 255, 0); break;
182 case 3: fg = rgb2col(255, 255, 0); break;
183 case 4: fg = rgb2col(255, 127, 0); break;
185 } else {
186 draw_char8(x, y, ch, fg, TRANSPARENT_COLOR);
187 x += 12;
193 static void toggle_help (void) {
194 show_help = !show_help;
198 static void draw_help (void) {
199 if (show_help) {
200 int x, y;
201 int wdt = 0, hgt = sizeof(help_text)/sizeof(help_text[0])*16+8;
202 Uint32 fg = rgb2col(255, 255, 255);
203 Uint32 bg = rgb2col(25, 69, 247);
204 for (size_t f = 0; f < sizeof(help_text)/sizeof(help_text[0]); ++f) {
205 int l = stlen(help_text[f]);
206 if (l > wdt) wdt = l;
208 wdt = wdt*12+8;
209 x = (SCR_WIDTH-wdt)/2;
210 y = (SCR_HEIGHT-hgt)/2;
211 fill_rect(x, y, wdt, hgt, fg);
212 fill_rect(x+1, y+1, wdt-2, hgt-2, rgb2col(0, 0, 0));
213 fill_rect(x+2, y+2, wdt-4, hgt-4, bg);
214 x += 4;
215 y += 4;
216 for (size_t f = 0; f < sizeof(help_text)/sizeof(help_text[0]); ++f, y += 16) stdraw(x, y, help_text[f]);
221 ////////////////////////////////////////////////////////////////////////////////
222 static void rebuild_screen (void) {
223 fill_rect(0, 0, SCR_WIDTH, SCR_HEIGHT, rgb2col(0, 0, 0));
224 draw_stroke(&stk);
225 if (stkpat_inited) draw_template(stkpat);
226 draw_stroke_list(stklist_curptr);
227 if (message != NULL) {
228 int w = strlen(message)*16;
229 int h = 16;
230 int x = (SCR_WIDTH-w)/2;
231 int y = SCR_HEIGHT-h-2;
232 Uint32 fg = rgb2col(255, 255, 255);
233 Uint32 bg = rgb2col(25, 69, 247);
234 Uint32 blk = rgb2col(0, 0, 0);
235 fill_rect(x-2, y-2, w+4, h+4, fg);
236 fill_rect(x-1, y-1, w+2, h+2, blk);
237 draw_str8(x, y, message, fg, bg);
239 draw_help();
240 frame_changed = 1;
244 ////////////////////////////////////////////////////////////////////////////////
245 static Uint32 timer_frame (Uint32 interval, void *param) {
246 SDL_Event evt;
247 evt.user.type = SDL_USEREVENT;
248 evt.user.code = EVT_SHOW_FRAME;
249 SDL_PushEvent(&evt);
250 return interval;
254 static Uint32 timer_msghide (Uint32 interval, void *param) {
255 SDL_Event evt;
256 evt.user.type = SDL_USEREVENT;
257 evt.user.code = EVT_MESSAGE_RESET;
258 SDL_PushEvent(&evt);
259 tid_msghide = 0; /* cancelled */
260 return 0;
264 static void show_message (const char *msg) {
265 if (tid_msghide != 0) SDL_RemoveTimer(tid_msghide);
266 if (message != NULL) free(message);
267 if (msg && msg[0]) message = strdup(msg); else message = NULL;
268 tid_msghide = SDL_AddTimer(5000, timer_msghide, NULL);
269 rebuild_screen();
273 static void hide_message (void) {
274 if (message != NULL) {
275 free(message);
276 message = NULL;
277 if (tid_msghide != 0) SDL_RemoveTimer(tid_msghide);
278 tid_msghide = 0;
279 rebuild_screen();
284 ////////////////////////////////////////////////////////////////////////////////
285 static void main_loop (void) {
286 SDL_Event event;
287 if (genglib_load_file(&stklib, "strokes.dat") == 0) {
288 stroke_list_rebuild();
289 show_message("'strokes.dat' loaded...");
291 rebuild_screen();
292 paint_screen();
293 while (SDL_WaitEvent(&event)) {
294 switch (event.type) {
295 case SDL_QUIT: return;
296 case SDL_MOUSEMOTION:
297 if (SDL_GetWindowGrab(sdl_win)) {
298 if ((event.motion.state&SDL_BUTTON(1)) != 0) {
299 if (stklist_curptr == -1) {
300 geng_add_point(&stk, event.motion.x, event.motion.y);
301 rebuild_screen();
304 } else if (event.motion.state == 0) {
305 int np = stroke_list_curptr(event.motion.x, event.motion.y);
306 if (np != stklist_curptr) {
307 stklist_curptr = np;
308 rebuild_screen();
311 break;
312 case SDL_MOUSEBUTTONDOWN:
313 if (show_help) {
314 toggle_help();
315 } else {
316 if (event.button.button == SDL_BUTTON_LEFT) {
317 if (stklist_curptr == -1) {
318 geng_clear(&stk);
319 SDL_SetWindowGrab(sdl_win, SDL_TRUE);
320 geng_add_point(&stk, event.button.x, event.button.y);
321 rebuild_screen();
322 } else {
323 stkpat_inited = 0;
324 curstkname = NULL;
325 for (int f = 0; f < stklib.count; ++f) {
326 if (strcmp(stklib.names[f], stknames[stklist_curptr]) == 0) {
327 geng_copytpl(stkpat, stklib.tpls[f]);
328 curstkname = stklib.names[f];
329 stkpat_inited = 1;
330 break;
334 } else if (event.button.button == SDL_BUTTON_RIGHT || event.button.button == SDL_BUTTON_MIDDLE) {
335 if (stk.count > 1) {
336 const char *nm = (event.button.button == SDL_BUTTON_MIDDLE ? NULL : curstkname);
337 geng_normalize(stkpat, &stk);
338 stkpat_inited = 1;
339 if (nm == NULL) {
340 hide_message();
341 if ((nm = read_str()) == READSTR_QUIT) return;
343 if (nm != NULL) {
344 genglib_add_stk(&stklib, nm, &stk);
345 stroke_list_rebuild();
346 stklist_curptr = stroke_list_curptr(event.button.x, event.button.y);
347 geng_clear(&stk);
352 rebuild_screen();
353 break;
354 case SDL_MOUSEBUTTONUP:
355 if (event.button.button == SDL_BUTTON_LEFT) {
356 if (SDL_GetWindowGrab(sdl_win)) {
357 SDL_SetWindowGrab(sdl_win, SDL_FALSE);
358 if (stk.count > 1) {
359 double score;
360 char buf[128];
361 curstkname = genglib_find_match(&stklib, &stk, &score);
362 if (curstkname != NULL && score < 2.0) curstkname = NULL;
363 if (curstkname != NULL) {
364 snprintf(buf, sizeof(buf), "%s: score=%.15g", curstkname, score);
365 } else {
366 snprintf(buf, sizeof(buf), "can't recognize stroke");
368 show_message(buf);
372 rebuild_screen();
373 break;
374 case SDL_KEYDOWN:
375 switch (event.key.keysym.sym) {
376 case SDLK_ESCAPE:
377 if (show_help) {
378 toggle_help();
379 rebuild_screen();
381 break;
382 case SDLK_F1:
383 if (!SDL_GetWindowGrab(sdl_win)) {
384 toggle_help();
385 rebuild_screen();
387 break;
388 case SDLK_F2:
389 if (genglib_save_file(&stklib, "strokes.dat") == 0) show_message("'strokes.dat' saved...");
390 break;
391 case SDLK_F3:
392 curstkname = NULL;
393 if (genglib_load_file(&stklib, "strokes.dat") == 0) show_message("'strokes.dat' loaded...");
394 stroke_list_rebuild();
395 rebuild_screen();
396 break;
397 case SDLK_F8:
398 curstkname = NULL;
399 genglib_clear(&stklib);
400 stroke_list_rebuild();
401 show_message("library cleared...");
402 break;
403 case SDLK_r: case SDLK_DELETE: case SDLK_KP_PERIOD:
404 if (stklist_curptr >= 0) {
405 genglib_remove(&stklib, stknames[stklist_curptr]);
406 curstkname = NULL;
407 stroke_list_rebuild();
408 rebuild_screen();
410 break;
411 case SDLK_F10: return;
412 default: ;
414 break;
415 case SDL_USEREVENT:
416 switch (event.user.code) {
417 case EVT_SHOW_FRAME:
418 if (frame_changed) {
419 frame_changed = 0;
420 paint_screen();
422 break;
423 case EVT_MESSAGE_RESET:
424 hide_message();
425 break;
427 break;
428 case SDL_WINDOWEVENT:
429 switch (event.window.event) {
430 case SDL_WINDOWEVENT_EXPOSED:
431 frame_changed = 0;
432 paint_screen();
433 break;
435 break;
436 default: ;
442 int main (int argc, char *argv[]) {
443 if (video_init()) return 1;
444 genglib_init(&stklib);
445 geng_init(&stk);
446 tid_frame = SDL_AddTimer(1000/FPS, timer_frame, NULL);
447 main_loop();
448 SDL_RemoveTimer(tid_frame);
449 SDL_SetWindowGrab(sdl_win, SDL_FALSE);
450 geng_done(&stk);
451 genglib_done(&stklib);
452 stroke_list_clear();
453 if (message != NULL) free(message);
454 return 0;