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