void *action_exec(const action_t *action, const arg_t *args) { void *ret = NULL; int i, nb_args; long vals[4]; // So that we do not add undo snapshot when an action calls an other one. static int reentry = 0; // XXX: not sure this is actually legal in C. func will be called with // a variable number or arguments, that might be of any registered types! void *(*func)() = action->func; bool is_void; assert(action); nb_args = action->sig.nb_args; assert(nb_args <= ARRAY_SIZE(vals)); is_void = action->sig.ret == TYPE_VOID; // For the moment all action cancel the current tool, for simplicity. tool_cancel(goxel(), goxel()->tool, goxel()->tool_state); if (reentry == 0 && !(action->flags & ACTION_NO_CHANGE)) { image_history_push(goxel()->image); } reentry++; for (i = 0; i < nb_args; i++) vals[i] = get_arg_value(action->sig.args[i], args); if (is_void && nb_args == 0) func(); else if (is_void && nb_args == 1) func(vals[0]); else if (is_void && nb_args == 2) func(vals[0], vals[1]); else if (is_void && nb_args == 3) func(vals[0], vals[1], vals[2]); else if (is_void && nb_args == 4) func(vals[0], vals[1], vals[2], vals[3]); else if (!is_void && nb_args == 0) ret = func(); else if (!is_void && nb_args == 1) ret = func(vals[0]); else if (!is_void && nb_args == 2) ret = func(vals[0], vals[1]); else if (!is_void && nb_args == 3) ret = func(vals[0], vals[1], vals[2]); else if (!is_void && nb_args == 4) ret = func(vals[0], vals[1], vals[2], vals[3]); else LOG_E("Cannot handle signature for action %s", action->id); reentry--; if (reentry == 0 && !(action->flags & ACTION_NO_CHANGE)) { goxel_update_meshes(goxel(), -1); } return ret; }
static int tool_laser_iter(goxel_t *goxel, const inputs_t *inputs, int state, const vec2_t *view_size, bool inside) { vec3_t pos, normal; box_t box; painter_t painter = goxel->painter; mesh_t *mesh = goxel->image->active_layer->mesh; const bool down = inputs->mouse_down[0]; // XXX: would be nice if we got the vec4_t view instead of view_size, // and why input->pos is not already in win pos? vec4_t view = vec4(0, 0, view_size->x, view_size->y); vec2_t win = inputs->mouse_pos; win.y = view_size->y - win.y; painter.op = OP_SUB; painter.shape = &shape_cylinder; // Create the tool box from the camera along the visible ray. camera_get_ray(&goxel->camera, &win, &view, &pos, &normal); box.mat = mat4_identity; box.w = mat4_mul_vec(mat4_inverted(goxel->camera.view_mat), vec4(1, 0, 0, 0)).xyz; box.h = mat4_mul_vec(mat4_inverted(goxel->camera.view_mat), vec4(0, 1, 0, 0)).xyz; box.d = mat4_mul_vec(mat4_inverted(goxel->camera.view_mat), vec4(0, 0, 1, 0)).xyz; box.d = vec3_neg(normal); box.p = pos; // Just a large value for the size of the laser box. mat4_itranslate(&box.mat, 0, 0, -1024); mat4_iscale(&box.mat, goxel->tool_radius, goxel->tool_radius, 1024); render_box(&goxel->rend, &box, false, NULL, false); if (state == STATE_IDLE) { if (down) { state = STATE_PAINT; image_history_push(goxel->image); } } if (state == STATE_PAINT) { if (!down) { return STATE_IDLE; } mesh_op(mesh, &painter, &box); goxel_update_meshes(goxel, -1); } return state; }
static int tool_laser_iter(goxel_t *goxel, const inputs_t *inputs, int state, const vec2_t *view_size, bool inside) { vec3_t pos, normal; box_t box; painter_t painter = goxel->painter; mesh_t *mesh = goxel->image->active_layer->mesh; const bool down = inputs->mouse_down[0]; painter.op = OP_SUB; painter.shape = &shape_cylinder; // Create the laser box with an inifinity width. goxel_unproject_on_screen(goxel, view_size, &inputs->mouse_pos, &pos, &normal); box.mat = mat4_identity; box.w = mat4_mul_vec(mat4_inverted(goxel->camera.view_mat), vec4(1, 0, 0, 0)).xyz; box.h = mat4_mul_vec(mat4_inverted(goxel->camera.view_mat), vec4(0, 1, 0, 0)).xyz; box.d = mat4_mul_vec(mat4_inverted(goxel->camera.view_mat), vec4(0, 0, 1, 0)).xyz; box.p = pos; mat4_itranslate(&box.mat, 0, 0, -128); mat4_iscale(&box.mat, goxel->tool_radius, goxel->tool_radius, 128); render_box(&goxel->rend, &box, false, NULL, false); if (state == STATE_IDLE) { if (down) state = STATE_PAINT; } if (state == STATE_PAINT) { if (!down) { image_history_push(goxel->image); return STATE_IDLE; } mesh_op(mesh, &painter, &box); goxel_update_meshes(goxel, false); } return state; }
static void do_move(layer_t *layer, const float mat[4][4]) { float m[4][4]; mat4_set_identity(m); // Change referential to the mesh origin. // XXX: maybe this should be done in mesh_move directy?? mat4_itranslate(m, -0.5, -0.5, -0.5); mat4_imul(m, mat); mat4_itranslate(m, +0.5, +0.5, +0.5); if (layer->base_id || layer->image) { mat4_mul(mat, layer->mat, layer->mat); layer->base_mesh_key = 0; } else { mesh_move(layer->mesh, m); if (!box_is_null(layer->box)) { mat4_mul(mat, layer->box, layer->box); box_get_bbox(layer->box, layer->box); } } goxel_update_meshes(goxel, -1); }
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; }
static int tool_brush_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 pressed = down && !goxel->painting; const bool released = !down && goxel->painting; int snaped = 0; vec3_t pos, normal; box_t box; painter_t painter2; mesh_t *mesh = goxel->image->active_layer->mesh; if (inside) snaped = goxel_unproject(goxel, view_size, &inputs->mouse_pos, &pos, &normal); goxel_set_help_text(goxel, "Brush: use shift to draw lines, " "ctrl to pick color"); if (snaped) { if ( snaped == SNAP_MESH && goxel->painter.op == OP_ADD && !goxel->snap_offset) vec3_iadd(&pos, normal); if (goxel->tool == TOOL_BRUSH && goxel->snap_offset) vec3_iaddk(&pos, normal, goxel->snap_offset * goxel->tool_radius); 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 (!inputs->keys[KEY_SHIFT]) mesh_set(&goxel->pick_mesh, goxel->layers_mesh); goxel->tool_last_op.op = 0; // Discard last op. } if (!snaped) return STATE_CANCEL; if (inputs->keys[KEY_SHIFT]) render_line(&goxel->rend, &goxel->tool_start_pos, &pos, NULL); if (check_can_skip(goxel, pos, down, goxel->painter.op)) return state; box = get_box(&pos, NULL, &normal, goxel->tool_radius, NULL); mesh_set(&mesh, goxel->tool_origin_mesh); mesh_op(mesh, &goxel->painter, &box); goxel_update_meshes(goxel, false); if (inputs->keys[KEY_SHIFT]) { render_line(&goxel->rend, &goxel->tool_start_pos, &pos, NULL); if (pressed) { painter2 = goxel->painter; painter2.shape = &shape_cylinder; box = get_box(&goxel->tool_start_pos, &pos, &normal, goxel->tool_radius, NULL); mesh_op(mesh, &painter2, &box); goxel_update_meshes(goxel, false); goxel->tool_start_pos = pos; mesh_set(&goxel->tool_origin_mesh, mesh); } } if (pressed) { mesh_set(&mesh, goxel->tool_origin_mesh); state = STATE_PAINT; goxel->tool_last_op.op = 0; goxel->painting = true; } } if (state == STATE_PAINT) { if (check_can_skip(goxel, pos, down, goxel->painter.op)) return state; if (released) { image_history_push(goxel->image); goxel->painting = false; goxel->last_pos = pos; if (inputs->keys[KEY_SHIFT]) return STATE_WAIT_KEY_UP; mesh_set(&goxel->pick_mesh, goxel->layers_mesh); return STATE_IDLE; } box = get_box(&pos, NULL, &normal, goxel->tool_radius, NULL); mesh_op(mesh, &goxel->painter, &box); goxel_update_meshes(goxel, false); goxel->tool_start_pos = pos; } if (state == STATE_WAIT_KEY_UP) { goxel->tool_t = 0; if (!inputs->keys[KEY_SHIFT]) state = STATE_IDLE; if (snaped) state = STATE_SNAPED; } return state; }