static int on_move(gesture3d_t *gest, void *user) { float face_plane[4][4]; cursor_t *curs = gest->cursor; tool_move_t *tool = user; float n[3], pos[3], d[3], ofs[3], v[3]; layer_t *layer = goxel->image->active_layer; float mat[4][4]; if (box_is_null(tool->box)) return GESTURE_FAILED; if (gest->type == GESTURE_HOVER) { goxel_set_help_text(goxel, "Drag to move face"); if (curs->snaped != SNAP_LAYER_OUT) return GESTURE_FAILED; tool->snap_face = get_face(curs->normal); curs->snap_offset = 0; curs->snap_mask &= ~SNAP_ROUNDED; mat4_mul(tool->box, FACES_MATS[tool->snap_face], face_plane); render_img(&goxel->rend, NULL, face_plane, EFFECT_NO_SHADING); if (curs->flags & CURSOR_PRESSED) { gest->type = GESTURE_DRAG; vec3_normalize(face_plane[0], v); plane_from_vectors(goxel->tool_plane, curs->pos, curs->normal, v); image_history_push(goxel->image); } return 0; } if (gest->type == GESTURE_DRAG) { goxel_set_help_text(goxel, "Drag to move face"); curs->snap_offset = 0; curs->snap_mask &= ~SNAP_ROUNDED; mat4_mul(tool->box, FACES_MATS[tool->snap_face], face_plane); vec3_normalize(face_plane[2], n); vec3_sub(curs->pos, goxel->tool_plane[3], v); vec3_project(v, n, v); vec3_add(goxel->tool_plane[3], v, pos); pos[0] = round(pos[0]); pos[1] = round(pos[1]); pos[2] = round(pos[2]); vec3_add(tool->box[3], face_plane[2], d); vec3_sub(pos, d, ofs); vec3_project(ofs, n, ofs); mat4_set_identity(mat); mat4_itranslate(mat, ofs[0], ofs[1], ofs[2]); do_move(layer, mat); if (gest->state == GESTURE_END) { gest->type = GESTURE_HOVER; mat4_copy(plane_null, goxel->tool_plane); } return 0; } return 0; }
void collision_response_slide(void* x, vec3* position, vec3* velocity, collision (*colfunc)(void* x, vec3* pos, vec3* vel) ) { collision col = colfunc(x, position, velocity); int count = 0; while (col.collided) { //renderer_add(x, render_object_line(*position, vec3_add(*position, col.norm), vec3_red(), count+1)); if (count++ == 100) { *velocity = vec3_zero(); break; } vec3 fwrd = vec3_mul(*velocity, col.time); float len = max(vec3_length(fwrd) - 0.001, 0.0) / vec3_length(fwrd); vec3 move = vec3_add(*position, vec3_mul(fwrd, len)); vec3 proj = vec3_project(vec3_mul(*velocity, (1.0-col.time)), col.norm); //renderer_add(x, render_object_line(*position, vec3_add(*position, vec3_normalize(proj)), vec3_green(), count+1)); *position = move; *velocity = proj; col = colfunc(x, position, velocity); } *position = vec3_add(*position, *velocity); }
static int tool_cube_iter(goxel_t *goxel, const inputs_t *inputs, int state, const vec2_t *view_size, bool inside) { const bool down = inputs->mouse_down[0]; const bool up = !down; int snaped = 0; vec3_t pos, normal; box_t box; uvec4b_t box_color = HEXCOLOR(0xffff00ff); mesh_t *mesh = goxel->image->active_layer->mesh; if (inside) snaped = goxel_unproject(goxel, view_size, &inputs->mouse_pos, &pos, &normal); if (snaped) { if ( snaped == SNAP_MESH && goxel->painter.op == OP_ADD && !goxel->snap_offset) vec3_iadd(&pos, normal); pos.x = round(pos.x - 0.5) + 0.5; pos.y = round(pos.y - 0.5) + 0.5; pos.z = round(pos.z - 0.5) + 0.5; } if (state == STATE_IDLE) { goxel->tool_t = 0; if (snaped) state = STATE_SNAPED; } if (state == STATE_SNAPED) { if (goxel->tool_t == 0) { goxel->tool_t = 1; mesh_set(&goxel->tool_origin_mesh, mesh); } if (!snaped) return STATE_CANCEL; goxel_set_help_text(goxel, "Click and drag to draw."); goxel->tool_start_pos = pos; box = get_box(&goxel->tool_start_pos, &pos, &normal, 0, &goxel->plane); mesh_set(&mesh, goxel->tool_origin_mesh); mesh_op(mesh, &goxel->painter, &box); render_box(&goxel->rend, &box, false, &box_color, false); if (down) { state = STATE_PAINT; goxel->painting = true; } } if (state == STATE_PAINT) { goxel_set_help_text(goxel, "Drag."); box = get_box(&goxel->tool_start_pos, &pos, &normal, 0, &goxel->plane); render_box(&goxel->rend, &box, false, &box_color, false); mesh_set(&mesh, goxel->tool_origin_mesh); mesh_op(mesh, &goxel->painter, &box); goxel_update_meshes(goxel, false); if (up) { state = STATE_PAINT2; goxel->tool_plane = plane_from_normal(pos, goxel->plane.u); } } if (state == STATE_PAINT2) { goxel_set_help_text(goxel, "Adjust height."); render_plane(&goxel->rend, &goxel->tool_plane, &goxel->grid_color); pos = vec3_add(goxel->tool_plane.p, vec3_project(vec3_sub(pos, goxel->tool_plane.p), goxel->plane.n)); box = get_box(&goxel->tool_start_pos, &pos, &normal, 0, &goxel->plane); render_box(&goxel->rend, &box, false, &box_color, false); mesh_set(&mesh, goxel->tool_origin_mesh); mesh_op(mesh, &goxel->painter, &box); goxel_update_meshes(goxel, false); if (down) { mesh_set(&mesh, goxel->tool_origin_mesh); mesh_op(mesh, &goxel->painter, &box); goxel_update_meshes(goxel, true); goxel->painting = false; image_history_push(goxel->image); return STATE_WAIT_UP; } } if (state == STATE_WAIT_UP) { goxel->tool_plane = plane_null; if (up) state = STATE_IDLE; } return state; }
// XXX: this is very close to tool_cube_iter. static int tool_selection_iter(goxel_t *goxel, const inputs_t *inputs, int state, const vec2_t *view_size, bool inside) { extern const mat4_t FACES_MATS[6]; const bool down = inputs->mouse_down[0]; const bool up = !down; int snaped = 0; int face = -1; vec3_t pos, normal; plane_t face_plane; box_t box; uvec4b_t box_color = HEXCOLOR(0xffff00ff); // See if we can snap on a selection face. if (inside && !box_is_null(goxel->selection) && IS_IN(state, STATE_IDLE, STATE_SNAPED, STATE_SNAPED_FACE)) { goxel->tool_snape_face = -1; if (goxel_unproject_on_box(goxel, view_size, &inputs->mouse_pos, &goxel->selection, &pos, &normal, &face)) { goxel->tool_snape_face = face; state = STATE_SNAPED_FACE; } } if (!box_is_null(goxel->selection) && goxel->tool_snape_face != -1) face_plane.mat = mat4_mul(goxel->selection.mat, FACES_MATS[goxel->tool_snape_face]); if (inside && face == -1) snaped = goxel_unproject(goxel, view_size, &inputs->mouse_pos, &pos, &normal); if (snaped) { pos.x = round(pos.x - 0.5) + 0.5; pos.y = round(pos.y - 0.5) + 0.5; pos.z = round(pos.z - 0.5) + 0.5; } if (state == STATE_IDLE) { goxel->tool_t = 0; goxel->tool_snape_face = -1; if (snaped) state = STATE_SNAPED; } if (state == STATE_SNAPED) { if (!snaped) return STATE_CANCEL; goxel_set_help_text(goxel, "Click and drag to set selection."); goxel->tool_start_pos = pos; box = get_box(&goxel->tool_start_pos, &pos, &normal, 0, &goxel->plane); render_box(&goxel->rend, &box, false, &box_color, false); if (down) { state = STATE_PAINT; goxel->painting = true; } } if (state == STATE_PAINT) { goxel_set_help_text(goxel, "Drag."); goxel->selection = get_box(&goxel->tool_start_pos, &pos, &normal, 0, &goxel->plane); if (up) { state = STATE_PAINT2; goxel->tool_plane = plane_from_normal(pos, goxel->plane.u); } } if (state == STATE_PAINT2) { goxel_set_help_text(goxel, "Adjust height."); render_plane(&goxel->rend, &goxel->tool_plane, &goxel->grid_color); pos = vec3_add(goxel->tool_plane.p, vec3_project(vec3_sub(pos, goxel->tool_plane.p), goxel->plane.n)); goxel->selection = get_box(&goxel->tool_start_pos, &pos, &normal, 0, &goxel->plane); if (down) { goxel->painting = false; return STATE_WAIT_UP; } } if (state == STATE_WAIT_UP) { goxel->tool_plane = plane_null; goxel->selection = box_get_bbox(goxel->selection); return up ? STATE_IDLE : STATE_WAIT_UP; } if (IS_IN(state, STATE_SNAPED_FACE, STATE_MOVE_FACE)) goxel_set_help_text(goxel, "Drag to move face"); if (state == STATE_SNAPED_FACE) { if (face == -1) return STATE_IDLE; render_img(&goxel->rend, NULL, &face_plane.mat); if (down) { state = STATE_MOVE_FACE; goxel->tool_plane = plane(pos, normal, vec3_normalized(face_plane.u)); } } if (state == STATE_MOVE_FACE) { if (up) return STATE_IDLE; goxel_unproject_on_plane(goxel, view_size, &inputs->mouse_pos, &goxel->tool_plane, &pos, &normal); pos = vec3_add(goxel->tool_plane.p, vec3_project(vec3_sub(pos, goxel->tool_plane.p), vec3_normalized(face_plane.n))); pos.x = round(pos.x); pos.y = round(pos.y); pos.z = round(pos.z); goxel->selection = box_move_face(goxel->selection, goxel->tool_snape_face, pos); } return state; }