nestedvm.c 11 KB

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