diff --git a/apps/tools/twndel/state.h b/apps/tools/twndel/state.h index fbe224f..f24bdab 100644 --- a/apps/tools/twndel/state.h +++ b/apps/tools/twndel/state.h @@ -20,6 +20,10 @@ #define CAMERA_ROTATION_SPEED 0.04f #define SELECTION_SPHERE_RADIUS 32 +/* should be an odd number */ +#define SNAP_LINES_SHOW 7 +#define SNAP_LINES_WIDTH 1.0f +#define SNAP_LINES_COLOR ((Color){200,200,200,150}) typedef struct Operation { enum { diff --git a/apps/tools/twndel/tool.c b/apps/tools/twndel/tool.c index 4c46f01..82b5050 100644 --- a/apps/tools/twndel/tool.c +++ b/apps/tools/twndel/tool.c @@ -242,6 +242,39 @@ static bool vector_plane_intersection(Vec3 o, Vec3 v, Vec3 p, Vec3 n, Vec3 *out) } +static void show_snap_lines(Vec3 p) { + float step = 1.0f / ((float)POINTS_PER_METER / state.grid_snap_granularity); + int const lines_per_side = (SNAP_LINES_SHOW - 1) / 2; + for (int l = -lines_per_side; l <= lines_per_side; ++l) { + if (!state.axis_mask[0]) { + Vec3 c = vec3_add(p, vec3_scale((Vec3){1,0,0}, step * (float)l)); + draw_line_3d( + vec3_add(c, vec3_scale((Vec3){0,0,1}, SNAP_LINES_WIDTH)), + vec3_add(c, vec3_scale((Vec3){0,0,1}, -SNAP_LINES_WIDTH)), + 1, + SNAP_LINES_COLOR); + } + if (!state.axis_mask[1]) { + Vec3 axis = fabsf(vec3_dot(state.camera_direction, (Vec3){0,0,1})) >= 0.5f ? (Vec3){1,0,0} : (Vec3){0,0,1}; + Vec3 c = vec3_add(p, vec3_scale((Vec3){0,1,0}, step * (float)l)); + draw_line_3d( + vec3_add(c, vec3_scale(axis, SNAP_LINES_WIDTH)), + vec3_add(c, vec3_scale(axis, -SNAP_LINES_WIDTH)), + 1, + SNAP_LINES_COLOR); + } + if (!state.axis_mask[2]) { + Vec3 c = vec3_add(p, vec3_scale((Vec3){0,0,1}, step * (float)l)); + draw_line_3d( + vec3_add(c, vec3_scale((Vec3){1,0,0}, SNAP_LINES_WIDTH)), + vec3_add(c, vec3_scale((Vec3){1,0,0}, -SNAP_LINES_WIDTH)), + 1, + SNAP_LINES_COLOR); + } + } +} + + static void process_operation_move_point(Operation *op) { /* finish dragging around */ /* TODO: dont keep empty ops on stack? */ @@ -262,16 +295,15 @@ static void process_operation_move_point(Operation *op) { Vec3 p = point_to_vec3(op->data.move_point.object, op->data.move_point.point); bool point_moved = false; - /* TODO: show thresholds */ - /* TODO: planes used should depend on looking angle */ - /* for example, editing from the side makes better use of x/z facing planes */ - /* figure out which planes are angled acutely against the viewing direction */ bool y_closer_than_horizon = fabsf(vec3_dot(state.camera_direction, (Vec3){0,1,0})) >= 0.5f; Vec3 plane_normal_x = y_closer_than_horizon ? (Vec3){0,1,0} : (Vec3){0,0,1}; Vec3 plane_normal_z = y_closer_than_horizon ? (Vec3){0,1,0} : (Vec3){1,0,0}; + /* show snapping in lines */ + show_snap_lines(p); + Vec3 s; if (!state.axis_mask[0]) { if (vector_plane_intersection(cam.position, cam.direction, p, plane_normal_x, &s)) {