diff options
Diffstat (limited to 'apps/plugins/puzzles/nestedvm.c')
-rw-r--r-- | apps/plugins/puzzles/nestedvm.c | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/apps/plugins/puzzles/nestedvm.c b/apps/plugins/puzzles/nestedvm.c new file mode 100644 index 0000000000..c61afecf6a --- /dev/null +++ b/apps/plugins/puzzles/nestedvm.c | |||
@@ -0,0 +1,432 @@ | |||
1 | /* | ||
2 | * nestedvm.c: NestedVM front end for my puzzle collection. | ||
3 | */ | ||
4 | |||
5 | #include <stdio.h> | ||
6 | #include "rbassert.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 | |||
17 | extern void _pause(); | ||
18 | extern int _call_java(int cmd, int arg1, int arg2, int arg3); | ||
19 | |||
20 | void 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 | |||
31 | struct 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, w, h; | ||
39 | }; | ||
40 | |||
41 | static frontend *_fe; | ||
42 | |||
43 | void 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 | |||
51 | void frontend_default_colour(frontend *fe, float *output) | ||
52 | { | ||
53 | output[0] = output[1]= output[2] = 0.8f; | ||
54 | } | ||
55 | |||
56 | void nestedvm_status_bar(void *handle, char *text) | ||
57 | { | ||
58 | _call_java(4,0,(int)text,0); | ||
59 | } | ||
60 | |||
61 | void nestedvm_start_draw(void *handle) | ||
62 | { | ||
63 | frontend *fe = (frontend *)handle; | ||
64 | _call_java(5, 0, fe->w, fe->h); | ||
65 | _call_java(4, 1, fe->ox, fe->oy); | ||
66 | } | ||
67 | |||
68 | void 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 | |||
75 | void nestedvm_unclip(void *handle) | ||
76 | { | ||
77 | frontend *fe = (frontend *)handle; | ||
78 | _call_java(4, 4, fe->ox, fe->oy); | ||
79 | } | ||
80 | |||
81 | void 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 | |||
90 | void 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 | |||
97 | void 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 | |||
105 | void 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 | |||
117 | void 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 | |||
125 | struct blitter { | ||
126 | int handle, w, h, x, y; | ||
127 | }; | ||
128 | |||
129 | blitter *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 | |||
138 | void 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 | |||
145 | void 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 | |||
155 | void 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 | |||
166 | void nestedvm_end_draw(void *handle) | ||
167 | { | ||
168 | _call_java(4,2,0,0); | ||
169 | } | ||
170 | |||
171 | char *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 | |||
181 | const 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} */ | ||
198 | NULL, NULL, /* line_width, line_dotted */ | ||
199 | nestedvm_text_fallback, | ||
200 | }; | ||
201 | |||
202 | int 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 | |||
213 | int 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; | ||
222 | fe->w = x; | ||
223 | fe->h = y; | ||
224 | midend_force_redraw(fe->me); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | int 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 | |||
243 | void deactivate_timer(frontend *fe) | ||
244 | { | ||
245 | if (fe->timer_active) | ||
246 | _call_java(4, 13, 0, 0); | ||
247 | fe->timer_active = FALSE; | ||
248 | } | ||
249 | |||
250 | void 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 | |||
259 | void 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 | |||
273 | void 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 | |||
281 | void 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 | |||
286 | void jcallback_config_set_choice(int item_ptr, int selected) { | ||
287 | config_item *i = (config_item *)item_ptr; | ||
288 | i->ival = selected; | ||
289 | } | ||
290 | |||
291 | static 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 | |||
308 | int 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 | |||
316 | static 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 | |||
326 | int 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 | |||
339 | int 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 | |||
351 | int jcallback_restart_event() | ||
352 | { | ||
353 | frontend *fe = (frontend *)_fe; | ||
354 | |||
355 | midend_restart_game(fe->me); | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | int 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 | |||
371 | int 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 | |||
385 | int 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); | ||
393 | if (argc > 1) | ||
394 | midend_game_id(_fe->me, argv[1]); /* ignore failure */ | ||
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, ¶ms); | ||
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 | } | ||