PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/raidem-0.3.1-src/tools/splined.m

#
Objective C | 511 lines | 383 code | 103 blank | 25 comment | 64 complexity | 167c608ed15f28449d47cd51be9de0f4 MD5 | raw file
  1. // #define DEBUG_SPLINED
  2. #include <allegro.h>
  3. #include <assert.h>
  4. #include <math.h>
  5. #include "common.h"
  6. #include "linklist.h"
  7. #include "waypoint.h"
  8. static BITMAP *dbuf;
  9. static int black, red, green, blue, yellow, magenta, cyan, white;
  10. static waypoint_t *waypoint_array;
  11. static int total_waypoint_steps;
  12. static ControlPoint *cp_in_use; /* The ctrlpt being moved or placed. */
  13. static BOOL mouse_held_lmb;
  14. static int control_point_n; /* Which of the sub-ctrlpts in use. */
  15. static BOOL snap_to_grid;
  16. static double offx, offy;
  17. static void draw_spline(void)
  18. {
  19. int i, c = makecol(0x80, 0x80, 0x80);
  20. for (i = 0; i < total_waypoint_steps; i++)
  21. putpixel(dbuf, waypoint_array[i].x-offx, waypoint_array[i].y-offy, c);
  22. }
  23. static void draw_control_points(List *list)
  24. {
  25. ListIterator *it;
  26. int n = 0, steps = 0;
  27. double x, y, x0, y0, x1, y1, first_x = 0, first_y = 0;
  28. foreach (it, list) {
  29. ControlPoint *cp = [it getItem];
  30. [cp getX:&x Y:&y];
  31. [cp getControlPoint:0 X:&x0 Y:&y0];
  32. [cp getControlPoint:1 X:&x1 Y:&y1];
  33. steps = [cp steps];
  34. x -= offx; x0 -= offx; x1 -= offx;
  35. y -= offy; y0 -= offy; y1 -= offy;
  36. if (n == 0)
  37. first_x = x, first_y = y;
  38. line(dbuf, x, y, x0, y0, white);
  39. line(dbuf, x, y, x1, y1, white);
  40. circle(dbuf, x, y, 8, (cp == cp_in_use) ? yellow : green);
  41. circle(dbuf, x0, y0, 4, red);
  42. circle(dbuf, x1, y1, 4, blue);
  43. textprintf(dbuf, font, x, y, white, "%d", n);
  44. textprintf(dbuf, font, 0, n * 10, (cp == cp_in_use) ? yellow : white,
  45. "%02d: (%03g, %03g) - %d", n, x - first_x, y - first_y, steps);
  46. n++;
  47. }
  48. y = n * 10;
  49. textprintf(dbuf, font, 0, y, cyan, " total - %d", n);
  50. }
  51. /*--------------------------------------------------------------*/
  52. /* Load/Save (old, uses PACKFILE). */
  53. /*--------------------------------------------------------------*/
  54. #if 0
  55. static void export_file_pack(List *list)
  56. {
  57. ListIterator *it;
  58. PACKFILE *fp;
  59. char path[1024] = "";
  60. double first_x, first_y;
  61. if (file_select_ex("Save as...", path, "spline", sizeof path, 480, 320) == 0)
  62. return;
  63. fp = pack_fopen(path, "wp");
  64. if (!fp)
  65. return;
  66. first_x = waypoint_array[0].x;
  67. first_y = waypoint_array[0].y;
  68. foreach (it, list) {
  69. ControlPoint *cp = [it getItem];
  70. double x, y, x0, y0, x1, y1;
  71. int steps;
  72. [cp getX:&x Y:&y];
  73. steps = [cp steps];
  74. [cp getControlPoint:0 X:&x0 Y:&y0];
  75. [cp getControlPoint:1 X:&x1 Y:&y1];
  76. pack_iputl(x - first_x, fp);
  77. pack_iputl(y - first_y, fp);
  78. pack_iputl(steps, fp);
  79. pack_iputl(x0 - x, fp);
  80. pack_iputl(y0 - y, fp);
  81. pack_iputl(x1 - x, fp);
  82. pack_iputl(y1 - y, fp);
  83. }
  84. pack_fclose(fp);
  85. }
  86. #endif
  87. static unsigned int load_spline_pack(const char *fn, waypoint_t *waypoints[], List **ll)
  88. {
  89. PACKFILE *fp;
  90. unsigned int len;
  91. List *l;
  92. assert(fn);
  93. if (!(fp = pack_fopen(fn, "rp")))
  94. return 0;
  95. if (ll)
  96. l = *ll;
  97. else
  98. l = [LIST_NEW]; /* Create a temporary list of waypoints. */
  99. assert(l);
  100. while (!pack_feof(fp)) {
  101. ControlPoint *cp;
  102. double x, y, x0, y0, x1, y1;
  103. int steps;
  104. x = pack_igetl(fp);
  105. y = pack_igetl(fp);
  106. steps = pack_igetl(fp);
  107. x0 = pack_igetl(fp);
  108. y0 = pack_igetl(fp);
  109. x1 = pack_igetl(fp);
  110. y1 = pack_igetl(fp);
  111. cp = [[[[ControlPoint new] setX:x Y:y steps:steps]
  112. setControlPoint:0 X:x0 Y:y0]
  113. setControlPoint:1 X:x1 Y:y1];
  114. [l insertItemAtEnd:cp];
  115. }
  116. pack_fclose(fp);
  117. len = spline_length(l);
  118. (*waypoints) = articulate_spline(l);
  119. if (ll)
  120. *ll = l;
  121. else
  122. l = [l free];
  123. return len;
  124. }
  125. static List *import_file_pack(void)
  126. {
  127. char fn[PATH_MAX] = "";
  128. List *list = [LIST_NEW];
  129. assert(list);
  130. if (file_select_ex("Load...", fn, "spline", sizeof fn, 480, 320) == 0)
  131. return NULL;
  132. total_waypoint_steps = load_spline_pack(fn, &waypoint_array, &list);
  133. return list;
  134. }
  135. /*--------------------------------------------------------------*/
  136. /* Load/Save (new). */
  137. /*--------------------------------------------------------------*/
  138. /* Stolen from waypoint.m */
  139. typedef struct {
  140. int x, y; /* X/Y relative to first point. */
  141. unsigned int steps;
  142. int x0, y0, x1, y1; /* Control point's x/y. */
  143. } save_struct_t;
  144. /* Stolen from allegro/src/file.c */
  145. long iputl(long l, FILE *f)
  146. {
  147. int b1, b2, b3, b4;
  148. ASSERT(f);
  149. b1 = (int)((l & 0xFF000000L) >> 24);
  150. b2 = (int)((l & 0x00FF0000L) >> 16);
  151. b3 = (int)((l & 0x0000FF00L) >> 8);
  152. b4 = (int)l & 0x00FF;
  153. if (fputc(b4,f)==b4)
  154. if (fputc(b3,f)==b3)
  155. if (fputc(b2,f)==b2)
  156. if (fputc(b1,f)==b1)
  157. return l;
  158. return EOF;
  159. }
  160. static List *import_file(void)
  161. {
  162. char fn[PATH_MAX] = "";
  163. List *list = [LIST_NEW];
  164. assert(list);
  165. if (file_select_ex("Load...", fn, "spline", sizeof fn, 480, 320) == 0)
  166. return NULL;
  167. total_waypoint_steps = load_spline(fn, &waypoint_array, &list);
  168. return list;
  169. }
  170. static void export_file(List *list)
  171. {
  172. FILE *fp;
  173. ListIterator *it;
  174. char path[1024] = "";
  175. double first_x, first_y;
  176. if (file_select_ex("Save as...", path, "spline", sizeof path, 480, 320) == 0)
  177. return;
  178. fp = fopen(path, "wb");
  179. if (!fp)
  180. return;
  181. first_x = waypoint_array[0].x;
  182. first_y = waypoint_array[0].y;
  183. foreach (it, list) {
  184. ControlPoint *cp = [it getItem];
  185. double x, y, x0, y0, x1, y1;
  186. unsigned int steps;
  187. steps = [cp steps];
  188. [cp getX:&x Y:&y];
  189. [cp getControlPoint:0 X:&x0 Y:&y0];
  190. [cp getControlPoint:1 X:&x1 Y:&y1];
  191. iputl(x - first_x, fp);
  192. iputl(y - first_y, fp);
  193. iputl(steps, fp);
  194. iputl(x0 - x, fp);
  195. iputl(y0 - y, fp);
  196. iputl(x1 - x, fp);
  197. iputl(y1 - y, fp);
  198. }
  199. fclose(fp);
  200. }
  201. /*--------------------------------------------------------------*/
  202. static ControlPoint *find_control_point_near(List *list, int x, int y)
  203. {
  204. ControlPoint *cp;
  205. ListIterator *it;
  206. foreach (it, list) {
  207. double xx, yy;
  208. cp = [it getItem];
  209. [cp getControlPoint:0 X:&xx Y:&yy];
  210. if (SQ(x - xx) + SQ(y - yy) < SQ(6)) {
  211. control_point_n = 0;
  212. break;
  213. }
  214. [cp getControlPoint:1 X:&xx Y:&yy];
  215. if (SQ(x - xx) + SQ(y - yy) < SQ(6)) {
  216. control_point_n = 1;
  217. break;
  218. }
  219. [cp getX:&xx Y:&yy];
  220. if (SQ(x - xx) + SQ(y - yy) < SQ(8)) {
  221. control_point_n = -1;
  222. break;
  223. }
  224. }
  225. if (it) {
  226. [it free];
  227. return cp;
  228. }
  229. return NULL;
  230. }
  231. static void splined_loop(void)
  232. {
  233. BOOL redraw = YES;
  234. List *list = [LIST_NEW];
  235. do {
  236. int mx = mouse_x + offx, my = mouse_y + offy;
  237. /* Snap to grid. Real cheaped. */
  238. if (key[KEY_SPACE]) {
  239. while (key[KEY_SPACE]);
  240. snap_to_grid = !snap_to_grid;
  241. redraw = YES;
  242. }
  243. /* Load/save. */
  244. if (key[KEY_L] && (key_shifts & KB_CTRL_FLAG)) {
  245. List *new_list;
  246. if (key_shifts & KB_SHIFT_FLAG)
  247. new_list = import_file_pack();
  248. else
  249. new_list = import_file();
  250. if (new_list) {
  251. cp_in_use = NULL;
  252. [list free];
  253. list = new_list;
  254. total_waypoint_steps = spline_length(list);
  255. redraw = YES;
  256. }
  257. }
  258. if (key[KEY_S] && (key_shifts & KB_CTRL_FLAG))
  259. export_file(list);
  260. /* Increase/decrease steps to reach control point. */
  261. if (cp_in_use) {
  262. if (key[KEY_UP]) {
  263. while(key[KEY_UP]);
  264. [cp_in_use setSteps:[cp_in_use steps] + 1];
  265. redraw = YES;
  266. }
  267. if (key[KEY_DOWN]) {
  268. [cp_in_use setSteps:MAX(1, [cp_in_use steps] - 1)];
  269. redraw = YES;
  270. }
  271. }
  272. /* Pan around the area. */
  273. if (key[KEY_H]) offx -= 3.0, redraw = YES;
  274. if (key[KEY_J]) offy += 3.0, redraw = YES;
  275. if (key[KEY_K]) offy -= 3.0, redraw = YES;
  276. if (key[KEY_L]) offx += 3.0, redraw = YES;
  277. /* Add or move a control point. */
  278. if ((mouse_b & 1) && !(mouse_held_lmb)) {
  279. cp_in_use = find_control_point_near(list, mx, my);
  280. /* Add one. */
  281. if (!cp_in_use) {
  282. cp_in_use = [[ControlPoint new] setX:mx Y:my];
  283. [list insertItemAtEnd:cp_in_use];
  284. /* After we place one, we want to set the control points. */
  285. control_point_n = 0;
  286. }
  287. mouse_held_lmb = YES;
  288. }
  289. else if (mouse_held_lmb) {
  290. if (cp_in_use) {
  291. double x, y;
  292. if (control_point_n < 0) {
  293. if (snap_to_grid)
  294. x = mx/10*10, y = my/10*10;
  295. else
  296. x = mx, y = my;
  297. [cp_in_use setX:x Y:y];
  298. }
  299. else {
  300. [cp_in_use getX:&x Y:&y];
  301. x = mx - x;
  302. y = my - y;
  303. /* 90 degrees. */
  304. if (key[KEY_LCONTROL]) {
  305. if (ABS(x) < ABS(y))
  306. x = 0;
  307. else
  308. y = 0;
  309. }
  310. [cp_in_use setControlPoint:control_point_n X:x Y:y];
  311. /* If shift is not pressed, move the other one too. */
  312. if (!key[KEY_LSHIFT])
  313. [cp_in_use setControlPoint:!control_point_n X:-x Y:-y];
  314. }
  315. }
  316. mouse_held_lmb = (mouse_b & 1);
  317. redraw = YES;
  318. }
  319. /* Remove a control point. */
  320. if (mouse_b & 2) {
  321. cp_in_use = find_control_point_near(list, mx, my);
  322. if (cp_in_use) {
  323. [list removeItem:cp_in_use];
  324. cp_in_use = [cp_in_use free];
  325. redraw = YES;
  326. }
  327. }
  328. /*----------*/
  329. if (redraw) {
  330. int old_spline_length = total_waypoint_steps;
  331. clear_to_color(dbuf, black);
  332. rectfill_wh(dbuf, (SCREEN_W - screen_w)/2, 0, screen_w, screen_h, makecol(0x40, 0x40, 0x40));
  333. total_waypoint_steps = spline_length(list);
  334. if (total_waypoint_steps < old_spline_length) {
  335. waypoint_array = reticulate_spline(waypoint_array, list);
  336. }
  337. else {
  338. /* Need more room + lazy to muck with realloc = */
  339. FREE_SPLINE(waypoint_array);
  340. waypoint_array = articulate_spline(list);
  341. }
  342. draw_control_points(list);
  343. draw_spline();
  344. if (snap_to_grid)
  345. textout(dbuf, font, "Snapped", 0, SCREEN_H - 10, white);
  346. scare_mouse();
  347. blit(dbuf, screen, 0, 0, 0, 0, dbuf->w, dbuf->h);
  348. unscare_mouse();
  349. redraw = NO;
  350. }
  351. } while (!key[KEY_Q]);
  352. if (list)
  353. list = [list free];
  354. }
  355. /*--------------------------------------------------------------*/
  356. #ifdef DEBUG_SPLINED
  357. #include <mcheck.h>
  358. @interface mtraceInit
  359. @end
  360. @implementation mtraceInit
  361. + (void)load
  362. {
  363. setenv("MALLOC_TRACE", "./,splined-memtrace.log", 0);
  364. mtrace();
  365. }
  366. @end
  367. #endif
  368. static int splined_init(void)
  369. {
  370. allegro_init();
  371. install_timer();
  372. set_color_depth(16);
  373. if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) < 0) {
  374. allegro_message("Error setting video mode.\n%s.\n", allegro_error);
  375. return -1;
  376. }
  377. set_window_title("Raid'em Spline Editor");
  378. dbuf = create_bitmap(SCREEN_W, SCREEN_H);
  379. clear_to_color(dbuf, makecol(0x00, 0x00, 0x00));
  380. /* Input devices. */
  381. install_keyboard();
  382. install_mouse();
  383. show_mouse(screen);
  384. /* Basic colours. */
  385. black = makecol(0x00, 0x00, 0x00);
  386. red = makecol(0xff, 0x00, 0x00);
  387. green = makecol(0x00, 0xff, 0x00);
  388. blue = makecol(0x00, 0x00, 0xff);
  389. yellow = makecol(0xff, 0xff, 0x00);
  390. magenta = makecol(0xff, 0x00, 0xff);
  391. cyan = makecol(0x00, 0xff, 0xff);
  392. white = makecol(0xff, 0xff, 0xff);
  393. return 0;
  394. }
  395. static void splined_shutdown(void)
  396. {
  397. FREE_BITMAP(dbuf);
  398. FREE_SPLINE(waypoint_array);
  399. }
  400. int main(void)
  401. {
  402. if (splined_init() < 0)
  403. return -1;
  404. splined_loop();
  405. splined_shutdown();
  406. return 0;
  407. }
  408. END_OF_MAIN()