This source file includes following definitions.
- del_aabb_node
- mesh_reset
- mesh_free
- new_mesh
- mesh_fit_alloc
- mesh_update_bounds
- mesh_clone
- set_vertex
- mesh_set_vertex
- mesh_set_vertex_v
- mesh_set_vertex_vx
- mesh_set_point
- mesh_set_index
- mesh_set_triangle
- mesh_set_line
- mesh_recompute_normals
- mesh_generate_tex_coords
- mesh_new_box
- mesh_new_unit_bbox
- compute_cylinder
- mesh_new_cylinder
- mesh_new_cone
- compute_sphere
- mesh_new_sphere
- mesh_new_rectangle
- mesh_new_ellipse
- mesh_from_path_intern
- mesh_from_path
- mesh_get_outline
- mesh_new_ils
- mesh_new_ps
- register_point_in_face
- register_face_in_point
- smooth_face_normals
- mesh_new_ifs_intern
- mesh_new_ifs2d
- mesh_new_ifs
- mesh_new_elevation_grid
- mesh_extrude_path_intern
- mesh_extrude_path_ext
- mesh_extrude_path
- mesh_new_extrusion
#include <gpac/internal/mesh.h>
#include <gpac/nodes_mpeg4.h>
#include <gpac/nodes_x3d.h>
#include <gpac/color.h>
#ifndef GPAC_DISABLE_3D
#include "gl_inc.h"
#define HIGH_SPEED_RATIO 2
#define MESH_CHECK_VERTEX(m) \
if (m->v_count == m->v_alloc) { \
m->v_alloc *= 2; \
m->vertices = (GF_Vertex *)gf_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*)gf_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);
gf_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) gf_free(mesh->aabb_indices);
mesh->aabb_indices = NULL;
if (mesh->vbo) {
glDeleteBuffers(1, &mesh->vbo);
mesh->vbo = 0;
}
if (mesh->vbo_idx) {
glDeleteBuffers(1, &mesh->vbo_idx);
mesh->vbo_idx = 0;
}
}
void mesh_free(GF_Mesh *mesh)
{
if (mesh->vertices) gf_free(mesh->vertices);
if (mesh->indices) gf_free(mesh->indices);
if (mesh->aabb_root) del_aabb_node(mesh->aabb_root);
mesh->aabb_root = NULL;
if (mesh->aabb_indices) gf_free(mesh->aabb_indices);
gf_free(mesh);
}
GF_Mesh *new_mesh()
{
GF_Mesh *mesh = (GF_Mesh *)gf_malloc(sizeof(GF_Mesh));
if (mesh) {
memset(mesh, 0, sizeof(GF_Mesh));
mesh->v_alloc = 8;
mesh->vertices = (GF_Vertex*)gf_malloc(sizeof(GF_Vertex)*mesh->v_alloc);
mesh->i_alloc = 8;
mesh->indices = (IDX_TYPE*)gf_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 *)gf_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*)gf_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 *)gf_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*)gf_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;
if (dest->aabb_root) del_aabb_node(dest->aabb_root);
dest->aabb_root = NULL;
if (dest->aabb_indices) gf_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)
{
SFVec3f nor;
GF_Vertex res;
res.pos.x = x;
res.pos.y = y;
res.pos.z = z;
nor.x = nx;
nor.y = ny;
nor.z = nz;
gf_vec_norm(&nor);
MESH_SET_NORMAL(res, nor);
res.texcoords.x = u;
res.texcoords.y = v;
#ifdef MESH_USE_SFCOLOR
res.color.blue = res.color.red = res.color.green = res.color.alpha = FIX_ONE;
#else
res.color = 0xFFFFFFFF;
#endif
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)
{
if (!mesh) return;
MESH_CHECK_VERTEX(mesh);
if (!mesh->vertices) return;
mesh->vertices[mesh->v_count].pos = pt;
mesh->vertices[mesh->v_count].texcoords = tx;
mesh->vertices[mesh->v_count].color = MESH_MAKE_COL(col);
gf_vec_norm(&nor);
MESH_SET_NORMAL(mesh->vertices[mesh->v_count], 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 = MESH_MAKE_COL(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_SET_NORMAL(mesh->vertices[mesh->indices[i]], v3);
MESH_SET_NORMAL(mesh->vertices[mesh->indices[i+1]], v3);
MESH_SET_NORMAL(mesh->vertices[mesh->indices[i+2]], v3);
}
}
#if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_X3D)
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;
}
}
}
#endif
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);
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);
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);
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);
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);
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);
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 24
void 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*) gf_malloc(sizeof(SFVec3f) * nfacets);
texcoords = (SFVec2f*)gf_malloc(sizeof(SFVec2f) * nfacets);
compute_cylinder(height, radius, nfacets, coords, texcoords);
if (side) {
for (i=0; i<nfacets; ++i) {
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);
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);
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);
}
}
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);
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);
}
if (top) {
Fixed aincr = GF_2PI / nfacets;
Fixed angle = GF_PI + aincr;
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=nfacets; i>0; --i, angle += aincr) {
mesh_set_vertex(mesh, coords[i - 1].x, coords[i - 1].y, coords[i - 1].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[nfacets - 1].x, coords[nfacets - 1].y, coords[nfacets - 1].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);
}
gf_free(texcoords);
gf_free(coords);
if (top && bottom && side) mesh->flags |= MESH_IS_SOLID;
mesh->bounds.min_edge.x = mesh->bounds.min_edge.z = -radius;
mesh->bounds.max_edge.x = mesh->bounds.max_edge.z = radius;
mesh->bounds.max_edge.y = (side || (top && bottom)) ? height/2 : 0;
mesh->bounds.min_edge.y = -mesh->bounds.max_edge.y;
gf_bbox_refresh(&mesh->bounds);
gf_mesh_build_aabbtree(mesh);
}
#define CONE_SUBDIV 24
void mesh_new_cone(GF_Mesh *mesh, Fixed height, Fixed radius, Bool bottom, Bool side, Bool low_res)
{
u32 nfacets, i, c_idx;
SFVec3f *coords;
SFVec2f *texcoords;
mesh_reset(mesh);
if (!bottom && !side) return;
nfacets = CONE_SUBDIV;
if (low_res) nfacets /= HIGH_SPEED_RATIO;
coords = (SFVec3f*)gf_malloc(sizeof(SFVec3f) * nfacets);
texcoords = (SFVec2f*)gf_malloc(sizeof(SFVec2f) * nfacets);
compute_cylinder(height, radius, nfacets, coords, texcoords);
if (side) {
Fixed Ny = gf_muldiv(radius, radius, height);
for (i = 0; i < nfacets; ++i) {
mesh_set_vertex(mesh, 0, coords[i].y, 0,
coords[i].x, Ny, coords[i].z,
texcoords[i].x, FIX_ONE);
mesh_set_vertex(mesh, coords[i].x, -1*coords[i].y, coords[i].z,
coords[i].x, Ny, coords[i].z,
texcoords[i].x, 0);
if (i) {
mesh_set_triangle(mesh, mesh->v_count-4, mesh->v_count-1, mesh->v_count-3);
}
}
mesh_set_vertex(mesh, 0, coords[0].y, 0, coords[0].x, Ny, coords[0].z, texcoords[0].x - FIX_ONE, FIX_ONE);
mesh_set_vertex(mesh, coords[0].x, -1*coords[0].y, coords[0].z,
coords[0].x, Ny, 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);
}
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);
}
gf_free(texcoords);
gf_free(coords);
if (bottom && side) mesh->flags |= MESH_IS_SOLID;
mesh->bounds.min_edge.x = mesh->bounds.min_edge.z = -radius;
mesh->bounds.max_edge.x = mesh->bounds.max_edge.z = radius;
mesh->bounds.max_edge.y = height/2;
mesh->bounds.min_edge.y = -mesh->bounds.max_edge.y;
gf_bbox_refresh(&mesh->bounds);
gf_mesh_build_aabbtree(mesh);
}
void compute_sphere(Fixed radius, SFVec3f *coords, SFVec2f *texcoords, u32 num_steps, GF_MeshSphereAngles *sphere_angles)
{
Fixed r, angle, x, y, z;
u32 i, j;
for (i=0; i<num_steps; i++) {
if (!sphere_angles) {
angle = (i * GF_PI / (num_steps-1) ) - GF_PI2;
} else {
angle = (i * (sphere_angles->max_phi - sphere_angles->min_phi) / (num_steps-1) ) + sphere_angles->min_phi;
}
y = gf_sin(angle);
r = gf_sqrt(FIX_ONE - gf_mulfix(y, y));
for (j = 0; j<num_steps; j++) {
if (!sphere_angles) {
angle = GF_2PI * j / num_steps - GF_PI2;
} else {
angle = (j * (sphere_angles->max_theta - sphere_angles->min_theta) / (num_steps-1) ) + sphere_angles->min_theta;
}
x = gf_mulfix(gf_cos(angle), r);
z = gf_mulfix(gf_sin(angle), r);
coords[i * num_steps + j].x = gf_mulfix(radius, x);
coords[i * num_steps + j].y = gf_mulfix(radius, y);
coords[i * num_steps + j].z = gf_mulfix(radius, z);
if (radius>0) {
if (!sphere_angles){
texcoords[i * num_steps + j].x = FIX_ONE - j*FIX_ONE/num_steps;
texcoords[i * num_steps + j].y = i*FIX_ONE/num_steps;
}else{
texcoords[i * num_steps + j].x = j*FIX_ONE/(num_steps-1);
texcoords[i * num_steps + j].y = FIX_ONE - i*FIX_ONE/(num_steps-1);
}
}else {
if (!sphere_angles){
texcoords[i * num_steps + j].x = j*FIX_ONE/(num_steps);
texcoords[i * num_steps + j].y = FIX_ONE - i*FIX_ONE/(num_steps);
}else{
texcoords[i * num_steps + j].x = j*FIX_ONE/(num_steps-1);
texcoords[i * num_steps + j].y = FIX_ONE - i*FIX_ONE/(num_steps-1);
}
}
}
}
}
void mesh_new_sphere(GF_Mesh *mesh, Fixed radius, Bool low_res, GF_MeshSphereAngles *sphere_angles)
{
u32 i, j, num_steps, npts;
SFVec3f *coords;
SFVec2f *texcoords;
num_steps = 48;
if (radius<0) num_steps = 72;
if (low_res) num_steps /= 2;
npts = num_steps * num_steps;
coords = (SFVec3f*)gf_malloc(sizeof(SFVec3f)*npts);
texcoords = (SFVec2f*)gf_malloc(sizeof(SFVec2f)*npts);
compute_sphere(radius, coords, texcoords, num_steps, sphere_angles);
for (i=0; i<num_steps-1; i++) {
u32 n = i * num_steps;
Fixed last_tx_coord;
for (j=0; j<num_steps; j++) {
mesh_set_vertex(mesh, coords[n + j + num_steps].x, coords[n + j + num_steps].y, coords[n + j + num_steps].z,
coords[n + j + num_steps].x, coords[n + j + num_steps].y, coords[n + j + num_steps].z,
texcoords[n + j + num_steps].x, texcoords[n + j + num_steps].y);
mesh_set_vertex(mesh, coords[n + j].x, coords[n + j].y, coords[n + j].z,
coords[n + j].x, coords[n + j].y, coords[n + j].z,
texcoords[n + j].x, texcoords[n + j].y);
if (j) {
mesh_set_triangle(mesh, mesh->v_count-3, mesh->v_count-4, mesh->v_count-2);
mesh_set_triangle(mesh, mesh->v_count-3, mesh->v_count-2, mesh->v_count-1);
}
}
if (!sphere_angles) {
last_tx_coord = (radius>0) ? 0 : FIX_ONE;
mesh_set_vertex(mesh, coords[n + num_steps].x, coords[n + num_steps].y, coords[n + num_steps].z,
coords[n + num_steps].x, coords[n + num_steps].y, coords[n + num_steps].z,
last_tx_coord, texcoords[n + num_steps].y);
mesh_set_vertex(mesh, coords[n].x, coords[n].y, coords[n].z,
coords[n].x, coords[n].y, coords[n].z,
last_tx_coord, texcoords[n].y);
mesh_set_triangle(mesh, mesh->v_count-3, mesh->v_count-4, mesh->v_count-2);
mesh_set_triangle(mesh, mesh->v_count-3, mesh->v_count-2, mesh->v_count-1);
}
}
gf_free(coords);
gf_free(texcoords);
if (!sphere_angles) {
mesh->flags |= MESH_IS_SOLID;
}
mesh->bounds.min_edge.x = mesh->bounds.min_edge.y = mesh->bounds.min_edge.z = -radius;
mesh->bounds.max_edge.x = mesh->bounds.max_edge.y = mesh->bounds.max_edge.z = radius;
gf_bbox_refresh(&mesh->bounds);
if (radius != FIX_ONE) gf_mesh_build_aabbtree(mesh);
}
void mesh_new_rectangle(GF_Mesh *mesh, SFVec2f size, SFVec2f *orig, Bool flip)
{
Fixed tmin, tmax;
Fixed x = - size.x / 2;
Fixed y = size.y / 2;
if (orig) {
x = orig->x;
y = orig->y;
}
mesh_reset(mesh);
tmin = flip ? FIX_ONE : 0;
tmax = flip ? 0 : FIX_ONE;
mesh_set_vertex(mesh, x, y-size.y, 0, 0, 0, FIX_ONE, 0, tmin);
mesh_set_vertex(mesh, x+size.x, y-size.y, 0, 0, 0, FIX_ONE, FIX_ONE, tmin);
mesh_set_vertex(mesh, x+size.x, y, 0, 0, 0, FIX_ONE, FIX_ONE, tmax);
mesh_set_vertex(mesh, x, y, 0, 0, 0, FIX_ONE, 0, tmax);
mesh_set_triangle(mesh, 0, 1, 2);
mesh_set_triangle(mesh, 0, 2, 3);
mesh->flags |= MESH_IS_2D;
mesh->bounds.min_edge.x = x;
mesh->bounds.min_edge.y = y-size.y;
mesh->bounds.min_edge.z = 0;
mesh->bounds.max_edge.x = x+size.x;
mesh->bounds.max_edge.y = y;
mesh->bounds.max_edge.z = 0;
gf_bbox_refresh(&mesh->bounds);
}
#define ELLIPSE_SUBDIV 32
void mesh_new_ellipse(GF_Mesh *mesh, Fixed a_dia, Fixed b_dia, Bool low_res)
{
Fixed step, cur, end, cosa, sina;
a_dia /= 2;
b_dia /= 2;
end = GF_2PI;
step = end / ELLIPSE_SUBDIV;
if (low_res) step *= HIGH_SPEED_RATIO;
mesh_reset(mesh);
mesh_set_vertex(mesh, 0, 0, 0, 0, 0, FIX_ONE, FIX_ONE/2, FIX_ONE/2);
for (cur=0; cur<end; cur += step) {
cosa = gf_cos(cur);
sina = gf_sin(cur);
mesh_set_vertex(mesh, gf_mulfix(a_dia, cosa), gf_mulfix(b_dia, sina), 0,
0, 0, FIX_ONE,
(FIX_ONE + cosa)/2, (FIX_ONE + sina)/2);
if (cur) mesh_set_triangle(mesh, 0, mesh->v_count-2, mesh->v_count-1);
}
mesh_set_vertex(mesh, a_dia, 0, 0, 0, 0, FIX_ONE, FIX_ONE, FIX_ONE/2);
mesh_set_triangle(mesh, 0, mesh->v_count-2, mesh->v_count-1);
mesh->flags |= MESH_IS_2D;
mesh->bounds.min_edge.x = -a_dia;
mesh->bounds.min_edge.y = -b_dia;
mesh->bounds.min_edge.z = 0;
mesh->bounds.max_edge.x = a_dia;
mesh->bounds.max_edge.y = b_dia;
mesh->bounds.max_edge.z = 0;
gf_bbox_refresh(&mesh->bounds);
}
void mesh_from_path_intern(GF_Mesh *mesh, GF_Path *path, Bool make_ccw)
{
u32 i, nbPts;
Fixed w, h;
GF_Rect bounds;
Bool isCW = 0;
gf_path_flatten(path);
gf_path_get_bounds(path, &bounds);
mesh_reset(mesh);
if (path->n_contours==1) {
u32 type = gf_polygone2d_get_convexity(path->points, path->n_points);
switch (type) {
case GF_POLYGON_CONVEX_LINE:
return;
case GF_POLYGON_CONVEX_CW:
isCW = make_ccw;
case GF_POLYGON_CONVEX_CCW:
w = bounds.width;
h = bounds.height;
for (i=0; i<path->n_points-1; i++) {
GF_Point2D pt = path->points[i];
mesh_set_vertex(mesh, pt.x, pt.y, 0, 0, 0, FIX_ONE, gf_divfix(pt.x - bounds.x, w), gf_divfix(bounds.y - pt.y, h));
}
nbPts = path->n_points - 1;
if ( (path->points[i].x != path->points[0].x) || (path->points[i].y != path->points[0].y)) {
GF_Point2D pt = path->points[i];
mesh_set_vertex(mesh, pt.x, pt.y, 0, 0, 0, FIX_ONE, gf_divfix(pt.x - bounds.x, w), gf_divfix(bounds.y - pt.y, h));
nbPts = path->n_points;
}
for (i=1; i<nbPts-1; i++) {
if (isCW) {
mesh_set_triangle(mesh, 0, nbPts-i, nbPts-i-1);
} else {
mesh_set_triangle(mesh, 0, i, i+1);
}
}
mesh->bounds.min_edge.x = bounds.x;
mesh->bounds.min_edge.y = bounds.y-bounds.height;
mesh->bounds.min_edge.z = 0;
mesh->bounds.max_edge.x = bounds.x+bounds.width;
mesh->bounds.max_edge.y = bounds.y;
mesh->bounds.max_edge.z = 0;
gf_bbox_refresh(&mesh->bounds);
return;
default:
break;
}
}
#ifdef GPAC_HAS_GLU
gf_mesh_tesselate_path(mesh, path, 0);
#endif
}
void mesh_from_path(GF_Mesh *mesh, GF_Path *path)
{
mesh_from_path_intern(mesh, path, 1);
}
void mesh_get_outline(GF_Mesh *mesh, GF_Path *path)
{
u32 i, j, cur, nb_pts;
mesh_reset(mesh);
mesh->mesh_type = MESH_LINESET;
mesh->flags |= (MESH_IS_2D | MESH_NO_TEXTURE);
gf_path_flatten(path);
cur = 0;
for (i=0; i<path->n_contours; i++) {
nb_pts = 1+path->contours[i] - cur;
for (j=0; j<nb_pts; j++) {
GF_Point2D pt = path->points[j+cur];
if (j) mesh_set_line(mesh, mesh->v_count-1, mesh->v_count);
mesh_set_vertex(mesh, pt.x, pt.y, 0, 0, 0, FIX_ONE, 0, 0);
}
cur += nb_pts;
}
mesh_update_bounds(mesh);
}
#ifndef GPAC_DISABLE_VRML
#define COL_TO_RGBA(res, col) { res.red = col.red; res.green = col.green; res.blue = col.blue; res.alpha = FIX_ONE; }
#define MESH_GET_COL(thecol, index) {\
if (colorRGB && ((u32) index < colorRGB->color.count) ) COL_TO_RGBA(thecol, colorRGB->color.vals[index]) \
else if (colorRGBA && (u32) index < colorRGBA->color.count) thecol = colorRGBA->color.vals[index]; \
} \
void mesh_new_ils(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, GF_Node *__color, MFInt32 *colorIndex, Bool colorPerVertex, Bool do_close)
{
u32 i, n, count, c_count, col_count;
u32 index;
u32 first_idx, last_idx;
Bool move_to;
SFVec3f pt;
SFColorRGBA colRGBA;
Bool has_color, has_coord;
M_Coordinate2D *coord2D = (M_Coordinate2D*) __coord;
M_Coordinate *coord = (M_Coordinate*) __coord;
M_Color *colorRGB = (M_Color *) __color;
#ifndef GPAC_DISABLE_X3D
X_ColorRGBA *colorRGBA = (X_ColorRGBA *) __color;
#endif
if (__coord && (gf_node_get_tag(__coord) == TAG_MPEG4_Coordinate2D)) {
coord = NULL;
} else {
coord2D = NULL;
}
colRGBA.red = colRGBA.green = colRGBA.blue = colRGBA.alpha = 0;
if (!coord2D && !coord) return;
c_count = coord2D ? coord2D->point.count : coord->point.count;
if (!c_count) return;
count = coordIndex->count;
has_coord = count ? 1 : 0;
if (!has_coord) count = c_count;
if (!colorIndex->vals) colorIndex = coordIndex;
col_count = colorIndex->count ? colorIndex->count : c_count;
if (colorPerVertex && (col_count<count) ) {
colorIndex = coordIndex;
col_count = count;
}
has_color = 0;
if (__color) {
#ifndef GPAC_DISABLE_X3D
if (gf_node_get_tag(__color)==TAG_X3D_ColorRGBA) {
colorRGB = NULL;
has_color = (colorRGBA->color.count) ? 1 : 0;
} else
#endif
{
#ifndef GPAC_DISABLE_X3D
colorRGBA = NULL;
#endif
has_color = (colorRGB->color.count) ? 1 : 0;
}
}
mesh_reset(mesh);
mesh->mesh_type = MESH_LINESET;
if (has_color) mesh->flags |= MESH_HAS_COLOR;
n = 0;
if (has_color && !colorPerVertex) {
index = colorIndex->count ? colorIndex->vals[0] : 0;
#ifndef GPAC_DISABLE_X3D
if ((u32) index < col_count) MESH_GET_COL(colRGBA, index);
#endif
}
move_to = 1;
first_idx = last_idx = 0;
for (i=0; i<count; i++) {
if (has_coord && coordIndex->vals[i] == -1) {
if (!move_to && do_close && !gf_vec_equal(mesh->vertices[first_idx].pos, mesh->vertices[last_idx].pos) ) {
mesh_set_line(mesh, last_idx, first_idx);
}
move_to = 1;
n++;
if (has_color && !colorPerVertex) {
if (n<colorIndex->count) index = colorIndex->vals[n];
else if (n<col_count) index = n;
else index = 0;
#ifndef GPAC_DISABLE_X3D
MESH_GET_COL(colRGBA, index);
#endif
}
} else {
if (has_color && colorPerVertex) {
if (i<colorIndex->count) index = colorIndex->vals[i];
else if (i<col_count) index = i;
else index=0;
#ifndef GPAC_DISABLE_X3D
MESH_GET_COL(colRGBA, index);
#endif
}
if (has_coord) index = coordIndex->vals[i];
else index = i;
if (index < c_count) {
if (coord2D) {
pt.x = coord2D->point.vals[index].x;
pt.y = coord2D->point.vals[index].y;
pt.z = 0;
} else {
pt = coord->point.vals[index];
}
mesh_set_point(mesh, pt.x, pt.y, pt.z, colRGBA);
last_idx = mesh->v_count - 1;
if (move_to) {
first_idx = last_idx;
move_to = 0;
} else {
mesh_set_line(mesh, last_idx-1, last_idx);
}
}
}
}
if (do_close && !gf_vec_equal(mesh->vertices[first_idx].pos, mesh->vertices[last_idx].pos) ) {
mesh_set_line(mesh, last_idx, first_idx);
}
if (coord2D) mesh->flags |= MESH_IS_2D;
#ifndef GPAC_DISABLE_X3D
if (colorRGBA) mesh->flags |= MESH_HAS_ALPHA;
#endif
mesh_update_bounds(mesh);
}
void mesh_new_ps(GF_Mesh *mesh, GF_Node *__coord, GF_Node *__color)
{
u32 c_count, i;
Bool has_color;
SFVec3f pt;
SFColorRGBA colRGBA;
M_Coordinate2D *coord2D = (M_Coordinate2D*) __coord;
M_Coordinate *coord = (M_Coordinate*) __coord;
M_Color *colorRGB = (M_Color *) __color;
#ifndef GPAC_DISABLE_X3D
X_ColorRGBA *colorRGBA = (X_ColorRGBA *) __color;
#endif
if (__coord && (gf_node_get_tag(__coord) == TAG_MPEG4_Coordinate2D)) {
coord = NULL;
} else {
coord2D = NULL;
}
if (!coord2D && !coord) return;
c_count = coord2D ? coord2D->point.count : coord->point.count;
if (!c_count) return;
mesh_reset(mesh);
mesh->mesh_type = MESH_POINTSET;
has_color = 0;
if (__color) {
#ifndef GPAC_DISABLE_X3D
if (gf_node_get_tag(__color)==TAG_X3D_ColorRGBA) {
colorRGB = NULL;
has_color = (colorRGBA->color.count) ? 1 : 0;
} else
#endif
{
#ifndef GPAC_DISABLE_X3D
colorRGBA = NULL;
#endif
has_color = (colorRGB->color.count) ? 1 : 0;
}
}
if (has_color) mesh->flags |= MESH_HAS_COLOR;
colRGBA.red = colRGBA.green = colRGBA.blue = colRGBA.alpha = FIX_ONE;
for (i=0; i<c_count; ++i) {
#ifndef GPAC_DISABLE_X3D
if (has_color) MESH_GET_COL(colRGBA, i);
#endif
if (coord2D) {
pt.x = coord2D->point.vals[i].x;
pt.y = coord2D->point.vals[i].y;
pt.z = 0;
} else {
pt = coord->point.vals[i];
}
mesh_set_point(mesh, pt.x, pt.y, pt.z, colRGBA);
mesh_set_index(mesh, mesh->v_count-1);
}
mesh_update_bounds(mesh);
}
struct face_info
{
SFVec3f nor;
u32 idx_alloc;
u32 idx_count;
u32 *idx;
};
struct pt_info
{
u32 face_alloc;
u32 face_count;
u32 *faces;
};
void register_point_in_face(struct face_info *fi, u32 pt_index)
{
if (fi->idx_count==fi->idx_alloc) {
fi->idx_alloc += 10;
fi->idx = (u32*)gf_realloc(fi->idx, sizeof(u32)*fi->idx_alloc);
}
fi->idx[fi->idx_count] = pt_index;
fi->idx_count++;
}
void register_face_in_point(struct pt_info *pi, u32 face_index)
{
if (pi->face_count==pi->face_alloc) {
pi->face_alloc += 10;
pi->faces = (u32*)gf_realloc(pi->faces, sizeof(u32)*pi->face_alloc);
}
pi->faces[pi->face_count] = face_index;
pi->face_count++;
}
static GFINLINE SFVec3f smooth_face_normals(struct pt_info *pts, u32 nb_pts, struct face_info *faces, u32 nb_faces,
u32 pt_idx_in_face, u32 face_idx, Fixed creaseAngleCos)
{
u32 i=0;
SFVec3f nor;
struct face_info *fi = &faces[face_idx];
struct pt_info *pi = &pts[fi->idx[pt_idx_in_face]];
nor = fi->nor;
for (i=0; i<pi->face_count; i++) {
if (pi->faces[i]==face_idx) continue;
if (gf_vec_dot(fi->nor, faces[pi->faces[i]].nor) > creaseAngleCos) {
gf_vec_add(nor, nor, faces[pi->faces[i]].nor);
}
}
gf_vec_norm(&nor);
return nor;
}
#define GET_IDX(idx, array) \
if (idx<array->count && (array->vals[idx]>=0) ) index = array->vals[idx]; \
else if (idx<c_count) index = idx; \
else index = 0; \
void mesh_new_ifs_intern(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex,
GF_Node *__color, MFInt32 *colorIndex, Bool colorPerVertex,
GF_Node *__normal, MFInt32 *normalIndex, Bool normalPerVertex,
GF_Node *__texCoords, MFInt32 *texCoordIndex,
Fixed creaseAngle)
{
u32 i, n, count, c_count, nor_count;
u32 index;
Bool smooth_normals;
SFVec2f tx;
u32 s_axis, t_axis;
SFVec3f pt, nor, bounds, center;
SFColorRGBA colRGBA;
Bool has_color, has_coord, has_normal, has_tex, gen_tex_coords;
GF_Mesh **faces;
struct face_info *faces_info;
struct pt_info *pts_info;
u32 face_count, cur_face;
M_Coordinate2D *coord2D = (M_Coordinate2D*) __coord;
M_Coordinate *coord = (M_Coordinate*) __coord;
M_Color *colorRGB = (M_Color *) __color;
#ifndef GPAC_DISABLE_X3D
X_ColorRGBA *colorRGBA = (X_ColorRGBA *) __color;
#endif
M_Normal *normal = (M_Normal*) __normal;
M_TextureCoordinate *txcoord = (M_TextureCoordinate*) __texCoords;
nor.x = nor.y = nor.z = 0;
center = pt = bounds = nor;
tx.x = tx.y = 0;
if (__coord && (gf_node_get_tag(__coord) == TAG_MPEG4_Coordinate2D)) {
coord = NULL;
} else {
coord2D = NULL;
if (!__coord)
return;
#ifndef GPAC_DISABLE_X3D
if (gf_node_get_tag(__coord) == TAG_X3D_CoordinateDouble)
return;
#endif
}
gen_tex_coords = 0;
#ifndef GPAC_DISABLE_X3D
if (__texCoords && (gf_node_get_tag(__texCoords)==TAG_X3D_TextureCoordinateGenerator)) {
gen_tex_coords = 1;
txcoord = NULL;
}
#endif
if (!coord2D && !coord) return;
c_count = coord2D ? coord2D->point.count : coord->point.count;
if (!c_count) return;
if (normal && normalIndex) {
if (!normalIndex->vals) normalIndex = coordIndex;
nor_count = normalIndex->count ? normalIndex->count : c_count;
has_normal = normal->vector.count ? 1 : 0;
} else {
nor_count = 0;
nor.x = nor.y = 0;
nor.z = FIX_ONE;
has_normal = 0;
}
has_tex = txcoord ? 1 : 0;
if (has_tex && !texCoordIndex->vals) texCoordIndex = coordIndex;
mesh_reset(mesh);
memset(&colRGBA, 0, sizeof(SFColorRGBA));
s_axis = t_axis = 0;
if (!has_tex) {
for (i=0; i<c_count; i++) {
if (coord2D) mesh_set_point(mesh, coord2D->point.vals[i].x, coord2D->point.vals[i].y, 0, colRGBA);
else mesh_set_point(mesh, coord->point.vals[i].x, coord->point.vals[i].y, coord->point.vals[i].z, colRGBA);
}
mesh_update_bounds(mesh);
gf_vec_diff(bounds, mesh->bounds.max_edge, mesh->bounds.min_edge);
center = mesh->bounds.min_edge;
if ( (bounds.x >= bounds.y) && (bounds.x >= bounds.z) ) {
s_axis = 0;
t_axis = (bounds.y >= bounds.z) ? 1 : 2;
}
else if ( (bounds.y >= bounds.x) && (bounds.y >= bounds.z) ) {
s_axis = 1;
t_axis = (bounds.x >= bounds.z) ? 0 : 2;
}
else {
s_axis = 2;
t_axis = (bounds.x >= bounds.y) ? 0 : 1;
}
}
has_color = 0;
if (__color) {
#ifndef GPAC_DISABLE_X3D
if (gf_node_get_tag(__color)==TAG_X3D_ColorRGBA) {
colorRGB = NULL;
has_color = (colorRGBA->color.count) ? 1 : 0;
} else
#endif
{
#ifndef GPAC_DISABLE_X3D
colorRGBA = NULL;
#endif
has_color = (colorRGB->color.count) ? 1 : 0;
}
}
n = 0;
if (has_color) {
if (!colorPerVertex) {
index = colorIndex->count ? colorIndex->vals[0] : 0;
#ifndef GPAC_DISABLE_X3D
MESH_GET_COL(colRGBA, index);
#endif
} else {
if (!colorIndex->vals) colorIndex = coordIndex;
}
}
if (has_normal && !normalPerVertex) {
index = normalIndex->count ? normalIndex->vals[0] : 0;
if (index < nor_count) nor = normal->vector.vals[index];
}
count = coordIndex->count;
has_coord = count ? 1 : 0;
if (!has_coord) count = c_count;
smooth_normals = (!has_normal && coord && (creaseAngle > FIX_EPSILON)) ? 1 : 0;
if (!has_coord) {
face_count = 1;
} else {
face_count = 0;
for (i=0; i<count; i++) {
if (coordIndex->vals[i] == -1) face_count++;
}
if (coordIndex->vals[count-1] != -1) face_count++;
}
faces = (GF_Mesh**)gf_malloc(sizeof(GF_Mesh *)*face_count);
for (i=0; i<face_count; i++) {
faces[i] = new_mesh();
if (coord2D) faces[i]->flags = MESH_IS_2D;
}
faces_info = NULL;
pts_info = NULL;
if (smooth_normals) {
faces_info = (struct face_info*)gf_malloc(sizeof(struct face_info)*face_count);
memset(faces_info, 0, sizeof(struct face_info)*face_count);
pts_info = (struct pt_info*)gf_malloc(sizeof(struct pt_info)*c_count);
memset(pts_info, 0, sizeof(struct pt_info)*c_count);
}
cur_face = 0;
for (i=0; i<count; i++) {
if (has_coord && coordIndex->vals[i] == -1) {
n++;
if (has_color && !colorPerVertex) {
GET_IDX(n, colorIndex);
#ifndef GPAC_DISABLE_X3D
MESH_GET_COL(colRGBA, index);
#endif
}
if (has_normal && !normalPerVertex) {
GET_IDX(n, normalIndex);
if (index < nor_count) nor = normal->vector.vals[index];
}
if (faces[cur_face]->v_count<3) faces[cur_face]->v_count=0;
else if (smooth_normals) {
SFVec3f v1, v2, fn;
u32 k=2;
gf_vec_diff(v1, faces[cur_face]->vertices[1].pos, faces[cur_face]->vertices[0].pos);
while (k<faces[cur_face]->v_count) {
gf_vec_diff(v2, faces[cur_face]->vertices[k].pos, faces[cur_face]->vertices[0].pos);
fn = gf_vec_cross(v1, v2);
if (gf_vec_len(fn)) {
gf_vec_norm(&fn);
faces_info[cur_face].nor = fn;
break;
}
k++;
}
}
cur_face++;
} else {
if (has_color && colorPerVertex) {
GET_IDX(i, colorIndex);
#ifndef GPAC_DISABLE_X3D
MESH_GET_COL(colRGBA, index);
#endif
}
if (has_normal && normalPerVertex) {
GET_IDX(i, normalIndex);
if (index < normal->vector.count) {
nor = normal->vector.vals[index];
}
}
if (has_coord) index = coordIndex->vals[i];
else index = i;
if (index < c_count) {
if (coord2D) {
pt.x = coord2D->point.vals[index].x;
pt.y = coord2D->point.vals[index].y;
pt.z = 0;
} else {
pt = coord->point.vals[index];
}
if (smooth_normals) {
register_point_in_face(&faces_info[cur_face], index);
register_face_in_point(&pts_info[index], cur_face);
}
}
if (has_tex) {
GET_IDX(i, texCoordIndex);
if (index < txcoord->point.count) tx = txcoord->point.vals[index];
} else {
SFVec3f v;
gf_vec_diff(v, pt, center);
tx.x = tx.y = 0;
if (s_axis==0) tx.x = gf_divfix(v.x, bounds.x);
else if (s_axis==1) tx.x = gf_divfix(v.y, bounds.y);
else if (s_axis==2) tx.x = gf_divfix(v.z, bounds.z);
if (t_axis==0) tx.y = gf_divfix(v.x, bounds.x);
else if (t_axis==1) tx.y = gf_divfix(v.y, bounds.y);
else if (t_axis==2) tx.y = gf_divfix(v.z, bounds.z);
}
mesh_set_vertex_v(faces[cur_face], pt, nor, tx, colRGBA);
}
}
if (!has_normal && coord) {
u32 j;
if (smooth_normals) {
Fixed cosCrease;
if (creaseAngle>GF_PI) cosCrease = -FIX_ONE;
else cosCrease = gf_cos(creaseAngle);
for (i=0; i<face_count; i++) {
for (j=0; j<faces[i]->v_count; j++) {
SFVec3f n = smooth_face_normals(pts_info, c_count, faces_info, face_count, j, i, cosCrease);
MESH_SET_NORMAL(faces[i]->vertices[j], n);
}
}
if (faces_info) {
for (i=0; i<face_count; i++) if (faces_info[i].idx) gf_free(faces_info[i].idx);
gf_free(faces_info);
}
if (pts_info) {
for (i=0; i<c_count; i++) if (pts_info[i].faces) gf_free(pts_info[i].faces);
gf_free(pts_info);
}
mesh->flags |= MESH_IS_SMOOTHED;
} else {
for (i=0; i<face_count; i++) {
SFVec3f v1, v2, n;
if (! faces[i] || ! faces[i]->vertices) continue;
gf_vec_diff(v1, faces[i]->vertices[1].pos, faces[i]->vertices[0].pos);
gf_vec_diff(v2, faces[i]->vertices[2].pos, faces[i]->vertices[0].pos);
n = gf_vec_cross(v1, v2);
if (!n.x && !n.y && !n.z) n.z = FIX_ONE;
else gf_vec_norm(&n);
for (j=0; j<faces[i]->v_count; j++)
MESH_SET_NORMAL(faces[i]->vertices[j], n);
}
}
}
mesh_reset(mesh);
mesh->mesh_type = MESH_TRIANGLES;
if (has_color) mesh->flags |= MESH_HAS_COLOR;
for (i=0; i<face_count; i++) {
if (! faces[i]) continue;
if (faces[i]->v_count) TesselateFaceMesh(mesh, faces[i]);
mesh_free(faces[i]);
}
gf_free(faces);
mesh_update_bounds(mesh);
if (!coord2D) gf_mesh_build_aabbtree(mesh);
#ifndef GPAC_DISABLE_X3D
if (colorRGBA) mesh->flags |= MESH_HAS_ALPHA;
if (gen_tex_coords) mesh_generate_tex_coords(mesh, __texCoords);
#endif
}
void mesh_new_ifs2d(GF_Mesh *mesh, GF_Node *node)
{
M_IndexedFaceSet2D *ifs2D = (M_IndexedFaceSet2D *)node;
mesh_new_ifs_intern(mesh, ifs2D->coord, &ifs2D->coordIndex,
ifs2D->color, &ifs2D->colorIndex, ifs2D->colorPerVertex,
NULL, NULL, 0, ifs2D->texCoord, &ifs2D->texCoordIndex, 0);
mesh->flags |= MESH_IS_2D;
}
void mesh_new_ifs(GF_Mesh *mesh, GF_Node *node)
{
M_IndexedFaceSet *ifs = (M_IndexedFaceSet *)node;
mesh_new_ifs_intern(mesh, ifs->coord, &ifs->coordIndex, ifs->color, &ifs->colorIndex, ifs->colorPerVertex,
ifs->normal, &ifs->normalIndex, ifs->normalPerVertex, ifs->texCoord, &ifs->texCoordIndex, ifs->creaseAngle);
if (ifs->solid) mesh->flags |= MESH_IS_SOLID;
if (!ifs->ccw) mesh->flags |= MESH_IS_CW;
}
void mesh_new_elevation_grid(GF_Mesh *mesh, GF_Node *node)
{
u32 i, j, face_count, pt_count, zDimension, xDimension, cur_face, idx, pt_idx;
Bool has_normal, has_txcoord, has_color, smooth_normals;
GF_Mesh **faces;
GF_Vertex vx;
SFVec3f v1, v2, n;
struct face_info *faces_info;
struct pt_info *pts_info;
M_ElevationGrid *eg = (M_ElevationGrid *) node;
M_Normal *norm = (M_Normal *)eg->normal;
M_Color *colorRGB = (M_Color *)eg->color;
#ifndef GPAC_DISABLE_X3D
X_ColorRGBA *colorRGBA = (X_ColorRGBA *)eg->color;
#endif
SFColorRGBA rgba;
M_TextureCoordinate *txc = (M_TextureCoordinate *)eg->texCoord;
mesh_reset(mesh);
if (!eg->height.count || (eg->xDimension<2) || (eg->zDimension<2)) return;
memset(&vx, 0, sizeof(GF_Vertex));
memset(&rgba, 0, sizeof(SFColorRGBA));
has_txcoord = txc ? txc->point.count : 0;
has_normal = norm ? norm->vector.count : 0;
has_color = 0;
if (eg->color) {
#ifndef GPAC_DISABLE_X3D
if (gf_node_get_tag(eg->color)==TAG_X3D_ColorRGBA) {
colorRGB = NULL;
has_color = colorRGBA->color.count ? 1 : 0;
} else
#endif
{
#ifndef GPAC_DISABLE_X3D
colorRGBA = NULL;
#endif
has_color = colorRGB->color.count ? 1 : 0;
}
}
face_count = (eg->xDimension-1) * (eg->zDimension-1);
pt_count = eg->xDimension * eg->zDimension;
if (pt_count>eg->height.count) return;
smooth_normals = (!has_normal && (eg->creaseAngle > FIX_EPSILON)) ? 1 : 0;
faces = NULL;
faces_info = NULL;
pts_info = NULL;
zDimension = (u32) eg->zDimension;
xDimension = (u32) eg->xDimension;
cur_face = 0;
pt_idx = 0;
if (!smooth_normals && !has_color && !has_normal && !has_txcoord) {
for (j=0; j<zDimension; j++) {
for (i=0; i<xDimension; i++) {
vx.pos.z = eg->zSpacing * j;
vx.pos.y = eg->height.vals[i +j*xDimension];
vx.pos.x = eg->xSpacing * i;
vx.texcoords.x = INT2FIX(i) / (xDimension - 1);
vx.texcoords.y = INT2FIX(j) / (zDimension - 1);
mesh_set_vertex_vx(mesh, &vx);
}
}
for (j=0; j<zDimension-1; j++) {
u32 z0 = (j)*xDimension;
u32 z1 = (j+1)*xDimension;
for (i=0; i<xDimension-1; i++) {
mesh_set_triangle(mesh, i+z0, i+z1, i+z1+1);
mesh_set_triangle(mesh, i+z0, i+z1+1, i+z0+1);
gf_vec_diff(v1, mesh->vertices[i+z0].pos, mesh->vertices[i+z0+1].pos);
gf_vec_diff(v2, mesh->vertices[i+z1+1].pos, mesh->vertices[i+z0+1].pos);
n = gf_vec_cross(v1, v2);
gf_vec_norm(&n);
MESH_SET_NORMAL(mesh->vertices[i+z0], n);
MESH_SET_NORMAL(mesh->vertices[i+z0+1], n);
MESH_SET_NORMAL(mesh->vertices[i+z1], n);
MESH_SET_NORMAL(mesh->vertices[i+z1+1], n);
}
}
mesh->mesh_type = MESH_TRIANGLES;
mesh_update_bounds(mesh);
if (!eg->ccw) mesh->flags |= MESH_IS_CW;
if (eg->solid) mesh->flags |= MESH_IS_SOLID;
gf_mesh_build_aabbtree(mesh);
return;
}
if (smooth_normals) {
faces = (GF_Mesh **)gf_malloc(sizeof(GF_Mesh *)*face_count);
faces_info = (struct face_info*)gf_malloc(sizeof(struct face_info)*face_count);
memset(faces_info, 0, sizeof(struct face_info)*face_count);
pts_info = (struct pt_info*)gf_malloc(sizeof(struct pt_info)*pt_count);
memset(pts_info, 0, sizeof(struct pt_info)*pt_count);
faces[cur_face] = new_mesh();
}
for (j=0; j<zDimension-1; j++) {
for (i = 0; i < xDimension-1; i++) {
u32 k, l;
if (has_color && !eg->colorPerVertex) {
idx = i + j * (xDimension-1);
#ifndef GPAC_DISABLE_X3D
MESH_GET_COL(rgba, idx);
#endif
vx.color = MESH_MAKE_COL(rgba);
}
if (has_normal && !eg->normalPerVertex) {
idx = i + j * (xDimension-1);
if (idx<norm->vector.count) {
SFVec3f n = norm->vector.vals[idx];
gf_vec_norm(&n);
MESH_SET_NORMAL(vx, n);
}
}
for (k=0; k<2; k++) {
vx.pos.z = eg->zSpacing * (j+k);
for (l=0; l<2; l++) {
vx.pos.y = eg->height.vals[(i+l) +(j+k)*xDimension];
vx.pos.x = eg->xSpacing * (i+l);
if (has_color && eg->colorPerVertex) {
idx = i+l + (j+k) * xDimension;
#ifndef GPAC_DISABLE_X3D
MESH_GET_COL(rgba, idx);
#endif
vx.color = MESH_MAKE_COL(rgba);
}
if (!has_txcoord) {
vx.texcoords.x = INT2FIX(i+l) / (xDimension - 1);
vx.texcoords.y = INT2FIX(j+k) / (zDimension - 1);
} else {
idx = (i+l) +(j+k)*xDimension;
if (idx<txc->point.count) vx.texcoords = txc->point.vals[idx];
}
if (has_normal && eg->normalPerVertex) {
idx = (i+l) + (j+k) * xDimension;
if (idx<norm->vector.count) {
SFVec3f n = norm->vector.vals[idx];
gf_vec_norm(&n);
MESH_SET_NORMAL(vx, n);
}
}
if (smooth_normals) {
mesh_set_vertex_vx(faces[cur_face], &vx);
register_point_in_face(&faces_info[cur_face], (i+l) + (j+k)*xDimension);
register_face_in_point(&pts_info[(i+l) + (j+k)*xDimension], cur_face);
} else {
mesh_set_vertex_vx(mesh, &vx);
}
}
}
if (smooth_normals) {
mesh_set_triangle(faces[cur_face], 0, 2, 3);
mesh_set_triangle(faces[cur_face], 0, 3, 1);
gf_vec_diff(v1, faces[cur_face]->vertices[0].pos, faces[cur_face]->vertices[1].pos);
gf_vec_diff(v2, faces[cur_face]->vertices[3].pos, faces[cur_face]->vertices[1].pos);
faces_info[cur_face].nor = gf_vec_cross(v1, v2);
gf_vec_norm(&faces_info[cur_face].nor);
cur_face++;
if (cur_face<face_count) faces[cur_face] = new_mesh();
} else {
mesh_set_triangle(mesh, pt_idx+0, pt_idx+2, pt_idx+3);
mesh_set_triangle(mesh, pt_idx+0, pt_idx+3, pt_idx+1);
if (!has_normal) {
gf_vec_diff(v1, mesh->vertices[pt_idx+0].pos, mesh->vertices[pt_idx+1].pos);
gf_vec_diff(v2, mesh->vertices[pt_idx+3].pos, mesh->vertices[pt_idx+1].pos);
n = gf_vec_cross(v1, v2);
gf_vec_norm(&n);
MESH_SET_NORMAL(mesh->vertices[pt_idx+0], n);
MESH_SET_NORMAL(mesh->vertices[pt_idx+1], n);
MESH_SET_NORMAL(mesh->vertices[pt_idx+2], n);
MESH_SET_NORMAL(mesh->vertices[pt_idx+3], n);
}
pt_idx+=4;
}
}
}
if (smooth_normals) {
Fixed cosCrease;
if (eg->creaseAngle>GF_PI) cosCrease = -FIX_ONE;
else cosCrease = gf_cos(eg->creaseAngle);
for (i=0; i<face_count; i++) {
for (j=0; j<faces[i]->v_count; j++) {
SFVec3f n = smooth_face_normals(pts_info, pt_count, faces_info, face_count, j, i, cosCrease);
MESH_SET_NORMAL(faces[i]->vertices[j], n);
}
}
if (faces_info) {
for (i=0; i<face_count; i++) if (faces_info[i].idx) gf_free(faces_info[i].idx);
gf_free(faces_info);
}
if (pts_info) {
for (i=0; i<pt_count; i++) if (pts_info[i].faces) gf_free(pts_info[i].faces);
gf_free(pts_info);
}
mesh->flags |= MESH_IS_SMOOTHED;
for (i=0; i<face_count; i++) {
if (faces[i]->v_count) {
u32 init_idx;
GF_Mesh *face = faces[i];
init_idx = mesh->v_count;
mesh_set_vertex_vx(mesh, &face->vertices[0]);
mesh_set_vertex_vx(mesh, &face->vertices[1]);
mesh_set_vertex_vx(mesh, &face->vertices[2]);
mesh_set_vertex_vx(mesh, &face->vertices[3]);
mesh_set_triangle(mesh, init_idx, init_idx + 2, init_idx + 3);
mesh_set_triangle(mesh, init_idx, init_idx + 3, init_idx + 1);
}
mesh_free(faces[i]);
}
gf_free(faces);
}
mesh->mesh_type = MESH_TRIANGLES;
if (has_color) mesh->flags |= MESH_HAS_COLOR;
mesh_update_bounds(mesh);
if (!eg->ccw) mesh->flags |= MESH_IS_CW;
if (eg->solid) mesh->flags |= MESH_IS_SOLID;
#ifndef GPAC_DISABLE_X3D
if (colorRGBA) mesh->flags |= MESH_HAS_ALPHA;
#endif
gf_mesh_build_aabbtree(mesh);
}
typedef struct
{
SFVec3f yaxis, zaxis, xaxis;
} SCP;
typedef struct
{
SFVec3f pt, yaxis, zaxis, xaxis;
u32 max_idx;
} SCPInfo;
#define REGISTER_POINT_FACE(FACE_IDX) \
{ u32 fidx; \
fidx = FACE_IDX; \
mesh_set_vertex_vx(faces[fidx], &vx); \
if (smooth_normals) { \
register_point_in_face(&faces_info[fidx], pidx); \
register_face_in_point(&pts_info[pidx], fidx); \
} \
} \
#define NEAR_ZERO(__x) (ABS(__x)<=FIX_EPSILON)
static void mesh_extrude_path_intern(GF_Mesh *mesh, GF_Path *path, MFVec3f *thespine, Fixed creaseAngle, Fixed min_cx, Fixed min_cy, Fixed width_cx, Fixed width_cy, Bool begin_cap, Bool end_cap, MFRotation *spine_ori, MFVec2f *spine_scale, Bool tx_along_spine)
{
GF_Mesh **faces;
GF_Vertex vx;
struct face_info *faces_info;
struct pt_info *pts_info;
GF_Matrix mx;
SCP *SCPs, SCPbegin, SCPend;
SCPInfo *SCPi;
Bool smooth_normals, spine_closed, check_first_spine_vec, do_close;
u32 i, j, k, nb_scp, nb_spine, face_count, pt_count, faces_per_cross, begin_face, end_face, face_spines, pts_per_cross, cur_pts_in_cross,cur, nb_pts, convexity;
SFVec3f *spine, v1, v2, n, spine_vec;
Fixed cross_len, spine_len, cur_cross, cur_spine;
SFRotation r;
SFVec2f scale;
if (!path->n_contours) return;
if (path->n_points<2) return;
if (thespine->count<2) return;
spine_closed = 0;
if (gf_vec_equal(thespine->vals[0], thespine->vals[thespine->count-1])) spine_closed = 1;
if (spine_closed && (thespine->count==2)) return;
gf_path_flatten(path);
memset(&vx, 0, sizeof(GF_Vertex));
pts_per_cross = 0;
cross_len = 0;
cur = 0;
for (i=0; i<path->n_contours; i++) {
nb_pts = 1 + path->contours[i] - cur;
pts_per_cross += nb_pts;
v1.z = 0;
for (j=1; j<nb_pts; j++) {
v1.x = path->points[j+cur].x - path->points[j-1+cur].x;
v1.y = path->points[j+cur].y - path->points[j-1+cur].y;
cross_len += gf_vec_len(v1);
}
}
faces_per_cross = pts_per_cross - path->n_contours;
begin_face = end_face = 0;
face_spines = face_count = (thespine->count-1)*faces_per_cross;
if (begin_cap) {
begin_face = face_count;
face_count ++;
}
if (end_cap) {
end_face = face_count;
face_count ++;
}
pt_count = pts_per_cross * thespine->count;
smooth_normals = NEAR_ZERO(creaseAngle) ? 0 : 1;
faces = (GF_Mesh**)gf_malloc(sizeof(GF_Mesh *)*face_count);
for (i=0; i<face_count; i++) faces[i] = new_mesh();
faces_info = NULL;
pts_info = NULL;
if (smooth_normals) {
faces_info = (struct face_info*)gf_malloc(sizeof(struct face_info)*face_count);
memset(faces_info, 0, sizeof(struct face_info)*face_count);
pts_info = (struct pt_info*)gf_malloc(sizeof(struct pt_info)*pt_count);
memset(pts_info, 0, sizeof(struct pt_info)*pt_count);
}
spine = thespine->vals;
nb_spine = thespine->count;
SCPs = (SCP *)gf_malloc(sizeof(SCP) * nb_spine);
memset(SCPs, 0, sizeof(SCP) * nb_spine);
SCPi = (SCPInfo *) gf_malloc(sizeof(SCPInfo) * nb_spine);
memset(SCPi, 0, sizeof(SCPInfo) * nb_spine);
SCPi[0].pt = spine[0];
SCPi[0].max_idx = 0;
nb_scp=1;
spine_len = 0;
check_first_spine_vec = 1;
for (i=1; i<nb_spine; i++) {
Fixed len;
gf_vec_diff(v2, spine[i], spine[i-1]);
len = gf_vec_len(v2);
spine_len += len;
if (check_first_spine_vec && len) {
check_first_spine_vec = 0;
spine_vec = v2;
}
if (gf_vec_equal(SCPi[nb_scp-1].pt, spine[i])) {
SCPi[nb_scp-1].max_idx = i;
continue;
}
if (i+1 == nb_spine) {
nb_scp++;
SCPi[nb_scp-1].pt = spine[i];
SCPi[nb_scp-1].max_idx = i;
break;
}
gf_vec_diff(v1, spine[i+1], spine[i]);
gf_vec_diff(v2, SCPi[nb_scp-1].pt, spine[i]);
n = gf_vec_cross(v1, v2);
if (!n.x && !n.y && !n.z) {
SCPi[nb_scp-1].max_idx = i;
}
else {
nb_scp++;
SCPi[nb_scp-1].pt = spine[i];
SCPi[nb_scp-1].max_idx = i;
}
}
if (nb_scp<=2) {
SCPi[0].xaxis.x = FIX_ONE;
SCPi[0].xaxis.y = 0;
SCPi[0].xaxis.z = 0;
SCPi[0].yaxis.x = 0;
SCPi[0].yaxis.y = FIX_ONE;
SCPi[0].yaxis.z = 0;
SCPi[0].zaxis.x = 0;
SCPi[0].zaxis.y = 0;
SCPi[0].zaxis.z = FIX_ONE;
if (!check_first_spine_vec) {
Fixed alpha, gamma;
Fixed cos_a, sin_a, sin_g, cos_g;
gf_vec_norm(&spine_vec);
if (! NEAR_ZERO(spine_vec.x) ) {
if (spine_vec.x >= FIX_ONE-FIX_EPSILON) alpha = GF_PI2;
else if (spine_vec.x <= -FIX_ONE+FIX_EPSILON) alpha = -GF_PI2;
else alpha = gf_asin(spine_vec.x);
cos_a = gf_cos(alpha);
sin_a = spine_vec.x;
if (NEAR_ZERO(cos_a)) gamma = 0;
else {
Fixed __abs;
gamma = gf_acos(gf_divfix(spine_vec.y, cos_a));
sin_g = gf_sin(gamma);
__abs = gf_divfix(spine_vec.z, cos_a) + sin_g;
if (ABS(__abs) > ABS(sin_g) ) gamma *= -1;
}
cos_g = gf_cos(gamma);
if (NEAR_ZERO(cos_g)) {
cos_g = 0;
sin_g = FIX_ONE;
} else {
sin_g = gf_sin(gamma);
}
SCPi[0].yaxis.y = gf_mulfix(cos_a, sin_g);
SCPi[0].yaxis.z = gf_mulfix(cos_a, cos_g);
SCPi[0].yaxis.x = sin_a;
SCPi[0].zaxis.y = -gf_mulfix(sin_a, sin_g);
SCPi[0].zaxis.z = -gf_mulfix(sin_a, cos_g);
SCPi[0].zaxis.x = cos_a;
}
if (! NEAR_ZERO(spine_vec.z) ) {
if (spine_vec.z >= FIX_ONE-FIX_EPSILON) alpha = GF_PI2;
else if (spine_vec.z <= -FIX_ONE+FIX_EPSILON) alpha = -GF_PI2;
else alpha = gf_asin(spine_vec.z);
cos_a = gf_cos(alpha);
sin_a = spine_vec.z;
if (NEAR_ZERO(cos_a) ) gamma = 0;
else {
Fixed __abs;
gamma = gf_acos(gf_divfix(spine_vec.y, cos_a));
sin_g = gf_sin(gamma);
__abs = gf_divfix(spine_vec.x, cos_a) + sin_g;
if (ABS(__abs) > ABS(sin_g) ) gamma *= -1;
}
cos_g = gf_cos(gamma);
sin_g = gf_sin(gamma);
SCPi[0].yaxis.y = gf_mulfix(cos_a, sin_g);
SCPi[0].yaxis.x = gf_mulfix(cos_a, cos_g);
SCPi[0].yaxis.z = sin_a;
SCPi[0].zaxis.y = -gf_mulfix(sin_a, sin_g);
SCPi[0].zaxis.x = -gf_mulfix(sin_a, cos_g);
SCPi[0].zaxis.z = cos_a;
}
}
for (i=0; i<nb_spine; i++) {
SCPs[i].xaxis = SCPi[0].xaxis;
SCPs[i].yaxis = SCPi[0].yaxis;
SCPs[i].zaxis = SCPi[0].zaxis;
}
}
else {
assert(nb_scp<=nb_spine);
for (i=1; i<nb_scp-1; i++) {
gf_vec_diff(SCPi[i].yaxis, SCPi[i+1].pt, SCPi[i-1].pt);
gf_vec_diff(v1, SCPi[i+1].pt, SCPi[i].pt);
gf_vec_diff(v2, SCPi[i-1].pt, SCPi[i].pt);
SCPi[i].zaxis = gf_vec_cross(v1, v2);
}
if (spine_closed) {
gf_vec_diff(SCPi[0].yaxis, SCPi[1].pt, SCPi[nb_scp-2].pt);
gf_vec_diff(v1, SCPi[1].pt, SCPi[0].pt);
gf_vec_diff(v2, SCPi[nb_scp-2].pt, SCPi[0].pt);
SCPi[0].zaxis = gf_vec_cross(v1, v2);
SCPi[nb_scp-1].yaxis = SCPi[0].yaxis;
SCPi[nb_scp-1].zaxis = SCPi[0].zaxis;
} else {
gf_vec_diff(SCPi[0].yaxis, SCPi[1].pt, SCPi[0].pt);
SCPi[0].zaxis = SCPi[1].zaxis;
gf_vec_diff(SCPi[nb_scp-1].yaxis, SCPi[nb_scp-1].pt, SCPi[nb_scp-2].pt);
SCPi[nb_scp-1].zaxis = SCPi[nb_scp-2].zaxis;
}
for (i=1; i<nb_scp; i++) {
Fixed res = gf_vec_dot(SCPi[i].zaxis, SCPi[i-1].zaxis);
if (res<0) gf_vec_rev(SCPi[i].zaxis);
}
j=0;
for (i=0; i<nb_scp; i++) {
SCPi[i].xaxis = gf_vec_cross(SCPi[i].yaxis, SCPi[i].zaxis);
gf_vec_norm(&SCPi[i].xaxis);
gf_vec_norm(&SCPi[i].yaxis);
gf_vec_norm(&SCPi[i].zaxis);
while (j<=SCPi[i].max_idx) {
SCPs[j].xaxis = SCPi[i].xaxis;
SCPs[j].yaxis = SCPi[i].yaxis;
SCPs[j].zaxis = SCPi[i].zaxis;
j++;
}
}
}
gf_free(SCPi);
r.x = r.q = r.z = 0;
r.y = FIX_ONE;
scale.x = scale.y = FIX_ONE;
cur_spine = 0;
for (i=0; i<nb_spine; i++) {
u32 cur_face_in_cross;
SCP *curSCP;
if (spine_closed && (i+1==nb_spine)) {
curSCP = &SCPs[0];
do_close = 1;
} else {
curSCP = &SCPs[i];
do_close = 0;
curSCP->xaxis = gf_vec_cross(curSCP->yaxis, curSCP->zaxis);
gf_vec_norm(&curSCP->xaxis);
gf_vec_norm(&curSCP->yaxis);
gf_vec_norm(&curSCP->zaxis);
if (spine_ori && (i<spine_ori->count)) r = spine_ori->vals[i];
if (spine_scale && (i<spine_scale->count)) scale = spine_scale->vals[i];
gf_mx_init(mx);
gf_mx_add_rotation(&mx, r.q, r.x, r.y, r.z);
gf_mx_apply_vec(&mx, &curSCP->xaxis);
gf_mx_apply_vec(&mx, &curSCP->yaxis);
gf_mx_apply_vec(&mx, &curSCP->zaxis);
}
vx.texcoords.y = gf_divfix(cur_spine, spine_len);
cur_pts_in_cross = 0;
cur_face_in_cross = 0;
cur = 0;
for (j=0; j<path->n_contours; j++) {
Bool subpath_closed;
nb_pts = 1+path->contours[j] - cur;
cur_cross = 0;
subpath_closed = 0;
if ((path->points[cur].x==path->points[path->contours[j]].x) && (path->points[cur].y==path->points[path->contours[j]].y))
subpath_closed = 1;
for (k=0; k<nb_pts; k++) {
u32 pidx = k + cur_pts_in_cross + i*pts_per_cross;
if (do_close) pidx = k + cur_pts_in_cross;
v1.x = path->points[k+cur].x;
v1.z = path->points[k+cur].y;
if (tx_along_spine) {
vx.texcoords.x = gf_divfix(cur_cross, cross_len);
} else {
vx.texcoords.x = gf_divfix(v1.x - min_cx, width_cx);
vx.texcoords.y = gf_divfix(v1.z - min_cy, width_cy);
}
if (subpath_closed && (k+1==nb_pts)) {
pidx = cur_pts_in_cross + i*pts_per_cross;
if (do_close) pidx = cur_pts_in_cross;
v1.x = path->points[cur].x;
v1.z = path->points[cur].y;
}
v1.x = gf_mulfix(v1.x, scale.x);
v1.z = gf_mulfix(v1.z, scale.y);
v1.y = 0;
vx.pos.x = gf_mulfix(v1.x, curSCP->xaxis.x) + gf_mulfix(v1.y, curSCP->yaxis.x) + gf_mulfix(v1.z, curSCP->zaxis.x) + spine[i].x;
vx.pos.y = gf_mulfix(v1.x, curSCP->xaxis.y) + gf_mulfix(v1.y, curSCP->yaxis.y) + gf_mulfix(v1.z, curSCP->zaxis.y) + spine[i].y;
vx.pos.z = gf_mulfix(v1.x, curSCP->xaxis.z) + gf_mulfix(v1.y, curSCP->yaxis.z) + gf_mulfix(v1.z, curSCP->zaxis.z) + spine[i].z;
if (i+1<nb_spine) {
if (k<nb_pts-1) REGISTER_POINT_FACE(k + cur_face_in_cross + i*faces_per_cross);
if (k) REGISTER_POINT_FACE(k-1 + cur_face_in_cross + i*faces_per_cross);
}
else if (smooth_normals && do_close) {
if (k<nb_pts-1) {
register_point_in_face(&faces_info[k + cur_face_in_cross], pidx);
register_face_in_point(&pts_info[pidx], k + cur_face_in_cross);
}
if (k) {
register_point_in_face(&faces_info[k-1 + cur_face_in_cross], pidx);
register_face_in_point(&pts_info[pidx], k-1 + cur_face_in_cross);
}
}
if (i) {
if (k<nb_pts-1) REGISTER_POINT_FACE(k + cur_face_in_cross + (i-1)*faces_per_cross);
if (k) REGISTER_POINT_FACE(k-1 + cur_face_in_cross + (i-1)*faces_per_cross);
}
if (k+1<nb_pts) {
v1.z = 0;
v1.x = path->points[k+1+cur].x - path->points[k+cur].x;
v1.y = path->points[k+1+cur].y - path->points[k+cur].y;
cur_cross += gf_vec_len(v1);
}
}
cur_face_in_cross += nb_pts-1;
cur_pts_in_cross += nb_pts;
cur += nb_pts;
}
if (i+1<nb_spine) {
gf_vec_diff(v1, spine[i+1], spine[i]);
cur_spine += gf_vec_len(v1);
}
}
for (i=0; i<face_spines; i++) {
mesh_set_triangle(faces[i], 0, 1, 3);
mesh_set_triangle(faces[i], 0, 3, 2);
gf_vec_diff(v1, faces[i]->vertices[1].pos, faces[i]->vertices[0].pos);
gf_vec_diff(v2, faces[i]->vertices[3].pos, faces[i]->vertices[0].pos);
n = gf_vec_cross(v1, v2);
gf_vec_norm(&n);
for (j=0; j<faces[i]->v_count; j++) {
MESH_SET_NORMAL(faces[i]->vertices[j], n);
if (smooth_normals) faces_info[i].nor = n;
}
}
if (begin_face) {
SFVec3f n;
scale.x = scale.y = FIX_ONE;
if (spine_scale && spine_scale->count) scale = spine_scale->vals[0];
SCPbegin = SCPs[0];
n = SCPbegin.yaxis;
gf_vec_norm(&n);
convexity = gf_polygone2d_get_convexity(path->points, path->n_points);
switch (convexity) {
case GF_POLYGON_CONVEX_CCW:
case GF_POLYGON_COMPLEX_CCW:
break;
default:
gf_vec_rev(n);
break;
}
MESH_SET_NORMAL(vx, n);
if (smooth_normals) {
faces_info[begin_face].nor = n;
assert(gf_vec_len(n));
}
cur_pts_in_cross = 0;
cur = 0;
for (i=0; i<path->n_contours; i++) {
Bool subpath_closed = 0;
nb_pts = 1 + path->contours[i] - cur;
if ((path->points[cur].x==path->points[path->contours[i]].x) && (path->points[cur].y==path->points[path->contours[i]].y))
subpath_closed = 1;
for (j=0; j<nb_pts; j++) {
u32 pidx = j + (pts_per_cross-1-cur_pts_in_cross);
v1.x = path->points[j+cur].x;
v1.z = path->points[j+cur].y;
vx.texcoords.x = gf_divfix(v1.x - min_cx, width_cx);
vx.texcoords.y = gf_divfix(v1.z - min_cy, width_cy);
if (subpath_closed && (j+1==nb_pts)) {
pidx = (pts_per_cross-1-cur_pts_in_cross);
v1.x = path->points[cur].x;
v1.z = path->points[cur].y;
}
v1.x = gf_mulfix(v1.x , scale.x);
v1.z = gf_mulfix(v1.z , scale.y);
v1.y = 0;
vx.pos.x = gf_mulfix(v1.x, SCPbegin.xaxis.x) + gf_mulfix(v1.y, SCPbegin.yaxis.x) + gf_mulfix(v1.z, SCPbegin.zaxis.x) + spine[0].x;
vx.pos.y = gf_mulfix(v1.x, SCPbegin.xaxis.y) + gf_mulfix(v1.y, SCPbegin.yaxis.y) + gf_mulfix(v1.z, SCPbegin.zaxis.y) + spine[0].y;
vx.pos.z = gf_mulfix(v1.x, SCPbegin.xaxis.z) + gf_mulfix(v1.y, SCPbegin.yaxis.z) + gf_mulfix(v1.z, SCPbegin.zaxis.z) + spine[0].z;
REGISTER_POINT_FACE(begin_face);
}
cur_pts_in_cross += nb_pts;
cur += nb_pts;
}
}
if (end_face) {
SFVec3f n;
scale.x = scale.y = FIX_ONE;
if (spine_scale && (nb_spine-1<spine_scale->count)) scale = spine_scale->vals[nb_spine-1];
SCPend = SCPs[nb_spine-1];
n = SCPend.yaxis;
gf_vec_norm(&n);
MESH_SET_NORMAL(vx, n);
convexity = gf_polygone2d_get_convexity(path->points, path->n_points);
switch (convexity) {
case GF_POLYGON_CONVEX_CCW:
case GF_POLYGON_COMPLEX_CCW:
gf_vec_rev(vx.normal);
gf_vec_rev(n);
break;
}
if (smooth_normals) {
faces_info[end_face].nor = n;
assert(gf_vec_len(n));
}
cur_pts_in_cross = 0;
cur = 0;
for (i=0; i<path->n_contours; i++) {
Bool subpath_closed = 0;
nb_pts = 1 + path->contours[i] - cur;
if ((path->points[cur].x==path->points[path->contours[i]].x) && (path->points[cur].y==path->points[path->contours[i]].y))
subpath_closed = 1;
for (j=0; j<nb_pts; j++) {
u32 pidx = j + cur_pts_in_cross + (nb_spine-1)*pts_per_cross;
v1.x = path->points[j+cur].x;
v1.z = path->points[j+cur].y;
vx.texcoords.x = gf_divfix(v1.x - min_cx, width_cx);
vx.texcoords.y = gf_divfix(v1.z - min_cy, width_cy);
if (subpath_closed && (j+1==nb_pts)) {
pidx = cur_pts_in_cross + (nb_spine-1)*pts_per_cross;
v1.x = path->points[cur].x;
v1.z = path->points[cur].y;
}
v1.x = gf_mulfix(v1.x, scale.x);
v1.z = gf_mulfix(v1.z, scale.y);
v1.y = 0;
vx.pos.x = gf_mulfix(v1.x, SCPend.xaxis.x) + gf_mulfix(v1.y, SCPend.yaxis.x) + gf_mulfix(v1.z, SCPend.zaxis.x) + spine[nb_spine-1].x;
vx.pos.y = gf_mulfix(v1.x, SCPend.xaxis.y) + gf_mulfix(v1.y, SCPend.yaxis.y) + gf_mulfix(v1.z, SCPend.zaxis.y) + spine[nb_spine-1].y;
vx.pos.z = gf_mulfix(v1.x, SCPend.xaxis.z) + gf_mulfix(v1.y, SCPend.yaxis.z) + gf_mulfix(v1.z, SCPend.zaxis.z) + spine[nb_spine-1].z;
REGISTER_POINT_FACE(end_face);
}
cur_pts_in_cross += nb_pts;
cur += nb_pts;
}
}
if (smooth_normals) {
Fixed cosCrease;
if (creaseAngle>GF_PI) cosCrease = -FIX_ONE;
else cosCrease = gf_cos(creaseAngle);
for (i=0; i<face_count; i++) {
for (j=0; j<faces[i]->v_count; j++) {
SFVec3f n = smooth_face_normals(pts_info, pt_count, faces_info, face_count, j, i, cosCrease);
MESH_SET_NORMAL(faces[i]->vertices[j], n);
}
}
if (faces_info) {
for (i=0; i<face_count; i++) if (faces_info[i].idx) gf_free(faces_info[i].idx);
gf_free(faces_info);
}
if (pts_info) {
for (i=0; i<pt_count; i++) if (pts_info[i].faces) gf_free(pts_info[i].faces);
gf_free(pts_info);
}
mesh->flags |= MESH_IS_SMOOTHED;
}
mesh->mesh_type = MESH_TRIANGLES;
for (i=0; i<face_spines; i++) {
if (faces[i]->v_count) {
u32 init_idx;
GF_Mesh *face = faces[i];
init_idx = mesh->v_count;
mesh_set_vertex_vx(mesh, &face->vertices[0]);
mesh_set_vertex_vx(mesh, &face->vertices[1]);
mesh_set_vertex_vx(mesh, &face->vertices[2]);
mesh_set_vertex_vx(mesh, &face->vertices[3]);
mesh_set_triangle(mesh, init_idx + 0, init_idx + 1, init_idx + 3);
mesh_set_triangle(mesh, init_idx + 0, init_idx + 3, init_idx + 2);
}
mesh_free(faces[i]);
}
if (begin_face) {
if (path->n_contours>1) {
#ifdef GPAC_HAS_GLU
u32 *ptsPerFace = gf_malloc(sizeof(u32)*path->n_contours);
cur = 0;
for (i=0; i<path->n_contours; i++) {
nb_pts = 1+path->contours[i] - cur;
cur+=nb_pts;
ptsPerFace[i] = nb_pts;
}
TesselateFaceMeshComplex(mesh, faces[begin_face], path->n_contours, ptsPerFace);
gf_free(ptsPerFace);
#endif
} else {
TesselateFaceMesh(mesh, faces[begin_face]);
}
mesh_free(faces[begin_face]);
}
if (end_face) {
if (path->n_contours>1) {
#ifdef GPAC_HAS_GLU
u32 *ptsPerFace = gf_malloc(sizeof(u32)*path->n_contours);
cur = 0;
for (i=0; i<path->n_contours; i++) {
nb_pts = 1+path->contours[i] - cur;
cur+=nb_pts;
ptsPerFace[i] = nb_pts;
}
TesselateFaceMeshComplex(mesh, faces[end_face], path->n_contours, ptsPerFace);
gf_free(ptsPerFace);
#endif
} else {
TesselateFaceMesh(mesh, faces[end_face]);
}
mesh_free(faces[end_face]);
}
gf_free(faces);
gf_free(SCPs);
}
void mesh_extrude_path_ext(GF_Mesh *mesh, GF_Path *path, MFVec3f *thespine, Fixed creaseAngle, Fixed min_cx, Fixed min_cy, Fixed width_cx, Fixed width_cy, Bool begin_cap, Bool end_cap, MFRotation *spine_ori, MFVec2f *spine_scale, Bool tx_along_spine)
{
mesh_extrude_path_intern(mesh, path, thespine, creaseAngle, min_cx, min_cy, width_cx, width_cy, begin_cap, end_cap, spine_ori, spine_scale, tx_along_spine);
}
void mesh_extrude_path(GF_Mesh *mesh, GF_Path *path, MFVec3f *thespine, Fixed creaseAngle, Bool begin_cap, Bool end_cap, MFRotation *spine_ori, MFVec2f *spine_scale, Bool tx_along_spine)
{
GF_Rect rc;
gf_path_get_bounds(path, &rc);
mesh_extrude_path_intern(mesh, path, thespine, creaseAngle, rc.x, rc.y-rc.height, rc.width, rc.height, begin_cap, end_cap, spine_ori, spine_scale, tx_along_spine);
mesh_update_bounds(mesh);
gf_mesh_build_aabbtree(mesh);
}
void mesh_new_extrusion(GF_Mesh *mesh, GF_Node *node)
{
GF_Path *path;
u32 i;
M_Extrusion *ext = (M_Extrusion *)node;
mesh_reset(mesh);
path = gf_path_new();
gf_path_add_move_to(path, ext->crossSection.vals[0].x, ext->crossSection.vals[0].y);
for (i=1; i<ext->crossSection.count; i++) {
gf_path_add_line_to(path, ext->crossSection.vals[i].x, ext->crossSection.vals[i].y);
}
mesh_extrude_path(mesh, path, &ext->spine, ext->creaseAngle, ext->beginCap, ext->endCap, &ext->orientation, &ext->scale, 1);
gf_path_del(path);
mesh_update_bounds(mesh);
if (!ext->ccw) mesh->flags |= MESH_IS_CW;
}
#endif
#endif