/raidem-0.3.1-src/tools/splined.m
Objective C | 511 lines | 383 code | 103 blank | 25 comment | 64 complexity | 167c608ed15f28449d47cd51be9de0f4 MD5 | raw file
- // #define DEBUG_SPLINED
- #include <allegro.h>
- #include <assert.h>
- #include <math.h>
- #include "common.h"
- #include "linklist.h"
- #include "waypoint.h"
- static BITMAP *dbuf;
- static int black, red, green, blue, yellow, magenta, cyan, white;
- static waypoint_t *waypoint_array;
- static int total_waypoint_steps;
- static ControlPoint *cp_in_use; /* The ctrlpt being moved or placed. */
- static BOOL mouse_held_lmb;
- static int control_point_n; /* Which of the sub-ctrlpts in use. */
- static BOOL snap_to_grid;
- static double offx, offy;
- static void draw_spline(void)
- {
- int i, c = makecol(0x80, 0x80, 0x80);
- for (i = 0; i < total_waypoint_steps; i++)
- putpixel(dbuf, waypoint_array[i].x-offx, waypoint_array[i].y-offy, c);
- }
- static void draw_control_points(List *list)
- {
- ListIterator *it;
- int n = 0, steps = 0;
- double x, y, x0, y0, x1, y1, first_x = 0, first_y = 0;
- foreach (it, list) {
- ControlPoint *cp = [it getItem];
- [cp getX:&x Y:&y];
- [cp getControlPoint:0 X:&x0 Y:&y0];
- [cp getControlPoint:1 X:&x1 Y:&y1];
- steps = [cp steps];
- x -= offx; x0 -= offx; x1 -= offx;
- y -= offy; y0 -= offy; y1 -= offy;
- if (n == 0)
- first_x = x, first_y = y;
- line(dbuf, x, y, x0, y0, white);
- line(dbuf, x, y, x1, y1, white);
- circle(dbuf, x, y, 8, (cp == cp_in_use) ? yellow : green);
- circle(dbuf, x0, y0, 4, red);
- circle(dbuf, x1, y1, 4, blue);
- textprintf(dbuf, font, x, y, white, "%d", n);
- textprintf(dbuf, font, 0, n * 10, (cp == cp_in_use) ? yellow : white,
- "%02d: (%03g, %03g) - %d", n, x - first_x, y - first_y, steps);
- n++;
- }
- y = n * 10;
- textprintf(dbuf, font, 0, y, cyan, " total - %d", n);
- }
- /*--------------------------------------------------------------*/
- /* Load/Save (old, uses PACKFILE). */
- /*--------------------------------------------------------------*/
- #if 0
- static void export_file_pack(List *list)
- {
- ListIterator *it;
- PACKFILE *fp;
- char path[1024] = "";
- double first_x, first_y;
- if (file_select_ex("Save as...", path, "spline", sizeof path, 480, 320) == 0)
- return;
- fp = pack_fopen(path, "wp");
- if (!fp)
- return;
- first_x = waypoint_array[0].x;
- first_y = waypoint_array[0].y;
- foreach (it, list) {
- ControlPoint *cp = [it getItem];
- double x, y, x0, y0, x1, y1;
- int steps;
- [cp getX:&x Y:&y];
- steps = [cp steps];
- [cp getControlPoint:0 X:&x0 Y:&y0];
- [cp getControlPoint:1 X:&x1 Y:&y1];
- pack_iputl(x - first_x, fp);
- pack_iputl(y - first_y, fp);
- pack_iputl(steps, fp);
- pack_iputl(x0 - x, fp);
- pack_iputl(y0 - y, fp);
- pack_iputl(x1 - x, fp);
- pack_iputl(y1 - y, fp);
- }
- pack_fclose(fp);
- }
- #endif
- static unsigned int load_spline_pack(const char *fn, waypoint_t *waypoints[], List **ll)
- {
- PACKFILE *fp;
- unsigned int len;
- List *l;
- assert(fn);
- if (!(fp = pack_fopen(fn, "rp")))
- return 0;
- if (ll)
- l = *ll;
- else
- l = [LIST_NEW]; /* Create a temporary list of waypoints. */
- assert(l);
- while (!pack_feof(fp)) {
- ControlPoint *cp;
- double x, y, x0, y0, x1, y1;
- int steps;
- x = pack_igetl(fp);
- y = pack_igetl(fp);
- steps = pack_igetl(fp);
- x0 = pack_igetl(fp);
- y0 = pack_igetl(fp);
- x1 = pack_igetl(fp);
- y1 = pack_igetl(fp);
- cp = [[[[ControlPoint new] setX:x Y:y steps:steps]
- setControlPoint:0 X:x0 Y:y0]
- setControlPoint:1 X:x1 Y:y1];
- [l insertItemAtEnd:cp];
- }
- pack_fclose(fp);
- len = spline_length(l);
- (*waypoints) = articulate_spline(l);
- if (ll)
- *ll = l;
- else
- l = [l free];
- return len;
- }
- static List *import_file_pack(void)
- {
- char fn[PATH_MAX] = "";
- List *list = [LIST_NEW];
- assert(list);
- if (file_select_ex("Load...", fn, "spline", sizeof fn, 480, 320) == 0)
- return NULL;
- total_waypoint_steps = load_spline_pack(fn, &waypoint_array, &list);
- return list;
- }
- /*--------------------------------------------------------------*/
- /* Load/Save (new). */
- /*--------------------------------------------------------------*/
- /* Stolen from waypoint.m */
- typedef struct {
- int x, y; /* X/Y relative to first point. */
- unsigned int steps;
- int x0, y0, x1, y1; /* Control point's x/y. */
- } save_struct_t;
- /* Stolen from allegro/src/file.c */
- long iputl(long l, FILE *f)
- {
- int b1, b2, b3, b4;
- ASSERT(f);
- b1 = (int)((l & 0xFF000000L) >> 24);
- b2 = (int)((l & 0x00FF0000L) >> 16);
- b3 = (int)((l & 0x0000FF00L) >> 8);
- b4 = (int)l & 0x00FF;
- if (fputc(b4,f)==b4)
- if (fputc(b3,f)==b3)
- if (fputc(b2,f)==b2)
- if (fputc(b1,f)==b1)
- return l;
- return EOF;
- }
- static List *import_file(void)
- {
- char fn[PATH_MAX] = "";
- List *list = [LIST_NEW];
- assert(list);
- if (file_select_ex("Load...", fn, "spline", sizeof fn, 480, 320) == 0)
- return NULL;
- total_waypoint_steps = load_spline(fn, &waypoint_array, &list);
- return list;
- }
- static void export_file(List *list)
- {
- FILE *fp;
- ListIterator *it;
- char path[1024] = "";
- double first_x, first_y;
- if (file_select_ex("Save as...", path, "spline", sizeof path, 480, 320) == 0)
- return;
- fp = fopen(path, "wb");
- if (!fp)
- return;
- first_x = waypoint_array[0].x;
- first_y = waypoint_array[0].y;
- foreach (it, list) {
- ControlPoint *cp = [it getItem];
- double x, y, x0, y0, x1, y1;
- unsigned int steps;
- steps = [cp steps];
- [cp getX:&x Y:&y];
- [cp getControlPoint:0 X:&x0 Y:&y0];
- [cp getControlPoint:1 X:&x1 Y:&y1];
- iputl(x - first_x, fp);
- iputl(y - first_y, fp);
- iputl(steps, fp);
- iputl(x0 - x, fp);
- iputl(y0 - y, fp);
- iputl(x1 - x, fp);
- iputl(y1 - y, fp);
- }
- fclose(fp);
- }
- /*--------------------------------------------------------------*/
- static ControlPoint *find_control_point_near(List *list, int x, int y)
- {
- ControlPoint *cp;
- ListIterator *it;
- foreach (it, list) {
- double xx, yy;
- cp = [it getItem];
- [cp getControlPoint:0 X:&xx Y:&yy];
- if (SQ(x - xx) + SQ(y - yy) < SQ(6)) {
- control_point_n = 0;
- break;
- }
- [cp getControlPoint:1 X:&xx Y:&yy];
- if (SQ(x - xx) + SQ(y - yy) < SQ(6)) {
- control_point_n = 1;
- break;
- }
- [cp getX:&xx Y:&yy];
- if (SQ(x - xx) + SQ(y - yy) < SQ(8)) {
- control_point_n = -1;
- break;
- }
- }
- if (it) {
- [it free];
- return cp;
- }
- return NULL;
- }
- static void splined_loop(void)
- {
- BOOL redraw = YES;
- List *list = [LIST_NEW];
- do {
- int mx = mouse_x + offx, my = mouse_y + offy;
- /* Snap to grid. Real cheaped. */
- if (key[KEY_SPACE]) {
- while (key[KEY_SPACE]);
- snap_to_grid = !snap_to_grid;
- redraw = YES;
- }
- /* Load/save. */
- if (key[KEY_L] && (key_shifts & KB_CTRL_FLAG)) {
- List *new_list;
- if (key_shifts & KB_SHIFT_FLAG)
- new_list = import_file_pack();
- else
- new_list = import_file();
- if (new_list) {
- cp_in_use = NULL;
- [list free];
- list = new_list;
- total_waypoint_steps = spline_length(list);
- redraw = YES;
- }
- }
- if (key[KEY_S] && (key_shifts & KB_CTRL_FLAG))
- export_file(list);
- /* Increase/decrease steps to reach control point. */
- if (cp_in_use) {
- if (key[KEY_UP]) {
- while(key[KEY_UP]);
- [cp_in_use setSteps:[cp_in_use steps] + 1];
- redraw = YES;
- }
- if (key[KEY_DOWN]) {
- [cp_in_use setSteps:MAX(1, [cp_in_use steps] - 1)];
- redraw = YES;
- }
- }
- /* Pan around the area. */
- if (key[KEY_H]) offx -= 3.0, redraw = YES;
- if (key[KEY_J]) offy += 3.0, redraw = YES;
- if (key[KEY_K]) offy -= 3.0, redraw = YES;
- if (key[KEY_L]) offx += 3.0, redraw = YES;
- /* Add or move a control point. */
- if ((mouse_b & 1) && !(mouse_held_lmb)) {
- cp_in_use = find_control_point_near(list, mx, my);
- /* Add one. */
- if (!cp_in_use) {
- cp_in_use = [[ControlPoint new] setX:mx Y:my];
- [list insertItemAtEnd:cp_in_use];
-
- /* After we place one, we want to set the control points. */
- control_point_n = 0;
- }
- mouse_held_lmb = YES;
- }
- else if (mouse_held_lmb) {
- if (cp_in_use) {
- double x, y;
- if (control_point_n < 0) {
- if (snap_to_grid)
- x = mx/10*10, y = my/10*10;
- else
- x = mx, y = my;
- [cp_in_use setX:x Y:y];
- }
- else {
- [cp_in_use getX:&x Y:&y];
- x = mx - x;
- y = my - y;
- /* 90 degrees. */
- if (key[KEY_LCONTROL]) {
- if (ABS(x) < ABS(y))
- x = 0;
- else
- y = 0;
- }
- [cp_in_use setControlPoint:control_point_n X:x Y:y];
- /* If shift is not pressed, move the other one too. */
- if (!key[KEY_LSHIFT])
- [cp_in_use setControlPoint:!control_point_n X:-x Y:-y];
- }
- }
- mouse_held_lmb = (mouse_b & 1);
- redraw = YES;
- }
- /* Remove a control point. */
- if (mouse_b & 2) {
- cp_in_use = find_control_point_near(list, mx, my);
- if (cp_in_use) {
- [list removeItem:cp_in_use];
- cp_in_use = [cp_in_use free];
- redraw = YES;
- }
- }
- /*----------*/
- if (redraw) {
- int old_spline_length = total_waypoint_steps;
- clear_to_color(dbuf, black);
- rectfill_wh(dbuf, (SCREEN_W - screen_w)/2, 0, screen_w, screen_h, makecol(0x40, 0x40, 0x40));
- total_waypoint_steps = spline_length(list);
- if (total_waypoint_steps < old_spline_length) {
- waypoint_array = reticulate_spline(waypoint_array, list);
- }
- else {
- /* Need more room + lazy to muck with realloc = */
- FREE_SPLINE(waypoint_array);
- waypoint_array = articulate_spline(list);
- }
- draw_control_points(list);
- draw_spline();
- if (snap_to_grid)
- textout(dbuf, font, "Snapped", 0, SCREEN_H - 10, white);
- scare_mouse();
- blit(dbuf, screen, 0, 0, 0, 0, dbuf->w, dbuf->h);
- unscare_mouse();
- redraw = NO;
- }
- } while (!key[KEY_Q]);
- if (list)
- list = [list free];
- }
- /*--------------------------------------------------------------*/
- #ifdef DEBUG_SPLINED
- #include <mcheck.h>
- @interface mtraceInit
- @end
- @implementation mtraceInit
- + (void)load
- {
- setenv("MALLOC_TRACE", "./,splined-memtrace.log", 0);
- mtrace();
- }
- @end
- #endif
- static int splined_init(void)
- {
- allegro_init();
- install_timer();
- set_color_depth(16);
- if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) < 0) {
- allegro_message("Error setting video mode.\n%s.\n", allegro_error);
- return -1;
- }
- set_window_title("Raid'em Spline Editor");
- dbuf = create_bitmap(SCREEN_W, SCREEN_H);
- clear_to_color(dbuf, makecol(0x00, 0x00, 0x00));
- /* Input devices. */
- install_keyboard();
- install_mouse();
- show_mouse(screen);
- /* Basic colours. */
- black = makecol(0x00, 0x00, 0x00);
- red = makecol(0xff, 0x00, 0x00);
- green = makecol(0x00, 0xff, 0x00);
- blue = makecol(0x00, 0x00, 0xff);
- yellow = makecol(0xff, 0xff, 0x00);
- magenta = makecol(0xff, 0x00, 0xff);
- cyan = makecol(0x00, 0xff, 0xff);
- white = makecol(0xff, 0xff, 0xff);
- return 0;
- }
- static void splined_shutdown(void)
- {
- FREE_BITMAP(dbuf);
- FREE_SPLINE(waypoint_array);
- }
- int main(void)
- {
- if (splined_init() < 0)
- return -1;
- splined_loop();
- splined_shutdown();
- return 0;
- }
- END_OF_MAIN()