void camera_update(camera_t *camera) { float size; camera->fovy = 20.; if (camera->move_to_target) { camera->move_to_target = !vec3_ilerp_const( &camera->ofs, vec3_neg(camera->target), camera->dist / 128); } // Update the camera mats camera->view_mat = mat4_identity; mat4_itranslate(&camera->view_mat, 0, 0, -camera->dist); mat4_imul_quat(&camera->view_mat, camera->rot); mat4_itranslate(&camera->view_mat, camera->ofs.x, camera->ofs.y, camera->ofs.z); if (camera->ortho) { size = camera->dist; camera->proj_mat = mat4_ortho( -size, +size, -size / camera->aspect, +size / camera->aspect, 0, 1000); } else { camera->proj_mat = mat4_perspective( camera->fovy, camera->aspect, 1, 1000); } }
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; }
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_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; }
void wavefront_export(const mesh_t *mesh, const char *path) { // XXX: Merge faces that can be merged into bigger ones. // Allow to chose between quads or triangles. // Also export mlt file for the colors. block_t *block; voxel_vertex_t* verts; vec3_t v; int nb_quads, i, j; mat4_t mat; FILE *out; const int N = BLOCK_SIZE; UT_array *lines; line_t line, face, *line_ptr; utarray_new(lines, &line_icd); verts = calloc(N * N * N * 6 * 4, sizeof(*verts)); face = (line_t){"f "}; MESH_ITER_BLOCKS(mesh, block) { mat = mat4_identity; mat4_itranslate(&mat, block->pos.x, block->pos.y, block->pos.z); mat4_itranslate(&mat, -N / 2 + 0.5, -N / 2 + 0.5, -N / 2 + 0.5); nb_quads = block_generate_vertices(block->data, 0, verts); for (i = 0; i < nb_quads; i++) { // Put the vertices. for (j = 0; j < 4; j++) { v = vec3(verts[i * 4 + j].pos.x, verts[i * 4 + j].pos.y, verts[i * 4 + j].pos.z); v = mat4_mul_vec3(mat, v); line = (line_t){"v ", .v = v}; face.vs[j] = lines_add(lines, &line); } // Put the normals for (j = 0; j < 4; j++) { v = vec3(verts[i * 4 + j].normal.x, verts[i * 4 + j].normal.y, verts[i * 4 + j].normal.z); line = (line_t){"vn", .vn = v}; face.vns[j] = lines_add(lines, &line); } lines_add(lines, &face); } } out = fopen(path, "w"); fprintf(out, "# Goxel " GOXEL_VERSION_STR "\n"); line_ptr = NULL; while( (line_ptr = (line_t*)utarray_next(lines, line_ptr))) { if (strncmp(line_ptr->type, "v ", 2) == 0) fprintf(out, "v %g %g %g\n", VEC3_SPLIT(line_ptr->v)); } while( (line_ptr = (line_t*)utarray_next(lines, line_ptr))) { if (strncmp(line_ptr->type, "vn", 2) == 0) fprintf(out, "vn %g %g %g\n", VEC3_SPLIT(line_ptr->vn)); } while( (line_ptr = (line_t*)utarray_next(lines, line_ptr))) { if (strncmp(line_ptr->type, "f ", 2) == 0) fprintf(out, "f %d//%d %d//%d %d//%d %d//%d\n", line_ptr->vs[0], line_ptr->vns[0], line_ptr->vs[1], line_ptr->vns[1], line_ptr->vs[2], line_ptr->vns[2], line_ptr->vs[3], line_ptr->vns[3]); } fclose(out); utarray_free(lines); } void ply_export(const mesh_t *mesh, const char *path) { block_t *block; voxel_vertex_t* verts; vec3_t v; uvec3b_t c; int nb_quads, i, j; mat4_t mat; FILE *out; const int N = BLOCK_SIZE; UT_array *lines; line_t line, face, *line_ptr; utarray_new(lines, &line_icd); verts = calloc(N * N * N * 6 * 4, sizeof(*verts)); face = (line_t){"f "}; MESH_ITER_BLOCKS(mesh, block) { mat = mat4_identity; mat4_itranslate(&mat, block->pos.x, block->pos.y, block->pos.z); mat4_itranslate(&mat, -N / 2 + 0.5, -N / 2 + 0.5, -N / 2 + 0.5); nb_quads = block_generate_vertices(block->data, 0, verts); for (i = 0; i < nb_quads; i++) { // Put the vertices. for (j = 0; j < 4; j++) { v = vec3(verts[i * 4 + j].pos.x, verts[i * 4 + j].pos.y, verts[i * 4 + j].pos.z); v = mat4_mul_vec3(mat, v); c = verts[i * 4 + j].color.rgb; line = (line_t){"v ", .v = v, .c = c}; face.vs[j] = lines_add(lines, &line); } // Put the normals for (j = 0; j < 4; j++) { v = vec3(verts[i * 4 + j].normal.x, verts[i * 4 + j].normal.y, verts[i * 4 + j].normal.z); line = (line_t){"vn", .vn = v}; face.vns[j] = lines_add(lines, &line); } lines_add(lines, &face); } } out = fopen(path, "w"); fprintf(out, "ply\n"); fprintf(out, "format ascii 1.0\n"); fprintf(out, "comment Generated from Goxel " GOXEL_VERSION_STR "\n"); fprintf(out, "element vertex %d\n", lines_count(lines, "v ")); fprintf(out, "property float x\n"); fprintf(out, "property float y\n"); fprintf(out, "property float z\n"); fprintf(out, "property uchar red\n"); fprintf(out, "property uchar green\n"); fprintf(out, "property uchar blue\n"); fprintf(out, "element face %d\n", lines_count(lines, "f ")); fprintf(out, "property list uchar int vertex_index\n"); fprintf(out, "end_header\n"); line_ptr = NULL; while( (line_ptr = (line_t*)utarray_next(lines, line_ptr))) { if (strncmp(line_ptr->type, "v ", 2) == 0) fprintf(out, "%g %g %g %d %d %d\n", VEC3_SPLIT(line_ptr->v), VEC3_SPLIT(line_ptr->c)); } while( (line_ptr = (line_t*)utarray_next(lines, line_ptr))) { if (strncmp(line_ptr->type, "f ", 2) == 0) fprintf(out, "4 %d %d %d %d\n", line_ptr->vs[0] - 1, line_ptr->vs[1] - 1, line_ptr->vs[2] - 1, line_ptr->vs[3] - 1); } fclose(out); utarray_free(lines); } static void export_as_obj(goxel_t *goxel, const char *path) { wavefront_export(goxel->layers_mesh, path); }