summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/nestedvm.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--apps/plugins/puzzles/nestedvm.c432
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 0000000..c61afec
--- /dev/null
+++ b/apps/plugins/puzzles/nestedvm.c
@@ -0,0 +1,432 @@
+/*
+ * nestedvm.c: NestedVM front end for my puzzle collection.
+ */
+
+#include <stdio.h>
+#include "rbassert.h"
+#include <stdlib.h>
+#include <time.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/time.h>
+
+#include "puzzles.h"
+
+extern void _pause();
+extern int _call_java(int cmd, int arg1, int arg2, int arg3);
+
+void fatal(char *fmt, ...)
+{
+ va_list ap;
+ fprintf(stderr, "fatal error: ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+struct frontend {
+ // TODO kill unneeded members!
+ midend *me;
+ int timer_active;
+ struct timeval last_time;
+ config_item *cfg;
+ int cfg_which, cfgret;
+ int ox, oy, w, h;
+};
+
+static frontend *_fe;
+
+void get_random_seed(void **randseed, int *randseedsize)
+{
+ struct timeval *tvp = snew(struct timeval);
+ gettimeofday(tvp, NULL);
+ *randseed = (void *)tvp;
+ *randseedsize = sizeof(struct timeval);
+}
+
+void frontend_default_colour(frontend *fe, float *output)
+{
+ output[0] = output[1]= output[2] = 0.8f;
+}
+
+void nestedvm_status_bar(void *handle, char *text)
+{
+ _call_java(4,0,(int)text,0);
+}
+
+void nestedvm_start_draw(void *handle)
+{
+ frontend *fe = (frontend *)handle;
+ _call_java(5, 0, fe->w, fe->h);
+ _call_java(4, 1, fe->ox, fe->oy);
+}
+
+void nestedvm_clip(void *handle, int x, int y, int w, int h)
+{
+ frontend *fe = (frontend *)handle;
+ _call_java(5, w, h, 0);
+ _call_java(4, 3, x + fe->ox, y + fe->oy);
+}
+
+void nestedvm_unclip(void *handle)
+{
+ frontend *fe = (frontend *)handle;
+ _call_java(4, 4, fe->ox, fe->oy);
+}
+
+void nestedvm_draw_text(void *handle, int x, int y, int fonttype, int fontsize,
+ int align, int colour, char *text)
+{
+ frontend *fe = (frontend *)handle;
+ _call_java(5, x + fe->ox, y + fe->oy,
+ (fonttype == FONT_FIXED ? 0x10 : 0x0) | align);
+ _call_java(7, fontsize, colour, (int)text);
+}
+
+void nestedvm_draw_rect(void *handle, int x, int y, int w, int h, int colour)
+{
+ frontend *fe = (frontend *)handle;
+ _call_java(5, w, h, colour);
+ _call_java(4, 5, x + fe->ox, y + fe->oy);
+}
+
+void nestedvm_draw_line(void *handle, int x1, int y1, int x2, int y2,
+ int colour)
+{
+ frontend *fe = (frontend *)handle;
+ _call_java(5, x2 + fe->ox, y2 + fe->oy, colour);
+ _call_java(4, 6, x1 + fe->ox, y1 + fe->oy);
+}
+
+void nestedvm_draw_poly(void *handle, int *coords, int npoints,
+ int fillcolour, int outlinecolour)
+{
+ frontend *fe = (frontend *)handle;
+ int i;
+ _call_java(4, 7, npoints, 0);
+ for (i = 0; i < npoints; i++) {
+ _call_java(6, i, coords[i*2] + fe->ox, coords[i*2+1] + fe->oy);
+ }
+ _call_java(4, 8, outlinecolour, fillcolour);
+}
+
+void nestedvm_draw_circle(void *handle, int cx, int cy, int radius,
+ int fillcolour, int outlinecolour)
+{
+ frontend *fe = (frontend *)handle;
+ _call_java(5, cx+fe->ox, cy+fe->oy, radius);
+ _call_java(4, 9, outlinecolour, fillcolour);
+}
+
+struct blitter {
+ int handle, w, h, x, y;
+};
+
+blitter *nestedvm_blitter_new(void *handle, int w, int h)
+{
+ blitter *bl = snew(blitter);
+ bl->handle = -1;
+ bl->w = w;
+ bl->h = h;
+ return bl;
+}
+
+void nestedvm_blitter_free(void *handle, blitter *bl)
+{
+ if (bl->handle != -1)
+ _call_java(4, 11, bl->handle, 0);
+ sfree(bl);
+}
+
+void nestedvm_blitter_save(void *handle, blitter *bl, int x, int y)
+{
+ frontend *fe = (frontend *)handle;
+ if (bl->handle == -1)
+ bl->handle = _call_java(4,10,bl->w, bl->h);
+ bl->x = x;
+ bl->y = y;
+ _call_java(8, bl->handle, x + fe->ox, y + fe->oy);
+}
+
+void nestedvm_blitter_load(void *handle, blitter *bl, int x, int y)
+{
+ frontend *fe = (frontend *)handle;
+ assert(bl->handle != -1);
+ if (x == BLITTER_FROMSAVED && y == BLITTER_FROMSAVED) {
+ x = bl->x;
+ y = bl->y;
+ }
+ _call_java(9, bl->handle, x + fe->ox, y + fe->oy);
+}
+
+void nestedvm_end_draw(void *handle)
+{
+ _call_java(4,2,0,0);
+}
+
+char *nestedvm_text_fallback(void *handle, const char *const *strings,
+ int nstrings)
+{
+ /*
+ * We assume Java can cope with any UTF-8 likely to be emitted
+ * by a puzzle.
+ */
+ return dupstr(strings[0]);
+}
+
+const struct drawing_api nestedvm_drawing = {
+ nestedvm_draw_text,
+ nestedvm_draw_rect,
+ nestedvm_draw_line,
+ nestedvm_draw_poly,
+ nestedvm_draw_circle,
+ NULL, // draw_update,
+ nestedvm_clip,
+ nestedvm_unclip,
+ nestedvm_start_draw,
+ nestedvm_end_draw,
+ nestedvm_status_bar,
+ nestedvm_blitter_new,
+ nestedvm_blitter_free,
+ nestedvm_blitter_save,
+ nestedvm_blitter_load,
+ NULL, NULL, NULL, NULL, NULL, NULL, /* {begin,end}_{doc,page,puzzle} */
+ NULL, NULL, /* line_width, line_dotted */
+ nestedvm_text_fallback,
+};
+
+int jcallback_key_event(int x, int y, int keyval)
+{
+ frontend *fe = (frontend *)_fe;
+ if (fe->ox == -1)
+ return 1;
+ if (keyval >= 0 &&
+ !midend_process_key(fe->me, x - fe->ox, y - fe->oy, keyval))
+ return 42;
+ return 1;
+}
+
+int jcallback_resize(int width, int height)
+{
+ frontend *fe = (frontend *)_fe;
+ int x, y;
+ x = width;
+ y = height;
+ midend_size(fe->me, &x, &y, TRUE);
+ fe->ox = (width - x) / 2;
+ fe->oy = (height - y) / 2;
+ fe->w = x;
+ fe->h = y;
+ midend_force_redraw(fe->me);
+ return 0;
+}
+
+int jcallback_timer_func()
+{
+ frontend *fe = (frontend *)_fe;
+ if (fe->timer_active) {
+ struct timeval now;
+ float elapsed;
+ gettimeofday(&now, NULL);
+ elapsed = ((now.tv_usec - fe->last_time.tv_usec) * 0.000001F +
+ (now.tv_sec - fe->last_time.tv_sec));
+ midend_timer(fe->me, elapsed); /* may clear timer_active */
+ fe->last_time = now;
+ }
+ return fe->timer_active;
+}
+
+void deactivate_timer(frontend *fe)
+{
+ if (fe->timer_active)
+ _call_java(4, 13, 0, 0);
+ fe->timer_active = FALSE;
+}
+
+void activate_timer(frontend *fe)
+{
+ if (!fe->timer_active) {
+ _call_java(4, 12, 0, 0);
+ gettimeofday(&fe->last_time, NULL);
+ }
+ fe->timer_active = TRUE;
+}
+
+void jcallback_config_ok()
+{
+ frontend *fe = (frontend *)_fe;
+ char *err;
+
+ err = midend_set_config(fe->me, fe->cfg_which, fe->cfg);
+
+ if (err)
+ _call_java(2, (int) "Error", (int)err, 1);
+ else {
+ fe->cfgret = TRUE;
+ }
+}
+
+void jcallback_config_set_string(int item_ptr, int char_ptr) {
+ config_item *i = (config_item *)item_ptr;
+ char* newval = (char*) char_ptr;
+ sfree(i->sval);
+ i->sval = dupstr(newval);
+ free(newval);
+}
+
+void jcallback_config_set_boolean(int item_ptr, int selected) {
+ config_item *i = (config_item *)item_ptr;
+ i->ival = selected != 0 ? TRUE : FALSE;
+}
+
+void jcallback_config_set_choice(int item_ptr, int selected) {
+ config_item *i = (config_item *)item_ptr;
+ i->ival = selected;
+}
+
+static int get_config(frontend *fe, int which)
+{
+ char *title;
+ config_item *i;
+ fe->cfg = midend_get_config(fe->me, which, &title);
+ fe->cfg_which = which;
+ fe->cfgret = FALSE;
+ _call_java(10, (int)title, 0, 0);
+ for (i = fe->cfg; i->type != C_END; i++) {
+ _call_java(5, (int)i, i->type, (int)i->name);
+ _call_java(11, (int)i->sval, i->ival, 0);
+ }
+ _call_java(12,0,0,0);
+ free_cfg(fe->cfg);
+ return fe->cfgret;
+}
+
+int jcallback_menu_key_event(int key)
+{
+ frontend *fe = (frontend *)_fe;
+ if (!midend_process_key(fe->me, 0, 0, key))
+ return 42;
+ return 0;
+}
+
+static void resize_fe(frontend *fe)
+{
+ int x, y;
+
+ x = INT_MAX;
+ y = INT_MAX;
+ midend_size(fe->me, &x, &y, FALSE);
+ _call_java(3, x, y, 0);
+}
+
+int jcallback_preset_event(int ptr_game_params)
+{
+ frontend *fe = (frontend *)_fe;
+ game_params *params =
+ (game_params *)ptr_game_params;
+
+ midend_set_params(fe->me, params);
+ midend_new_game(fe->me);
+ resize_fe(fe);
+ _call_java(13, midend_which_preset(fe->me), 0, 0);
+ return 0;
+}
+
+int jcallback_solve_event()
+{
+ frontend *fe = (frontend *)_fe;
+ char *msg;
+
+ msg = midend_solve(fe->me);
+
+ if (msg)
+ _call_java(2, (int) "Error", (int)msg, 1);
+ return 0;
+}
+
+int jcallback_restart_event()
+{
+ frontend *fe = (frontend *)_fe;
+
+ midend_restart_game(fe->me);
+ return 0;
+}
+
+int jcallback_config_event(int which)
+{
+ frontend *fe = (frontend *)_fe;
+ _call_java(13, midend_which_preset(fe->me), 0, 0);
+ if (!get_config(fe, which))
+ return 0;
+ midend_new_game(fe->me);
+ resize_fe(fe);
+ _call_java(13, midend_which_preset(fe->me), 0, 0);
+ return 0;
+}
+
+int jcallback_about_event()
+{
+ char titlebuf[256];
+ char textbuf[1024];
+
+ sprintf(titlebuf, "About %.200s", thegame.name);
+ sprintf(textbuf,
+ "%.200s\n\n"
+ "from Simon Tatham's Portable Puzzle Collection\n\n"
+ "%.500s", thegame.name, ver);
+ _call_java(2, (int)&titlebuf, (int)&textbuf, 0);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int i, n;
+ float* colours;
+
+ _fe = snew(frontend);
+ _fe->timer_active = FALSE;
+ _fe->me = midend_new(_fe, &thegame, &nestedvm_drawing, _fe);
+ if (argc > 1)
+ midend_game_id(_fe->me, argv[1]); /* ignore failure */
+ midend_new_game(_fe->me);
+
+ if ((n = midend_num_presets(_fe->me)) > 0) {
+ int i;
+ for (i = 0; i < n; i++) {
+ char *name;
+ game_params *params;
+ midend_fetch_preset(_fe->me, i, &name, &params);
+ _call_java(1, (int)name, (int)params, 0);
+ }
+ }
+
+ colours = midend_colours(_fe->me, &n);
+ _fe->ox = -1;
+
+ _call_java(0, (int)thegame.name,
+ (thegame.can_configure ? 1 : 0) |
+ (midend_wants_statusbar(_fe->me) ? 2 : 0) |
+ (thegame.can_solve ? 4 : 0), n);
+ for (i = 0; i < n; i++) {
+ _call_java(1024+ i,
+ (int)(colours[i*3] * 0xFF),
+ (int)(colours[i*3+1] * 0xFF),
+ (int)(colours[i*3+2] * 0xFF));
+ }
+ resize_fe(_fe);
+
+ _call_java(13, midend_which_preset(_fe->me), 0, 0);
+
+ // Now pause the vm. The VM will be call()ed when
+ // an input event occurs.
+ _pause();
+
+ // shut down when the VM is resumed.
+ deactivate_timer(_fe);
+ midend_free(_fe->me);
+ return 0;
+}