Stop the analysis pass in Loopy's redraw routine from being
[sgt/puzzles] / nestedvm.c
CommitLineData
2c930807 1/*
2 * nestedvm.c: NestedVM front end for my puzzle collection.
3 */
4
5#include <stdio.h>
6#include <assert.h>
7#include <stdlib.h>
8#include <time.h>
9#include <stdarg.h>
10#include <string.h>
11#include <errno.h>
12
13#include <sys/time.h>
14
15#include "puzzles.h"
16
17extern void _pause();
18extern int _call_java(int cmd, int arg1, int arg2, int arg3);
19
20void fatal(char *fmt, ...)
21{
22 va_list ap;
23 fprintf(stderr, "fatal error: ");
24 va_start(ap, fmt);
25 vfprintf(stderr, fmt, ap);
26 va_end(ap);
27 fprintf(stderr, "\n");
28 exit(1);
29}
30
31struct frontend {
32 // TODO kill unneeded members!
33 midend *me;
34 int timer_active;
35 struct timeval last_time;
36 config_item *cfg;
37 int cfg_which, cfgret;
047f95bc 38 int ox, oy, w, h;
2c930807 39};
40
41static frontend *_fe;
42
43void get_random_seed(void **randseed, int *randseedsize)
44{
45 struct timeval *tvp = snew(struct timeval);
46 gettimeofday(tvp, NULL);
47 *randseed = (void *)tvp;
48 *randseedsize = sizeof(struct timeval);
49}
50
51void frontend_default_colour(frontend *fe, float *output)
52{
53 output[0] = output[1]= output[2] = 0.8f;
54}
55
56void nestedvm_status_bar(void *handle, char *text)
57{
58 _call_java(4,0,(int)text,0);
59}
60
61void nestedvm_start_draw(void *handle)
62{
63 frontend *fe = (frontend *)handle;
047f95bc 64 _call_java(5, 0, fe->w, fe->h);
2c930807 65 _call_java(4, 1, fe->ox, fe->oy);
66}
67
68void nestedvm_clip(void *handle, int x, int y, int w, int h)
69{
70 frontend *fe = (frontend *)handle;
71 _call_java(5, w, h, 0);
72 _call_java(4, 3, x + fe->ox, y + fe->oy);
73}
74
75void nestedvm_unclip(void *handle)
76{
77 frontend *fe = (frontend *)handle;
78 _call_java(4, 4, fe->ox, fe->oy);
79}
80
81void nestedvm_draw_text(void *handle, int x, int y, int fonttype, int fontsize,
82 int align, int colour, char *text)
83{
84 frontend *fe = (frontend *)handle;
85 _call_java(5, x + fe->ox, y + fe->oy,
86 (fonttype == FONT_FIXED ? 0x10 : 0x0) | align);
87 _call_java(7, fontsize, colour, (int)text);
88}
89
90void nestedvm_draw_rect(void *handle, int x, int y, int w, int h, int colour)
91{
92 frontend *fe = (frontend *)handle;
93 _call_java(5, w, h, colour);
94 _call_java(4, 5, x + fe->ox, y + fe->oy);
95}
96
97void nestedvm_draw_line(void *handle, int x1, int y1, int x2, int y2,
98 int colour)
99{
100 frontend *fe = (frontend *)handle;
101 _call_java(5, x2 + fe->ox, y2 + fe->oy, colour);
102 _call_java(4, 6, x1 + fe->ox, y1 + fe->oy);
103}
104
105void nestedvm_draw_poly(void *handle, int *coords, int npoints,
106 int fillcolour, int outlinecolour)
107{
108 frontend *fe = (frontend *)handle;
109 int i;
110 _call_java(4, 7, npoints, 0);
111 for (i = 0; i < npoints; i++) {
112 _call_java(6, i, coords[i*2] + fe->ox, coords[i*2+1] + fe->oy);
113 }
114 _call_java(4, 8, outlinecolour, fillcolour);
115}
116
117void nestedvm_draw_circle(void *handle, int cx, int cy, int radius,
118 int fillcolour, int outlinecolour)
119{
120 frontend *fe = (frontend *)handle;
121 _call_java(5, cx+fe->ox, cy+fe->oy, radius);
122 _call_java(4, 9, outlinecolour, fillcolour);
123}
124
125struct blitter {
126 int handle, w, h, x, y;
127};
128
129blitter *nestedvm_blitter_new(void *handle, int w, int h)
130{
131 blitter *bl = snew(blitter);
132 bl->handle = -1;
133 bl->w = w;
134 bl->h = h;
135 return bl;
136}
137
138void nestedvm_blitter_free(void *handle, blitter *bl)
139{
140 if (bl->handle != -1)
141 _call_java(4, 11, bl->handle, 0);
142 sfree(bl);
143}
144
145void nestedvm_blitter_save(void *handle, blitter *bl, int x, int y)
146{
147 frontend *fe = (frontend *)handle;
148 if (bl->handle == -1)
149 bl->handle = _call_java(4,10,bl->w, bl->h);
150 bl->x = x;
151 bl->y = y;
152 _call_java(8, bl->handle, x + fe->ox, y + fe->oy);
153}
154
155void nestedvm_blitter_load(void *handle, blitter *bl, int x, int y)
156{
157 frontend *fe = (frontend *)handle;
158 assert(bl->handle != -1);
159 if (x == BLITTER_FROMSAVED && y == BLITTER_FROMSAVED) {
160 x = bl->x;
161 y = bl->y;
162 }
163 _call_java(9, bl->handle, x + fe->ox, y + fe->oy);
164}
165
166void nestedvm_end_draw(void *handle)
167{
168 _call_java(4,2,0,0);
169}
170
4011952c 171char *nestedvm_text_fallback(void *handle, const char *const *strings,
172 int nstrings)
173{
174 /*
175 * We assume Java can cope with any UTF-8 likely to be emitted
176 * by a puzzle.
177 */
178 return dupstr(strings[0]);
179}
180
2c930807 181const struct drawing_api nestedvm_drawing = {
182 nestedvm_draw_text,
183 nestedvm_draw_rect,
184 nestedvm_draw_line,
185 nestedvm_draw_poly,
186 nestedvm_draw_circle,
187 NULL, // draw_update,
188 nestedvm_clip,
189 nestedvm_unclip,
190 nestedvm_start_draw,
191 nestedvm_end_draw,
192 nestedvm_status_bar,
193 nestedvm_blitter_new,
194 nestedvm_blitter_free,
195 nestedvm_blitter_save,
196 nestedvm_blitter_load,
197 NULL, NULL, NULL, NULL, NULL, NULL, /* {begin,end}_{doc,page,puzzle} */
e91f8f26 198 NULL, NULL, /* line_width, line_dotted */
4011952c 199 nestedvm_text_fallback,
2c930807 200};
201
202int jcallback_key_event(int x, int y, int keyval)
203{
204 frontend *fe = (frontend *)_fe;
205 if (fe->ox == -1)
206 return 1;
207 if (keyval >= 0 &&
208 !midend_process_key(fe->me, x - fe->ox, y - fe->oy, keyval))
209 return 42;
210 return 1;
211}
212
213int jcallback_resize(int width, int height)
214{
215 frontend *fe = (frontend *)_fe;
216 int x, y;
217 x = width;
218 y = height;
219 midend_size(fe->me, &x, &y, TRUE);
220 fe->ox = (width - x) / 2;
221 fe->oy = (height - y) / 2;
047f95bc 222 fe->w = x;
223 fe->h = y;
2c930807 224 midend_force_redraw(fe->me);
225 return 0;
226}
227
228int jcallback_timer_func()
229{
230 frontend *fe = (frontend *)_fe;
231 if (fe->timer_active) {
232 struct timeval now;
233 float elapsed;
234 gettimeofday(&now, NULL);
235 elapsed = ((now.tv_usec - fe->last_time.tv_usec) * 0.000001F +
236 (now.tv_sec - fe->last_time.tv_sec));
237 midend_timer(fe->me, elapsed); /* may clear timer_active */
238 fe->last_time = now;
239 }
240 return fe->timer_active;
241}
242
243void deactivate_timer(frontend *fe)
244{
245 if (fe->timer_active)
246 _call_java(4, 13, 0, 0);
247 fe->timer_active = FALSE;
248}
249
250void activate_timer(frontend *fe)
251{
252 if (!fe->timer_active) {
253 _call_java(4, 12, 0, 0);
254 gettimeofday(&fe->last_time, NULL);
255 }
256 fe->timer_active = TRUE;
257}
258
259void jcallback_config_ok()
260{
261 frontend *fe = (frontend *)_fe;
262 char *err;
263
264 err = midend_set_config(fe->me, fe->cfg_which, fe->cfg);
265
266 if (err)
267 _call_java(2, (int) "Error", (int)err, 1);
268 else {
269 fe->cfgret = TRUE;
270 }
271}
272
273void jcallback_config_set_string(int item_ptr, int char_ptr) {
274 config_item *i = (config_item *)item_ptr;
275 char* newval = (char*) char_ptr;
276 sfree(i->sval);
277 i->sval = dupstr(newval);
278 free(newval);
279}
280
281void jcallback_config_set_boolean(int item_ptr, int selected) {
282 config_item *i = (config_item *)item_ptr;
283 i->ival = selected != 0 ? TRUE : FALSE;
284}
285
286void jcallback_config_set_choice(int item_ptr, int selected) {
287 config_item *i = (config_item *)item_ptr;
288 i->ival = selected;
289}
290
291static int get_config(frontend *fe, int which)
292{
293 char *title;
294 config_item *i;
295 fe->cfg = midend_get_config(fe->me, which, &title);
296 fe->cfg_which = which;
297 fe->cfgret = FALSE;
298 _call_java(10, (int)title, 0, 0);
299 for (i = fe->cfg; i->type != C_END; i++) {
300 _call_java(5, (int)i, i->type, (int)i->name);
301 _call_java(11, (int)i->sval, i->ival, 0);
302 }
303 _call_java(12,0,0,0);
304 free_cfg(fe->cfg);
305 return fe->cfgret;
306}
307
308int jcallback_menu_key_event(int key)
309{
310 frontend *fe = (frontend *)_fe;
311 if (!midend_process_key(fe->me, 0, 0, key))
312 return 42;
313 return 0;
314}
315
316static void resize_fe(frontend *fe)
317{
318 int x, y;
319
320 x = INT_MAX;
321 y = INT_MAX;
322 midend_size(fe->me, &x, &y, FALSE);
323 _call_java(3, x, y, 0);
324}
325
326int jcallback_preset_event(int ptr_game_params)
327{
328 frontend *fe = (frontend *)_fe;
329 game_params *params =
330 (game_params *)ptr_game_params;
331
332 midend_set_params(fe->me, params);
333 midend_new_game(fe->me);
334 resize_fe(fe);
335 _call_java(13, midend_which_preset(fe->me), 0, 0);
336 return 0;
337}
338
339int jcallback_solve_event()
340{
341 frontend *fe = (frontend *)_fe;
342 char *msg;
343
344 msg = midend_solve(fe->me);
345
346 if (msg)
347 _call_java(2, (int) "Error", (int)msg, 1);
348 return 0;
349}
350
351int jcallback_restart_event()
352{
353 frontend *fe = (frontend *)_fe;
354
355 midend_restart_game(fe->me);
356 return 0;
357}
358
359int jcallback_config_event(int which)
360{
361 frontend *fe = (frontend *)_fe;
362 _call_java(13, midend_which_preset(fe->me), 0, 0);
363 if (!get_config(fe, which))
364 return 0;
365 midend_new_game(fe->me);
366 resize_fe(fe);
367 _call_java(13, midend_which_preset(fe->me), 0, 0);
368 return 0;
369}
370
371int jcallback_about_event()
372{
373 char titlebuf[256];
374 char textbuf[1024];
375
376 sprintf(titlebuf, "About %.200s", thegame.name);
377 sprintf(textbuf,
378 "%.200s\n\n"
379 "from Simon Tatham's Portable Puzzle Collection\n\n"
380 "%.500s", thegame.name, ver);
381 _call_java(2, (int)&titlebuf, (int)&textbuf, 0);
382 return 0;
383}
384
385int main(int argc, char **argv)
386{
387 int i, n;
388 float* colours;
389
390 _fe = snew(frontend);
391 _fe->timer_active = FALSE;
392 _fe->me = midend_new(_fe, &thegame, &nestedvm_drawing, _fe);
cbbe322f 393 if (argc > 1)
394 midend_game_id(_fe->me, argv[1]); /* ignore failure */
2c930807 395 midend_new_game(_fe->me);
396
397 if ((n = midend_num_presets(_fe->me)) > 0) {
398 int i;
399 for (i = 0; i < n; i++) {
400 char *name;
401 game_params *params;
402 midend_fetch_preset(_fe->me, i, &name, &params);
403 _call_java(1, (int)name, (int)params, 0);
404 }
405 }
406
407 colours = midend_colours(_fe->me, &n);
408 _fe->ox = -1;
409
410 _call_java(0, (int)thegame.name,
411 (thegame.can_configure ? 1 : 0) |
412 (midend_wants_statusbar(_fe->me) ? 2 : 0) |
413 (thegame.can_solve ? 4 : 0), n);
414 for (i = 0; i < n; i++) {
415 _call_java(1024+ i,
416 (int)(colours[i*3] * 0xFF),
417 (int)(colours[i*3+1] * 0xFF),
418 (int)(colours[i*3+2] * 0xFF));
419 }
420 resize_fe(_fe);
421
422 _call_java(13, midend_which_preset(_fe->me), 0, 0);
423
424 // Now pause the vm. The VM will be call()ed when
425 // an input event occurs.
426 _pause();
427
428 // shut down when the VM is resumed.
429 deactivate_timer(_fe);
430 midend_free(_fe->me);
431 return 0;
432}