This source file includes following definitions.
- disk2d_check_changes
- TraverseDisk2D
- compositor_init_disk2d
- arc2d_check_changes
- TraverseArc2D
- compositor_init_arc2d
- polyline2d_check_changes
- TraversePolyline2D
- compositor_init_polyline2d
- triangleset2d_check_changes
- TraverseTriangleSet2D
- compositor_init_triangle_set2d
- build_polypoint2d
- TraversePolypoint2D
- compositor_init_polypoint2d
- build_line_set
- TraverseLineSet
- compositor_init_lineset
- BuildTriangleSet
- build_triangle_set
- TraverseTriangleSet
- compositor_init_triangle_set
- build_indexed_triangle_set
- TraverseIndexedTriangleSet
- ITS_SetIndex
- compositor_init_indexed_triangle_set
- BuildTriangleStripSet
- build_triangle_strip_set
- TraverseTriangleStripSet
- compositor_init_triangle_strip_set
- build_indexed_triangle_strip_set
- TraverseIndexedTriangleStripSet
- ITSS_SetIndex
- compositor_init_indexed_triangle_strip_set
- BuildTriangleFanSet
- build_triangle_fan_set
- TraverseTriangleFanSet
- compositor_init_triangle_fan_set
- build_indexed_triangle_fan_set
- TraverseIndexedTriangleFanSet
- ITFS_SetIndex
- compositor_init_indexed_triangle_fan_set
#include "nodes_stacks.h"
#include "visual_manager.h"
#include "drawable.h"
#ifndef GPAC_DISABLE_X3D
static void disk2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
{
if (gf_node_dirty_get(node)) {
Fixed a = ((X_Disk2D *) node)->outerRadius * 2;
drawable_reset_path(stack);
gf_path_add_ellipse(stack->path, 0, 0, a, a);
a = ((X_Disk2D *) node)->innerRadius * 2;
if (a) gf_path_add_ellipse(stack->path, 0, 0, a, a);
gf_node_dirty_clear(node, 0);
drawable_mark_modified(stack, tr_state);
}
}
static void TraverseDisk2D(GF_Node *node, void *rs, Bool is_destroy)
{
DrawableContext *ctx;
Drawable *stack = (Drawable *)gf_node_get_private(node);
GF_TraverseState *tr_state = (GF_TraverseState *)rs;
if (is_destroy) {
drawable_node_del(node);
return;
}
disk2d_check_changes(node, stack, tr_state);
switch (tr_state->traversing_mode) {
#ifndef GPAC_DISABLE_3D
case TRAVERSE_DRAW_3D:
if (!stack->mesh) {
stack->mesh = new_mesh();
mesh_from_path(stack->mesh, stack->path);
}
visual_3d_draw_2d(stack, tr_state);
return;
#endif
case TRAVERSE_GET_BOUNDS:
gf_path_get_bounds(stack->path, &tr_state->bounds);
return;
case TRAVERSE_PICK:
vrml_drawable_pick(stack, tr_state);
return;
case TRAVERSE_SORT:
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) return;
#endif
ctx = drawable_init_context_mpeg4(stack, tr_state);
if (!ctx) return;
drawable_finalize_sort(ctx, tr_state, NULL);
return;
}
}
void compositor_init_disk2d(GF_Compositor *compositor, GF_Node *node)
{
drawable_stack_new(compositor, node);
gf_node_set_callback_function(node, TraverseDisk2D);
}
static void arc2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
{
if (gf_node_dirty_get(node)) {
drawable_reset_path(stack);
if (gf_node_get_tag(node)==TAG_X3D_Arc2D) {
X_Arc2D *a = (X_Arc2D *) node;
gf_path_add_arc(stack->path, a->radius, a->startAngle, a->endAngle, 0);
} else {
X_ArcClose2D *a = (X_ArcClose2D *) node;
gf_path_add_arc(stack->path, a->radius, a->startAngle, a->endAngle, !stricmp(a->closureType.buffer, "PIE") ? 2 : 1);
}
gf_node_dirty_clear(node, 0);
drawable_mark_modified(stack, tr_state);
}
}
static void TraverseArc2D(GF_Node *node, void *rs, Bool is_destroy)
{
DrawableContext *ctx;
Drawable *stack = (Drawable *)gf_node_get_private(node);
GF_TraverseState *tr_state = (GF_TraverseState *)rs;
if (is_destroy) {
drawable_node_del(node);
return;
}
arc2d_check_changes(node, stack, tr_state);
switch (tr_state->traversing_mode) {
#ifndef GPAC_DISABLE_3D
case TRAVERSE_DRAW_3D:
if (!stack->mesh) {
stack->mesh = new_mesh();
if (gf_node_get_tag(node)==TAG_X3D_Arc2D) {
mesh_get_outline(stack->mesh, stack->path);
} else {
mesh_from_path(stack->mesh, stack->path);
}
}
visual_3d_draw_2d(stack, tr_state);
return;
#endif
case TRAVERSE_GET_BOUNDS:
gf_path_get_bounds(stack->path, &tr_state->bounds);
#ifndef GPAC_DISABLE_3D
gf_bbox_from_rect(&tr_state->bbox, &tr_state->bounds);
#endif
return;
case TRAVERSE_PICK:
vrml_drawable_pick(stack, tr_state);
return;
case TRAVERSE_SORT:
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) return;
#endif
ctx = drawable_init_context_mpeg4(stack, tr_state);
if (!ctx) return;
drawable_finalize_sort(ctx, tr_state, NULL);
return;
}
}
void compositor_init_arc2d(GF_Compositor *compositor, GF_Node *node)
{
drawable_stack_new(compositor, node);
gf_node_set_callback_function(node, TraverseArc2D);
}
static void polyline2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
{
if (gf_node_dirty_get(node)) {
u32 i;
X_Polyline2D *a = (X_Polyline2D *) node;
drawable_reset_path(stack);
for (i=0; i<a->lineSegments.count; i++) {
if (i) {
gf_path_add_line_to(stack->path, a->lineSegments.vals[i].x, a->lineSegments.vals[i].y);
} else {
gf_path_add_move_to(stack->path, a->lineSegments.vals[i].x, a->lineSegments.vals[i].y);
}
}
gf_node_dirty_clear(node, 0);
drawable_mark_modified(stack, tr_state);
}
}
static void TraversePolyline2D(GF_Node *node, void *rs, Bool is_destroy)
{
DrawableContext *ctx;
Drawable *stack = (Drawable *)gf_node_get_private(node);
GF_TraverseState *tr_state = (GF_TraverseState *)rs;
if (is_destroy) {
drawable_node_del(node);
return;
}
polyline2d_check_changes(node, stack, tr_state);
switch (tr_state->traversing_mode) {
#ifndef GPAC_DISABLE_3D
case TRAVERSE_DRAW_3D:
if (!stack->mesh) {
stack->mesh = new_mesh();
mesh_get_outline(stack->mesh, stack->path);
}
visual_3d_draw_2d(stack, tr_state);
return;
#endif
case TRAVERSE_GET_BOUNDS:
gf_path_get_bounds(stack->path, &tr_state->bounds);
return;
case TRAVERSE_PICK:
vrml_drawable_pick(stack, tr_state);
return;
case TRAVERSE_SORT:
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) return;
#endif
ctx = drawable_init_context_mpeg4(stack, tr_state);
if (!ctx) return;
drawable_finalize_sort(ctx, tr_state, NULL);
return;
}
}
void compositor_init_polyline2d(GF_Compositor *compositor, GF_Node *node)
{
drawable_stack_new(compositor, node);
gf_node_set_callback_function(node, TraversePolyline2D);
}
static void triangleset2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
{
if (gf_node_dirty_get(node)) {
u32 i, count;
X_TriangleSet2D *p = (X_TriangleSet2D *)node;
drawable_reset_path(stack);
count = p->vertices.count;
while (count%3) count--;
for (i=0; i<count; i+=3) {
gf_path_add_move_to(stack->path, p->vertices.vals[i].x, p->vertices.vals[i].y);
gf_path_add_line_to(stack->path, p->vertices.vals[i+1].x, p->vertices.vals[i+1].y);
gf_path_add_line_to(stack->path, p->vertices.vals[i+2].x, p->vertices.vals[i+2].y);
gf_path_close(stack->path);
}
gf_node_dirty_clear(node, 0);
drawable_mark_modified(stack, tr_state);
}
}
static void TraverseTriangleSet2D(GF_Node *node, void *rs, Bool is_destroy)
{
DrawableContext *ctx;
Drawable *stack = (Drawable *)gf_node_get_private(node);
GF_TraverseState *tr_state = (GF_TraverseState *)rs;
if (is_destroy) {
drawable_node_del(node);
return;
}
triangleset2d_check_changes(node, stack, tr_state);
switch (tr_state->traversing_mode) {
#ifndef GPAC_DISABLE_3D
case TRAVERSE_DRAW_3D:
if (!stack->mesh) {
SFColorRGBA col;
u32 i, count, idx;
GF_Vertex v1, v2, v3;
X_TriangleSet2D *p = (X_TriangleSet2D *)node;
stack->mesh = new_mesh();
stack->mesh->mesh_type = MESH_TRIANGLES;
col.red = col.green = col.blue = 0;
col.alpha = FIX_ONE;
v1.color = MESH_MAKE_COL(col);
v1.normal.x = v1.normal.y = 0;
v1.normal.z = MESH_NORMAL_UNIT;
v1.pos.z = 0;
v3 = v2 = v1;
count = p->vertices.count;
while (count%3) count--;
for (i=0; i<count; i+=3) {
idx = stack->mesh->v_count;
v1.pos.x = p->vertices.vals[i].x;
v1.pos.y = p->vertices.vals[i].y;
v2.pos.x = p->vertices.vals[i+1].x;
v2.pos.y = p->vertices.vals[i+1].y;
v3.pos.x = p->vertices.vals[i+2].x;
v3.pos.y = p->vertices.vals[i+2].y;
mesh_set_vertex_vx(stack->mesh, &v1);
mesh_set_vertex_vx(stack->mesh, &v2);
mesh_set_vertex_vx(stack->mesh, &v3);
gf_vec_diff(v2.pos, v2.pos, v1.pos);
gf_vec_diff(v3.pos, v3.pos, v1.pos);
v1.pos = gf_vec_cross(v2.pos, v3.pos);
if (v1.pos.z<0) {
mesh_set_triangle(stack->mesh, idx, idx+2, idx+1);
} else {
mesh_set_triangle(stack->mesh, idx, idx+1, idx+2);
}
}
stack->mesh->flags |= MESH_IS_2D;
mesh_update_bounds(stack->mesh);
}
visual_3d_draw_2d(stack, tr_state);
return;
#endif
case TRAVERSE_GET_BOUNDS:
gf_path_get_bounds(stack->path, &tr_state->bounds);
return;
case TRAVERSE_PICK:
vrml_drawable_pick(stack, tr_state);
return;
case TRAVERSE_SORT:
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) return;
#endif
ctx = drawable_init_context_mpeg4(stack, tr_state);
if (!ctx) return;
drawable_finalize_sort(ctx, tr_state, NULL);
return;
}
}
void compositor_init_triangle_set2d(GF_Compositor *compositor, GF_Node *node)
{
drawable_stack_new(compositor, node);
gf_node_set_callback_function(node, TraverseTriangleSet2D);
}
#ifndef GPAC_DISABLE_3D
static void build_polypoint2d(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
{
u32 i;
SFColorRGBA col;
X_Polypoint2D *p = (X_Polypoint2D *)node;
stack->mesh->mesh_type = MESH_POINTSET;
col.red = col.green = col.blue = 0;
col.alpha = FIX_ONE;
for (i=0; i<p->point.count; i++) {
mesh_set_point(stack->mesh, p->point.vals[i].x, p->point.vals[i].y, 0, col);
mesh_set_index(stack->mesh, stack->mesh->v_count-1);
}
}
static void TraversePolypoint2D(GF_Node *node, void *rs, Bool is_destroy)
{
drawable_3d_base_traverse(node, rs, is_destroy, build_polypoint2d);
}
void compositor_init_polypoint2d(GF_Compositor *compositor, GF_Node *node)
{
drawable_3d_new(node);
gf_node_set_callback_function(node, TraversePolypoint2D);
}
static void build_line_set(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
{
u32 i, j, c_idx;
GenMFField *cols;
GF_Vertex vx;
Bool rgba_col;
SFColorRGBA rgba;
X_LineSet *p = (X_LineSet *)node;
X_Coordinate *c = (X_Coordinate *) p->coord;
stack->mesh->mesh_type = MESH_LINESET;
cols = NULL;
rgba_col = 0;
if (p->color) {
if (gf_node_get_tag(p->color)==TAG_X3D_ColorRGBA) {
rgba_col = 1;
cols = (GenMFField *) & ((X_ColorRGBA *) p->color)->color;
} else {
cols = (GenMFField *) & ((M_Color *) p->color)->color;
}
}
c_idx = 0;
memset(&vx, 0, sizeof(GF_Vertex));
for (i=0; i<p->vertexCount.count; i++) {
if (p->vertexCount.vals[i]<2) continue;
for (j=0; j<(u32) p->vertexCount.vals[i]; j++) {
vx.pos = c->point.vals[c_idx];
if (cols && (cols->count>c_idx)) {
if (rgba_col) {
rgba = ((MFColorRGBA *)cols)->vals[c_idx];
} else {
rgba = gf_sg_sfcolor_to_rgba( ((MFColor *)cols)->vals[c_idx]);
}
vx.color = MESH_MAKE_COL(rgba);
}
mesh_set_vertex_vx(stack->mesh, &vx);
if (j) {
mesh_set_index(stack->mesh, stack->mesh->v_count-2);
mesh_set_index(stack->mesh, stack->mesh->v_count-1);
}
c_idx++;
if (c_idx==c->point.count) break;
}
}
if (cols) stack->mesh->flags |= MESH_HAS_COLOR;
mesh_update_bounds(stack->mesh);
}
static void TraverseLineSet(GF_Node *node, void *rs, Bool is_destroy)
{
drawable_3d_base_traverse(node, rs, is_destroy, build_line_set);
}
void compositor_init_lineset(GF_Compositor *compositor, GF_Node *node)
{
drawable_3d_new(node);
gf_node_set_callback_function(node, TraverseLineSet);
}
static void BuildTriangleSet(GF_Mesh *mesh, GF_Node *_coords, GF_Node *_color, GF_Node *_txcoords, GF_Node *_normal, MFInt32 *indices, Bool normalPerVertex, Bool ccw, Bool solid)
{
u32 i, count, generate_tx;
GF_Vertex vx;
GenMFField *cols;
MFVec3f *norms;
MFVec2f *txcoords;
Bool rgba_col;
SFColorRGBA rgba;
X_Coordinate *c = (X_Coordinate *) _coords;
mesh_reset(mesh);
cols = NULL;
rgba_col = 0;
if (_color) {
if (gf_node_get_tag(_color)==TAG_X3D_ColorRGBA) {
rgba_col = 1;
cols = (GenMFField *) & ((X_ColorRGBA *) _color)->color;
} else {
cols = (GenMFField *) & ((M_Color *) _color)->color;
}
}
norms = NULL;
if (_normal) norms = & ((M_Normal *)_normal)->vector;
txcoords = NULL;
generate_tx = 0;
if (_txcoords) {
switch (gf_node_get_tag(_txcoords)) {
case TAG_X3D_TextureCoordinate:
case TAG_MPEG4_TextureCoordinate:
txcoords = & ((M_TextureCoordinate *)_txcoords)->point;
break;
case TAG_X3D_TextureCoordinateGenerator:
generate_tx = 1;
break;
}
}
if (indices) {
count = indices->count;
} else {
count = c->point.count;
}
while (count%3) count--;
memset(&vx, 0, sizeof(GF_Vertex));
for (i=0; i<count; i++) {
u32 idx;
if (indices) {
if (indices->count<=i) return;
idx = indices->vals[i];
} else {
idx = i;
}
vx.pos = c->point.vals[idx];
if (cols && (cols->count>idx)) {
if (rgba_col) {
rgba = ((MFColorRGBA *)cols)->vals[idx];
} else {
rgba = gf_sg_sfcolor_to_rgba( ((MFColor *)cols)->vals[idx]);
}
vx.color = MESH_MAKE_COL(rgba);
}
if (norms && (norms->count>idx)) {
SFVec3f n = norms->vals[idx];
gf_vec_norm(&n);
MESH_SET_NORMAL(vx, n);
}
if (txcoords) {
if (txcoords->count>idx) vx.texcoords = txcoords->vals[idx];
}
else if (!generate_tx) {
switch (i%3) {
case 2:
vx.texcoords.x = FIX_ONE;
vx.texcoords.y = 0;
break;
case 1:
vx.texcoords.x = FIX_ONE/2;
vx.texcoords.y = FIX_ONE;
break;
case 0:
vx.texcoords.x = 0;
vx.texcoords.y = 0;
break;
}
}
mesh_set_vertex_vx(mesh, &vx);
}
for (i=0; i<mesh->v_count; i+=3) {
mesh_set_triangle(mesh, i, i+1, i+2);
}
if (generate_tx) mesh_generate_tex_coords(mesh, _txcoords);
if (!ccw) mesh->flags |= MESH_IS_CW;
if (cols) mesh->flags |= MESH_HAS_COLOR;
if (rgba_col) mesh->flags |= MESH_HAS_ALPHA;
if (!_normal) mesh_recompute_normals(mesh);
if (solid) mesh->flags |= MESH_IS_SOLID;
mesh_update_bounds(mesh);
gf_mesh_build_aabbtree(mesh);
}
static void build_triangle_set(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
{
X_TriangleSet *ts = (X_TriangleSet *)node;
if (!ts->coord) return;
BuildTriangleSet(stack->mesh, ts->coord, ts->color, ts->texCoord, ts->normal, NULL, ts->normalPerVertex, ts->ccw, ts->solid);
}
static void TraverseTriangleSet(GF_Node *node, void *rs, Bool is_destroy)
{
drawable_3d_base_traverse(node, rs, is_destroy, build_triangle_set);
}
void compositor_init_triangle_set(GF_Compositor *compositor, GF_Node *node)
{
drawable_3d_new(node);
gf_node_set_callback_function(node, TraverseTriangleSet);
}
static void build_indexed_triangle_set(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
{
X_IndexedTriangleSet *its = (X_IndexedTriangleSet*)node;
if (!its->coord) return;
BuildTriangleSet(stack->mesh, its->coord, its->color, its->texCoord, its->normal, &its->index, its->normalPerVertex, its->ccw, its->solid);
}
static void TraverseIndexedTriangleSet(GF_Node *node, void *rs, Bool is_destroy)
{
drawable_3d_base_traverse(node, rs, is_destroy, build_indexed_triangle_set);
}
static void ITS_SetIndex(GF_Node *node, GF_Route *route)
{
X_IndexedTriangleSet *its = (X_IndexedTriangleSet*)node;
gf_sg_vrml_field_copy(&its->index, &its->set_index, GF_SG_VRML_MFINT32);
gf_sg_vrml_mf_reset(&its->set_index, GF_SG_VRML_MFINT32);
}
void compositor_init_indexed_triangle_set(GF_Compositor *compositor, GF_Node *node)
{
X_IndexedTriangleSet *its = (X_IndexedTriangleSet*)node;
drawable_3d_new(node);
gf_node_set_callback_function(node, TraverseIndexedTriangleSet);
its->on_set_index = ITS_SetIndex;
}
static void BuildTriangleStripSet(GF_Mesh *mesh, GF_Node *_coords, GF_Node *_color, GF_Node *_txcoords, GF_Node *_normal, MFInt32 *stripList, MFInt32 *indices, Bool normalPerVertex, Bool ccw, Bool solid)
{
u32 strip, i, cur_idx, generate_tx;
GF_Vertex vx;
GenMFField *cols;
MFVec3f *norms;
MFVec2f *txcoords;
Bool rgba_col;
SFColorRGBA rgba;
X_Coordinate *c = (X_Coordinate *) _coords;
mesh_reset(mesh);
cols = NULL;
rgba_col = 0;
if (_color) {
if (gf_node_get_tag(_color)==TAG_X3D_ColorRGBA) {
rgba_col = 1;
cols = (GenMFField *) & ((X_ColorRGBA *) _color)->color;
} else {
cols = (GenMFField *) & ((M_Color *) _color)->color;
}
}
norms = NULL;
if (_normal) norms = & ((M_Normal *)_normal)->vector;
txcoords = NULL;
generate_tx = 0;
if (_txcoords) {
switch (gf_node_get_tag(_txcoords)) {
case TAG_X3D_TextureCoordinate:
case TAG_MPEG4_TextureCoordinate:
txcoords = & ((M_TextureCoordinate *)_txcoords)->point;
break;
case TAG_X3D_TextureCoordinateGenerator:
generate_tx = 1;
break;
}
}
memset(&vx, 0, sizeof(GF_Vertex));
cur_idx = 0;
for (strip= 0; strip<stripList->count; strip++) {
u32 start_idx = mesh->v_count;
if (stripList->vals[strip] < 3) continue;
for (i=0; i<(u32) stripList->vals[strip]; i++) {
u32 idx;
if (indices) {
if (indices->count<=cur_idx) return;
if (indices->vals[cur_idx] == -1) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[X3D] bad formatted X3D triangle strip\n"));
return;
}
idx = indices->vals[cur_idx];
} else {
idx = cur_idx;
}
vx.pos = c->point.vals[idx];
if (cols && (cols->count>idx)) {
if (rgba_col) {
rgba = ((MFColorRGBA *)cols)->vals[idx];
} else {
rgba = gf_sg_sfcolor_to_rgba( ((MFColor *)cols)->vals[idx]);
}
vx.color = MESH_MAKE_COL(rgba);
}
if (norms && (norms->count>idx)) {
SFVec3f n = norms->vals[idx];
gf_vec_norm(&n);
MESH_SET_NORMAL(vx, n);
}
if (txcoords) {
if (txcoords->count>idx) vx.texcoords = txcoords->vals[idx];
}
else if (!generate_tx) {
switch (idx%3) {
case 2:
vx.texcoords.x = FIX_ONE;
vx.texcoords.y = 0;
break;
case 1:
vx.texcoords.x = FIX_ONE/2;
vx.texcoords.y = FIX_ONE;
break;
case 0:
vx.texcoords.x = 0;
vx.texcoords.y = 0;
break;
}
}
if (i>2) {
mesh_set_vertex_vx(mesh, &mesh->vertices[mesh->v_count-2]);
mesh_set_vertex_vx(mesh, &mesh->vertices[mesh->v_count-2]);
}
mesh_set_vertex_vx(mesh, &vx);
cur_idx ++;
if (indices) {
if (cur_idx>=indices->count) break;
} else if (cur_idx==c->point.count) break;
}
for (i=start_idx; i<mesh->v_count; i+=3) {
mesh_set_triangle(mesh, i, i+1, i+2);
}
if (indices && (cur_idx<indices->count) && (indices->vals[cur_idx]==-1)) cur_idx++;
}
if (generate_tx) mesh_generate_tex_coords(mesh, _txcoords);
if (cols) mesh->flags |= MESH_HAS_COLOR;
if (rgba_col) mesh->flags |= MESH_HAS_ALPHA;
if (_normal) {
if (!ccw) mesh->flags |= MESH_IS_CW;
}
else {
u32 cur_face = 0;
mesh_recompute_normals(mesh);
for (i=0; i<mesh->i_count; i+= 3) {
if ((ccw && (cur_face%2)) || (!ccw && !(cur_face%2))) {
SFVec3f v;
u32 idx;
MESH_GET_NORMAL(v, mesh->vertices[mesh->indices[i]]);
v = gf_vec_scale(v,-1);
MESH_SET_NORMAL(mesh->vertices[mesh->indices[i]], v);
mesh->vertices[mesh->indices[i+1]].normal = mesh->vertices[mesh->indices[i]].normal;
mesh->vertices[mesh->indices[i+2]].normal = mesh->vertices[mesh->indices[i]].normal;
idx = mesh->indices[i+2];
mesh->indices[i+2] = mesh->indices[i+1];
mesh->indices[i+1] = idx;
}
cur_face++;
}
if (normalPerVertex) {
cur_face = 0;
for (strip=0; strip<stripList->count; strip++) {
SFVec3f n_0, n_1, n_2, n_avg;
u32 nb_face;
if (stripList->vals[strip] < 3) continue;
if (stripList->vals[strip] <= 3) {
cur_face ++;
continue;
}
MESH_GET_NORMAL(n_0, mesh->vertices[mesh->indices[3*cur_face]]);
MESH_GET_NORMAL(n_1, mesh->vertices[mesh->indices[3*(cur_face+1)]]);
gf_vec_add(n_avg, n_0, n_1);
gf_vec_norm(&n_avg);
MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*cur_face+1]], n_avg);
MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*(cur_face+1)]], n_avg);
nb_face = stripList->vals[strip] - 2;
cur_face++;
for (i=1; i<nb_face-1; i++) {
MESH_GET_NORMAL(n_2, mesh->vertices[mesh->indices[3*cur_face + 1]]);
gf_vec_add(n_avg, n_0, n_1);
gf_vec_add(n_avg, n_avg, n_2);
gf_vec_norm(&n_avg);
MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*cur_face - 1]], n_avg);
mesh->vertices[mesh->indices[3*cur_face + 1]].normal = mesh->vertices[mesh->indices[3*cur_face - 1]].normal;
mesh->vertices[mesh->indices[3*cur_face + 3]].normal = mesh->vertices[mesh->indices[3*cur_face - 1]].normal;
n_0 = n_1;
n_1 = n_2;
cur_face++;
}
}
}
}
if (solid) mesh->flags |= MESH_IS_SOLID;
mesh_update_bounds(mesh);
gf_mesh_build_aabbtree(mesh);
}
static void build_triangle_strip_set(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
{
X_TriangleStripSet *tss = (X_TriangleStripSet *)node;
if (!tss->coord) return;
BuildTriangleStripSet(stack->mesh, tss->coord, tss->color, tss->texCoord, tss->normal, &tss->stripCount, NULL, tss->normalPerVertex, tss->ccw, tss->solid);
}
static void TraverseTriangleStripSet(GF_Node *node, void *rs, Bool is_destroy)
{
drawable_3d_base_traverse(node, rs, is_destroy, build_triangle_strip_set);
}
void compositor_init_triangle_strip_set(GF_Compositor *compositor, GF_Node *node)
{
drawable_3d_new(node);
gf_node_set_callback_function(node, TraverseTriangleStripSet);
}
static void build_indexed_triangle_strip_set(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
{
MFInt32 stripList;
u32 i, nb_strips;
X_IndexedTriangleStripSet *itss = (X_IndexedTriangleStripSet *)node;
if (!itss->coord) return;
stripList.count = 0;
stripList.vals = NULL;
nb_strips = 0;
for (i=0; i<itss->index.count; i++) {
if (itss->index.vals[i]==-1) {
if (nb_strips>=3) {
u32 *out_nb;
gf_sg_vrml_mf_append(&stripList, GF_SG_VRML_MFINT32, (void **) &out_nb);
*out_nb = nb_strips;
}
nb_strips = 0;
} else {
nb_strips++;
}
}
if (nb_strips>=3) {
u32 *out_nb;
gf_sg_vrml_mf_append(&stripList, GF_SG_VRML_MFINT32, (void **) &out_nb);
*out_nb = nb_strips;
}
BuildTriangleStripSet(stack->mesh, itss->coord, itss->color, itss->texCoord, itss->normal, &stripList, &itss->index, itss->normalPerVertex, itss->ccw, itss->solid);
gf_sg_vrml_mf_reset(&stripList, GF_SG_VRML_MFINT32);
}
static void TraverseIndexedTriangleStripSet(GF_Node *node, void *rs, Bool is_destroy)
{
drawable_3d_base_traverse(node, rs, is_destroy, build_indexed_triangle_strip_set);
}
static void ITSS_SetIndex(GF_Node *node, GF_Route *route)
{
X_IndexedTriangleStripSet *itss = (X_IndexedTriangleStripSet*)node;
gf_sg_vrml_field_copy(&itss->index, &itss->set_index, GF_SG_VRML_MFINT32);
gf_sg_vrml_mf_reset(&itss->set_index, GF_SG_VRML_MFINT32);
}
void compositor_init_indexed_triangle_strip_set(GF_Compositor *compositor, GF_Node *node)
{
X_IndexedTriangleStripSet *itss = (X_IndexedTriangleStripSet*)node;
drawable_3d_new(node);
gf_node_set_callback_function(node, TraverseIndexedTriangleStripSet);
itss->on_set_index = ITSS_SetIndex;
}
static void BuildTriangleFanSet(GF_Mesh *mesh, GF_Node *_coords, GF_Node *_color, GF_Node *_txcoords, GF_Node *_normal, MFInt32 *fanList, MFInt32 *indices, Bool normalPerVertex, Bool ccw, Bool solid)
{
u32 fan, i, cur_idx, generate_tx;
GF_Vertex vx;
GenMFField *cols;
MFVec3f *norms;
MFVec2f *txcoords;
Bool rgba_col;
SFColorRGBA rgba;
X_Coordinate *c = (X_Coordinate *) _coords;
mesh_reset(mesh);
cols = NULL;
rgba_col = 0;
if (_color) {
if (gf_node_get_tag(_color)==TAG_X3D_ColorRGBA) {
rgba_col = 1;
cols = (GenMFField *) & ((X_ColorRGBA *) _color)->color;
} else {
cols = (GenMFField *) & ((M_Color *) _color)->color;
}
}
norms = NULL;
if (_normal) norms = & ((M_Normal *)_normal)->vector;
txcoords = NULL;
generate_tx = 0;
if (_txcoords) {
switch (gf_node_get_tag(_txcoords)) {
case TAG_X3D_TextureCoordinate:
case TAG_MPEG4_TextureCoordinate:
txcoords = & ((M_TextureCoordinate *)_txcoords)->point;
break;
case TAG_X3D_TextureCoordinateGenerator:
generate_tx = 1;
break;
}
}
memset(&vx, 0, sizeof(GF_Vertex));
cur_idx = 0;
for (fan= 0; fan<fanList->count; fan++) {
u32 start_idx = mesh->v_count;
if (fanList->vals[fan] < 3) continue;
for (i=0; i<(u32) fanList->vals[fan]; i++) {
u32 idx;
if (indices) {
if (indices->count<=cur_idx) return;
if (indices->vals[cur_idx] == -1) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[X3D] bad formatted X3D triangle set\n"));
return;
}
idx = indices->vals[cur_idx];
} else {
idx = cur_idx;
}
vx.pos = c->point.vals[idx];
if (cols && (cols->count>idx)) {
if (rgba_col) {
rgba = ((MFColorRGBA *)cols)->vals[idx];
} else {
rgba = gf_sg_sfcolor_to_rgba( ((MFColor *)cols)->vals[idx]);
}
vx.color = MESH_MAKE_COL(rgba);
}
if (norms && (norms->count>idx)) {
SFVec3f n = norms->vals[idx];
gf_vec_norm(&n);
MESH_SET_NORMAL(vx, n);
}
if (txcoords) {
if (txcoords->count>idx) vx.texcoords = txcoords->vals[idx];
}
else if (!generate_tx) {
switch (idx%3) {
case 2:
vx.texcoords.x = FIX_ONE;
vx.texcoords.y = 0;
break;
case 1:
vx.texcoords.x = FIX_ONE/2;
vx.texcoords.y = FIX_ONE;
break;
case 0:
vx.texcoords.x = 0;
vx.texcoords.y = 0;
break;
}
}
mesh_set_vertex_vx(mesh, &vx);
cur_idx ++;
if (indices) {
if (cur_idx>=indices->count) break;
} else if (cur_idx==c->point.count) break;
if (i>1) {
mesh_set_vertex_vx(mesh, &mesh->vertices[start_idx]);
mesh_set_vertex_vx(mesh, &vx);
}
}
for (i=start_idx; i<mesh->v_count; i+=3) {
mesh_set_triangle(mesh, i, i+1, i+2);
}
if (indices && (cur_idx<indices->count) && (indices->vals[cur_idx]==-1)) cur_idx++;
}
if (generate_tx) mesh_generate_tex_coords(mesh, _txcoords);
if (cols) mesh->flags |= MESH_HAS_COLOR;
if (rgba_col) mesh->flags |= MESH_HAS_ALPHA;
if (!ccw) mesh->flags |= MESH_IS_CW;
if (!_normal) {
mesh_recompute_normals(mesh);
if (normalPerVertex) {
u32 cur_face = 0;
for (fan=0; fan<fanList->count; fan++) {
SFVec3f n_0, n_1, n_avg, n_tot;
u32 nb_face, start_face;
if (fanList->vals[fan] < 3) continue;
if (fanList->vals[fan] == 3) {
cur_face++;
continue;
}
start_face = cur_face;
MESH_GET_NORMAL(n_0, mesh->vertices[mesh->indices[3*cur_face]]);
n_tot = n_0;
cur_face++;
nb_face = fanList->vals[fan] - 2;
for (i=1; i<nb_face; i++) {
MESH_GET_NORMAL(n_1, mesh->vertices[mesh->indices[3*cur_face + 1]]);
gf_vec_add(n_avg, n_0, n_1);
gf_vec_norm(&n_avg);
MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*cur_face + 1]], n_avg);
gf_vec_add(n_tot, n_tot, n_1);
n_0 = n_1;
cur_face++;
}
gf_vec_norm(&n_tot);
for (i=0; i<nb_face; i++) {
MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*(i+start_face)]], n_tot);
}
}
}
}
if (solid) mesh->flags |= MESH_IS_SOLID;
mesh_update_bounds(mesh);
gf_mesh_build_aabbtree(mesh);
}
static void build_triangle_fan_set(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
{
X_TriangleFanSet *tfs = (X_TriangleFanSet *)node;
if (!tfs->coord) return;
BuildTriangleFanSet(stack->mesh, tfs->coord, tfs->color, tfs->texCoord, tfs->normal, &tfs->fanCount, NULL, tfs->normalPerVertex, tfs->ccw, tfs->solid);
}
static void TraverseTriangleFanSet(GF_Node *node, void *rs, Bool is_destroy)
{
drawable_3d_base_traverse(node, rs, is_destroy, build_triangle_fan_set);
}
void compositor_init_triangle_fan_set(GF_Compositor *compositor, GF_Node *node)
{
drawable_3d_new(node);
gf_node_set_callback_function(node, TraverseTriangleFanSet);
}
static void build_indexed_triangle_fan_set(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
{
MFInt32 fanList;
u32 i, nb_fans;
X_IndexedTriangleFanSet *itfs = (X_IndexedTriangleFanSet *)node;
gf_node_dirty_clear(node, 0);
if (!itfs->coord) return;
fanList.count = 0;
fanList.vals = NULL;
nb_fans = 0;
for (i=0; i<itfs->index.count; i++) {
if (itfs->index.vals[i]==-1) {
if (nb_fans>=3) {
u32 *out_nb;
gf_sg_vrml_mf_append(&fanList, GF_SG_VRML_MFINT32, (void **) &out_nb);
*out_nb = nb_fans;
}
nb_fans = 0;
} else {
nb_fans++;
}
}
if (nb_fans>=3) {
u32 *out_nb;
gf_sg_vrml_mf_append(&fanList, GF_SG_VRML_MFINT32, (void **) &out_nb);
*out_nb = nb_fans;
}
BuildTriangleFanSet(stack->mesh, itfs->coord, itfs->color, itfs->texCoord, itfs->normal, &fanList, &itfs->index, itfs->normalPerVertex, itfs->ccw, itfs->solid);
gf_sg_vrml_mf_reset(&fanList, GF_SG_VRML_MFINT32);
}
static void TraverseIndexedTriangleFanSet(GF_Node *node, void *rs, Bool is_destroy)
{
drawable_3d_base_traverse(node, rs, is_destroy, build_indexed_triangle_fan_set);
}
static void ITFS_SetIndex(GF_Node *node, GF_Route *route)
{
X_IndexedTriangleFanSet *itfs = (X_IndexedTriangleFanSet *)node;
gf_sg_vrml_field_copy(&itfs->index, &itfs->set_index, GF_SG_VRML_MFINT32);
gf_sg_vrml_mf_reset(&itfs->set_index, GF_SG_VRML_MFINT32);
}
void compositor_init_indexed_triangle_fan_set(GF_Compositor *compositor, GF_Node *node)
{
X_IndexedTriangleFanSet *itfs = (X_IndexedTriangleFanSet *)node;
drawable_3d_new(node);
gf_node_set_callback_function(node, TraverseIndexedTriangleFanSet);
itfs->on_set_index = ITFS_SetIndex;
}
#endif
#endif