📄 mesh.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / 3D rendering module * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "mesh.h"#include "visual_surface.h"/*size alloc for meshes doubles memory at each realloc rather than using a fix-size increment (this really speeds up large meshes constructing). Final memory usage is adjusted when updating mesh bounds*/#define MESH_CHECK_VERTEX(m) \ if (m->v_count == m->v_alloc) { \ m->v_alloc *= 2; \ m->vertices = (GF_Vertex *)realloc(m->vertices, sizeof(GF_Vertex)*m->v_alloc); \ } \#define MESH_CHECK_IDX(m) \ if (m->i_count == m->i_alloc) { \ m->i_alloc *= 2; \ m->indices = (IDX_TYPE*)realloc(m->indices, sizeof(IDX_TYPE)*m->i_alloc); \ } \static void del_aabb_node(AABBNode *node){ if (node->pos) del_aabb_node(node->pos); if (node->neg) del_aabb_node(node->neg); free(node);}void mesh_reset(GF_Mesh *mesh){ mesh->v_count = 0; mesh->i_count = 0; mesh->flags = 0; mesh->mesh_type = 0; memset(&mesh->bounds.min_edge, 0, sizeof(SFVec3f)); memset(&mesh->bounds.max_edge, 0, sizeof(SFVec3f)); if (mesh->aabb_root) del_aabb_node(mesh->aabb_root); mesh->aabb_root = NULL; if (mesh->aabb_indices) free(mesh->aabb_indices); mesh->aabb_indices = NULL;}void mesh_free(GF_Mesh *mesh){ if (mesh->vertices) free(mesh->vertices); if (mesh->indices) free(mesh->indices); if (mesh->aabb_root) del_aabb_node(mesh->aabb_root); mesh->aabb_root = NULL; if (mesh->aabb_indices) free(mesh->aabb_indices); free(mesh);}GF_Mesh *new_mesh(){ GF_Mesh *mesh = (GF_Mesh *)malloc(sizeof(GF_Mesh)); if (mesh) { memset(mesh, 0, sizeof(GF_Mesh)); mesh->v_alloc = 8; mesh->vertices = (GF_Vertex*)malloc(sizeof(GF_Vertex)*mesh->v_alloc); mesh->i_alloc = 8; mesh->indices = (IDX_TYPE*)malloc(sizeof(IDX_TYPE)*mesh->i_alloc); } return mesh;}static void mesh_fit_alloc(GF_Mesh *m){ if (m->v_count && (m->v_count < m->v_alloc)) { m->v_alloc = m->v_count; m->vertices = (GF_Vertex *)realloc(m->vertices, sizeof(GF_Vertex)*m->v_alloc); } if (m->i_count && (m->i_count < m->i_alloc)) { m->i_alloc = m->i_count; m->indices = (IDX_TYPE*)realloc(m->indices, sizeof(IDX_TYPE)*m->i_alloc); }}void mesh_update_bounds(GF_Mesh *mesh){ u32 i; Fixed mx, my, mz, Mx, My, Mz; mx = my = mz = FIX_MAX; Mx = My = Mz = FIX_MIN; mesh_fit_alloc(mesh); for (i=0; i<mesh->v_count; i++) { SFVec3f *v = &mesh->vertices[i].pos; if (mx>v->x) mx=v->x; if (my>v->y) my=v->y; if (mz>v->z) mz=v->z; if (Mx<v->x) Mx=v->x; if (My<v->y) My=v->y; if (Mz<v->z) Mz=v->z; } mesh->bounds.min_edge.x = mx; mesh->bounds.min_edge.y = my; mesh->bounds.min_edge.z = mz; mesh->bounds.max_edge.x = Mx; mesh->bounds.max_edge.y = My; mesh->bounds.max_edge.z = Mz; gf_bbox_refresh(&mesh->bounds);}void mesh_clone(GF_Mesh *dest, GF_Mesh *orig){ if (dest->v_alloc<orig->v_alloc) { dest->v_alloc = orig->v_alloc; dest->vertices = (GF_Vertex *)realloc(dest->vertices, sizeof(GF_Vertex)*dest->v_alloc); } dest->v_count = orig->v_count; memcpy(dest->vertices, orig->vertices, sizeof(GF_Vertex)*dest->v_count); if (dest->i_alloc < orig->i_alloc) { dest->i_alloc = orig->i_alloc; dest->indices = (IDX_TYPE*)realloc(dest->indices, sizeof(IDX_TYPE)*dest->i_alloc); } dest->i_count = orig->i_count; memcpy(dest->indices, orig->indices, sizeof(IDX_TYPE)*dest->i_count); dest->mesh_type = orig->mesh_type; dest->flags = orig->flags; dest->bounds = orig->bounds; /*and reset AABB*/ if (dest->aabb_root) del_aabb_node(dest->aabb_root); dest->aabb_root = NULL; if (dest->aabb_indices) free(dest->aabb_indices); dest->aabb_indices = NULL;}static GFINLINE GF_Vertex set_vertex(Fixed x, Fixed y, Fixed z, Fixed nx, Fixed ny, Fixed nz, Fixed u, Fixed v){ GF_Vertex res; res.pos.x = x; res.pos.y = y; res.pos.z = z; res.normal.x = nx; res.normal.y = ny; res.normal.z = nz; gf_vec_norm(&res.normal); res.texcoords.x = u; res.texcoords.y = v; res.color.blue = res.color.red = res.color.green = res.color.alpha = FIX_ONE; return res;}void mesh_set_vertex(GF_Mesh *mesh, Fixed x, Fixed y, Fixed z, Fixed nx, Fixed ny, Fixed nz, Fixed u, Fixed v){ MESH_CHECK_VERTEX(mesh); mesh->vertices[mesh->v_count] = set_vertex(x, y, z, nx, ny, nz, u, v); mesh->v_count++;}void mesh_set_vertex_v(GF_Mesh *mesh, SFVec3f pt, SFVec3f nor, SFVec2f tx, SFColorRGBA col){ MESH_CHECK_VERTEX(mesh); mesh->vertices[mesh->v_count].pos = pt; mesh->vertices[mesh->v_count].texcoords = tx; mesh->vertices[mesh->v_count].color = col; gf_vec_norm(&nor); mesh->vertices[mesh->v_count].normal = nor; mesh->v_count++;}void mesh_set_vertex_vx(GF_Mesh *mesh, GF_Vertex *vx){ MESH_CHECK_VERTEX(mesh); mesh->vertices[mesh->v_count] = *vx; mesh->v_count++;}void mesh_set_point(GF_Mesh *mesh, Fixed x, Fixed y, Fixed z, SFColorRGBA col){ MESH_CHECK_VERTEX(mesh); mesh->vertices[mesh->v_count].pos.x = x; mesh->vertices[mesh->v_count].pos.y = y; mesh->vertices[mesh->v_count].pos.z = z; mesh->vertices[mesh->v_count].normal.x = mesh->vertices[mesh->v_count].normal.y = mesh->vertices[mesh->v_count].normal.z = 0; mesh->vertices[mesh->v_count].texcoords.x = mesh->vertices[mesh->v_count].texcoords.y = 0; mesh->vertices[mesh->v_count].color = col; mesh->v_count++;}void mesh_set_index(GF_Mesh *mesh, u32 idx){ MESH_CHECK_IDX(mesh); mesh->indices[mesh->i_count] = (IDX_TYPE) idx; mesh->i_count++;}void mesh_set_triangle(GF_Mesh *mesh, u32 v1_idx, u32 v2_idx, u32 v3_idx){ mesh_set_index(mesh, v1_idx); mesh_set_index(mesh, v2_idx); mesh_set_index(mesh, v3_idx);}void mesh_set_line(GF_Mesh *mesh, u32 v1_idx, u32 v2_idx){ mesh_set_index(mesh, v1_idx); mesh_set_index(mesh, v2_idx);}void mesh_recompute_normals(GF_Mesh *mesh){ u32 i; if (mesh->mesh_type) return; for (i=0; i<mesh->i_count; i+=3) { SFVec3f v1, v2, v3; gf_vec_diff(v1, mesh->vertices[mesh->indices[i+1]].pos, mesh->vertices[mesh->indices[i]].pos); gf_vec_diff(v2, mesh->vertices[mesh->indices[i+2]].pos, mesh->vertices[mesh->indices[i]].pos); v3 = gf_vec_cross(v1, v2); gf_vec_norm(&v3); mesh->vertices[mesh->indices[i]].normal = v3; mesh->vertices[mesh->indices[i+1]].normal = v3; mesh->vertices[mesh->indices[i+2]].normal = v3; }}void mesh_generate_tex_coords(GF_Mesh *mesh, GF_Node *__texCoords){ u32 i; X_TextureCoordinateGenerator *txgen = (X_TextureCoordinateGenerator *)__texCoords; if (!strcmp(txgen->mode.buffer, "SPHERE-LOCAL")) { for (i=0; i<mesh->v_count; i++) { GF_Vertex *vx = &mesh->vertices[i]; vx->texcoords.x = (vx->normal.x+FIX_ONE) / 2; vx->texcoords.y = (vx->normal.y+FIX_ONE) / 2; } } else if (!strcmp(txgen->mode.buffer, "COORD")) { for (i=0; i<mesh->v_count; i++) { GF_Vertex *vx = &mesh->vertices[i]; vx->texcoords.x = vx->pos.x; vx->texcoords.y = vx->pos.y; } }}void mesh_new_box(GF_Mesh *mesh, SFVec3f size){ Fixed hx = size.x / 2; Fixed hy = size.y / 2; Fixed hz = size.z / 2; mesh_reset(mesh); /*back face (horiz flip of texcoords)*/ mesh_set_vertex(mesh, hx, -hy, -hz, 0, 0, -FIX_ONE, 0, 0); mesh_set_vertex(mesh, -hx, -hy, -hz, 0, 0, -FIX_ONE, FIX_ONE, 0); mesh_set_vertex(mesh, -hx, hy, -hz, 0, 0, -FIX_ONE, FIX_ONE, FIX_ONE); mesh_set_vertex(mesh, hx, hy, -hz, 0, 0, -FIX_ONE, 0, FIX_ONE); mesh_set_triangle(mesh, 0, 1, 2); mesh_set_triangle(mesh, 0, 2, 3); /*top face*/ mesh_set_vertex(mesh, -hx, hy, hz, 0, FIX_ONE, 0, 0, 0); mesh_set_vertex(mesh, hx, hy, hz, 0, FIX_ONE, 0, FIX_ONE, 0); mesh_set_vertex(mesh, hx, hy, -hz, 0, FIX_ONE, 0, FIX_ONE, FIX_ONE); mesh_set_vertex(mesh, -hx, hy, -hz, 0, FIX_ONE, 0, 0, FIX_ONE); mesh_set_triangle(mesh, 4, 5, 6); mesh_set_triangle(mesh, 4, 6, 7); /*front face*/ mesh_set_vertex(mesh, -hx, -hy, hz, 0, 0, FIX_ONE, 0, 0); mesh_set_vertex(mesh, hx, -hy, hz, 0, 0, FIX_ONE, FIX_ONE, 0); mesh_set_vertex(mesh, hx, hy, hz, 0, 0, FIX_ONE, FIX_ONE, FIX_ONE); mesh_set_vertex(mesh, -hx, hy, hz, 0, 0, FIX_ONE, 0, FIX_ONE); mesh_set_triangle(mesh, 8, 9, 10); mesh_set_triangle(mesh, 8, 10, 11); /*left face*/ mesh_set_vertex(mesh, -hx, -hy, -hz, -FIX_ONE, 0, 0, 0, 0); mesh_set_vertex(mesh, -hx, -hy, hz, -FIX_ONE, 0, 0, FIX_ONE, 0); mesh_set_vertex(mesh, -hx, hy, hz, -FIX_ONE, 0, 0, FIX_ONE, FIX_ONE); mesh_set_vertex(mesh, -hx, hy, -hz, -FIX_ONE, 0, 0, 0, FIX_ONE); mesh_set_triangle(mesh, 12, 13, 14); mesh_set_triangle(mesh, 12, 14, 15); /*bottom face*/ mesh_set_vertex(mesh, -hx, -hy, -hz, 0, -FIX_ONE, 0, 0, 0); mesh_set_vertex(mesh, hx, -hy, -hz, 0, -FIX_ONE, 0, FIX_ONE, 0); mesh_set_vertex(mesh, hx, -hy, hz, 0, -FIX_ONE, 0, FIX_ONE, FIX_ONE); mesh_set_vertex(mesh, -hx, -hy, hz, 0, -FIX_ONE, 0, 0, FIX_ONE); mesh_set_triangle(mesh, 16, 17, 18); mesh_set_triangle(mesh, 16, 18, 19); /*right face*/ mesh_set_vertex(mesh, hx, -hy, hz, FIX_ONE, 0, 0, 0, 0); mesh_set_vertex(mesh, hx, -hy, -hz, FIX_ONE, 0, 0, FIX_ONE, 0); mesh_set_vertex(mesh, hx, hy, -hz, FIX_ONE, 0, 0, FIX_ONE, FIX_ONE); mesh_set_vertex(mesh, hx, hy, hz, FIX_ONE, 0, 0, 0, FIX_ONE); mesh_set_triangle(mesh, 20, 21, 22); mesh_set_triangle(mesh, 20, 22, 23); mesh->flags |= MESH_IS_SOLID; mesh->bounds.min_edge.x = -hx; mesh->bounds.min_edge.y = -hy; mesh->bounds.min_edge.z = -hz; mesh->bounds.max_edge.x = hx; mesh->bounds.max_edge.y = hy; mesh->bounds.max_edge.z = hz; gf_bbox_refresh(&mesh->bounds); gf_mesh_build_aabbtree(mesh);}void mesh_new_unit_bbox(GF_Mesh *mesh){ SFColorRGBA col; Fixed s = FIX_ONE/2; memset(&col, 0, sizeof(SFColor)); col.alpha = 1; mesh_reset(mesh); mesh->mesh_type = MESH_LINESET; mesh_set_point(mesh, -s, -s, -s, col); mesh_set_point(mesh, s, -s, -s, col); mesh_set_point(mesh, s, s, -s, col); mesh_set_point(mesh, -s, s, -s, col); mesh_set_point(mesh, -s, -s, s, col); mesh_set_point(mesh, s, -s, s, col); mesh_set_point(mesh, s, s, s, col); mesh_set_point(mesh, -s, s, s, col); mesh_set_line(mesh, 0, 1); mesh_set_line(mesh, 1, 2); mesh_set_line(mesh, 2, 3); mesh_set_line(mesh, 3, 0); mesh_set_line(mesh, 4, 5); mesh_set_line(mesh, 5, 6); mesh_set_line(mesh, 6, 7); mesh_set_line(mesh, 7, 4); mesh_set_line(mesh, 0, 4); mesh_set_line(mesh, 1, 5); mesh_set_line(mesh, 2, 6); mesh_set_line(mesh, 3, 7); gf_bbox_refresh(&mesh->bounds);}static void compute_cylinder(Fixed height, Fixed radius, s32 numFacets, SFVec3f *coords, SFVec2f *texcoords){ Fixed angle, t, u; s32 i; t = height / 2; for (i=0; i<numFacets; ++i) { angle = i*GF_2PI / numFacets - GF_PI2; coords[i].y = t; coords[i].x = gf_mulfix(radius, gf_cos(angle)); coords[i].z = gf_mulfix(radius , gf_sin(angle)); u = FIX_ONE - i*FIX_ONE/numFacets; texcoords[i].x = u; texcoords[i].y = FIX_ONE; }}#define CYLINDER_SUBDIV 24void mesh_new_cylinder(GF_Mesh *mesh, Fixed height, Fixed radius, Bool bottom, Bool side, Bool top, Bool low_res){ u32 nfacets, i, c_idx; SFVec3f *coords; SFVec2f *texcoords; mesh_reset(mesh); if (!bottom && !side && !top) return; nfacets = CYLINDER_SUBDIV; if (low_res) nfacets /= HIGH_SPEED_RATIO; coords = (SFVec3f*) malloc(sizeof(SFVec3f) * nfacets); texcoords = (SFVec2f*)malloc(sizeof(SFVec2f) * nfacets); compute_cylinder(height, radius, nfacets, coords, texcoords); if (side) { for (i=0; i<nfacets; ++i) { /*top*/ mesh_set_vertex(mesh, coords[i].x, coords[i].y, coords[i].z, coords[i].x, 0, coords[i].z, texcoords[i].x, FIX_ONE); /*bottom*/ mesh_set_vertex(mesh, coords[i].x, -1*coords[i].y, coords[i].z, coords[i].x, 0, coords[i].z, texcoords[i].x, 0); /*top circle is counterclockwise, reverse coords*/ if (i) { mesh_set_triangle(mesh, mesh->v_count-4, mesh->v_count-1, mesh->v_count-3); mesh_set_triangle(mesh, mesh->v_count-4, mesh->v_count-2, mesh->v_count-1); } } /*top*/ mesh_set_vertex(mesh, coords[0].x, coords[0].y, coords[0].z, coords[0].x, 0, coords[0].z, texcoords[0].x - FIX_ONE, FIX_ONE); /*bottom*/ mesh_set_vertex(mesh, coords[0].x, -1*coords[0].y, coords[0].z, coords[0].x, 0, coords[0].z, texcoords[0].x - FIX_ONE, 0); mesh_set_triangle(mesh, mesh->v_count-4, mesh->v_count-1, mesh->v_count-3); mesh_set_triangle(mesh, mesh->v_count-4, mesh->v_count-2, mesh->v_count-1); } if (bottom) { Fixed angle = 0; Fixed aincr = GF_2PI / nfacets; mesh_set_vertex(mesh, 0, -height/2, 0, 0, -FIX_ONE, 0, FIX_ONE/2, FIX_ONE/2); c_idx = mesh->v_count-1; for (i=0; i<nfacets; ++i, angle += aincr) { mesh_set_vertex(mesh, coords[i].x, -1*coords[i].y, coords[i].z, 0, -FIX_ONE, 0, (FIX_ONE + gf_sin(angle))/2, FIX_ONE - (FIX_ONE + gf_cos(angle))/2); if (i) mesh_set_triangle(mesh, c_idx, mesh->v_count-2, mesh->v_count-1); } mesh_set_vertex(mesh, coords[0].x, -1*coords[0].y, coords[0].z, 0, -FIX_ONE, 0, (FIX_ONE + gf_sin(angle))/2, FIX_ONE - (FIX_ONE + gf_cos(angle))/2); mesh_set_triangle(mesh, c_idx, mesh->v_count-2, mesh->v_count-1); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -