void compositor_extrude_text(GF_Node *node, GF_TraverseState *tr_state, GF_Mesh *mesh, MFVec3f *thespine, Fixed creaseAngle, Bool begin_cap, Bool end_cap, MFRotation *spine_ori, MFVec2f *spine_scale, Bool txAlongSpine) { u32 i, count; Fixed min_cx, min_cy, width_cx, width_cy; TextStack *st = (TextStack *) gf_node_get_private(node); /*rebuild text node*/ if (gf_node_dirty_get(node)) { ParentNode2D *parent = tr_state->parent; tr_state->parent = NULL; text_clean_paths(tr_state->visual->compositor, st); drawable_reset_path(st->graph); gf_node_dirty_clear(node, 0); build_text(st, (M_Text *)node, tr_state); tr_state->parent = parent; } min_cx = st->bounds.x; min_cy = st->bounds.y - st->bounds.height; width_cx = st->bounds.width; width_cy = st->bounds.height; mesh_reset(mesh); count = gf_list_count(st->spans); for (i=0; i<count; i++) { GF_TextSpan *span = (GF_TextSpan *)gf_list_get(st->spans, i); GF_Path *span_path = gf_font_span_create_path(span); mesh_extrude_path_ext(mesh, span_path, thespine, creaseAngle, min_cx, min_cy, width_cx, width_cy, begin_cap, end_cap, spine_ori, spine_scale, txAlongSpine); gf_path_del(span_path); } mesh_update_bounds(mesh); gf_mesh_build_aabbtree(mesh); }
void drawable_3d_base_traverse(GF_Node *n, void *rs, Bool is_destroy, void (*build_shape)(GF_Node*,Drawable3D *,GF_TraverseState *) ) { GF_TraverseState *tr_state = (GF_TraverseState *)rs; Drawable3D *stack = (Drawable3D*)gf_node_get_private(n); if (is_destroy) { drawable_3d_del(n); return; } if (gf_node_dirty_get(n)) { mesh_reset(stack->mesh); GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Rebuilding mesh %s\n", gf_node_get_class_name(n))); build_shape(n, stack, tr_state); gf_node_dirty_clear(n, 0); } switch (tr_state->traversing_mode) { case TRAVERSE_DRAW_3D: visual_3d_draw(tr_state, stack->mesh); drawable3d_check_focus_highlight(n, tr_state, &stack->mesh->bounds); break; case TRAVERSE_GET_BOUNDS: tr_state->bbox = stack->mesh->bounds; break; case TRAVERSE_PICK: visual_3d_vrml_drawable_pick(n, tr_state, stack->mesh, NULL); return; } }
static void TraversePlanarExtrusion(GF_Node *node, void *rs, Bool is_destroy) { PlanarExtrusion plane_ext; Drawable *stack_2d; u32 i, j, k; MFVec3f spine_vec; SFVec3f d; Fixed spine_len; GF_Rect bounds; GF_Path *geo, *spine; GF_TraverseState *tr_state = (GF_TraverseState *)rs; Drawable3D *stack = (Drawable3D *)gf_node_get_private(node); if (is_destroy) { drawable_3d_del(node); return; } if (!PlanarExtrusion_GetNode(node, &plane_ext)) return; if (!plane_ext.geometry || !plane_ext.spine) return; if (gf_node_dirty_get(node)) { u32 cur, nb_pts; u32 mode = tr_state->traversing_mode; geo = spine = NULL; tr_state->traversing_mode = TRAVERSE_GET_BOUNDS; gf_node_traverse(plane_ext.geometry, tr_state); gf_node_traverse(plane_ext.spine, tr_state); tr_state->traversing_mode = mode; switch (gf_node_get_tag(plane_ext.geometry) ) { case TAG_MPEG4_Circle: case TAG_MPEG4_Ellipse: case TAG_MPEG4_Rectangle: case TAG_MPEG4_Curve2D: case TAG_MPEG4_XCurve2D: case TAG_MPEG4_IndexedFaceSet2D: case TAG_MPEG4_IndexedLineSet2D: stack_2d = (Drawable*)gf_node_get_private(plane_ext.geometry); if (stack_2d) geo = stack_2d->path; break; default: return; } switch (gf_node_get_tag(plane_ext.spine) ) { case TAG_MPEG4_Circle: case TAG_MPEG4_Ellipse: case TAG_MPEG4_Rectangle: case TAG_MPEG4_Curve2D: case TAG_MPEG4_XCurve2D: case TAG_MPEG4_IndexedFaceSet2D: case TAG_MPEG4_IndexedLineSet2D: stack_2d = (Drawable*)gf_node_get_private(plane_ext.spine); if (stack_2d) spine = stack_2d->path; break; default: return; } if (!geo || !spine) return; mesh_reset(stack->mesh); gf_path_flatten(spine); gf_path_get_bounds(spine, &bounds); gf_path_flatten(geo); gf_path_get_bounds(geo, &bounds); cur = 0; for (i=0; i<spine->n_contours; i++) { nb_pts = 1 + spine->contours[i] - cur; spine_vec.vals = NULL; gf_sg_vrml_mf_alloc(&spine_vec, GF_SG_VRML_MFVEC3F, nb_pts); spine_len = 0; for (j=cur; j<nb_pts; j++) { spine_vec.vals[j].x = spine->points[j].x; spine_vec.vals[j].y = spine->points[j].y; spine_vec.vals[j].z = 0; if (j) { gf_vec_diff(d, spine_vec.vals[j], spine_vec.vals[j-1]); spine_len += gf_vec_len(d); } } cur += nb_pts; if (!plane_ext.orientation->count && !plane_ext.scale->count) { mesh_extrude_path_ext(stack->mesh, geo, &spine_vec, plane_ext.creaseAngle, bounds.x, bounds.y-bounds.height, bounds.width, bounds.height, plane_ext.beginCap, plane_ext.endCap, NULL, NULL, plane_ext.txAlongSpine); } /*interpolate orientation and scale along subpath line*/ else { MFRotation ori; MFVec2f scale; Fixed cur_len, frac; ori.vals = NULL; gf_sg_vrml_mf_alloc(&ori, GF_SG_VRML_MFROTATION, nb_pts); scale.vals = NULL; gf_sg_vrml_mf_alloc(&scale, GF_SG_VRML_MFVEC2F, nb_pts); cur_len = 0; if (!plane_ext.orientation->count) ori.vals[0].y = FIX_ONE; if (!plane_ext.scale->count) scale.vals[0].x = scale.vals[0].y = FIX_ONE; for (j=0; j<nb_pts; j++) { if (j) { gf_vec_diff(d, spine_vec.vals[j], spine_vec.vals[j-1]); cur_len += gf_vec_len(d); ori.vals[j] = ori.vals[j-1]; scale.vals[j] = scale.vals[j-1]; } if (plane_ext.orientation->count && (plane_ext.orientation->count == plane_ext.orientationKeys->count)) { frac = gf_divfix(cur_len , spine_len); if (frac < plane_ext.orientationKeys->vals[0]) ori.vals[j] = plane_ext.orientation->vals[0]; else if (frac >= plane_ext.orientationKeys->vals[plane_ext.orientationKeys->count-1]) ori.vals[j] = plane_ext.orientation->vals[plane_ext.orientationKeys->count-1]; else { for (k=1; k<plane_ext.orientationKeys->count; k++) { Fixed kDiff = plane_ext.orientationKeys->vals[k] - plane_ext.orientationKeys->vals[k-1]; if (!kDiff) continue; if (frac < plane_ext.orientationKeys->vals[k-1]) continue; if (frac > plane_ext.orientationKeys->vals[k]) continue; frac = gf_divfix(frac - plane_ext.orientationKeys->vals[k-1], kDiff); break; } ori.vals[j] = gf_sg_sfrotation_interpolate(plane_ext.orientation->vals[k-1], plane_ext.orientation->vals[k], frac); } } if (plane_ext.scale->count == plane_ext.scaleKeys->count) { frac = gf_divfix(cur_len , spine_len); if (frac <= plane_ext.scaleKeys->vals[0]) scale.vals[j] = plane_ext.scale->vals[0]; else if (frac >= plane_ext.scaleKeys->vals[plane_ext.scaleKeys->count-1]) scale.vals[j] = plane_ext.scale->vals[plane_ext.scale->count-1]; else { for (k=1; k<plane_ext.scaleKeys->count; k++) { Fixed kDiff = plane_ext.scaleKeys->vals[k] - plane_ext.scaleKeys->vals[k-1]; if (!kDiff) continue; if (frac < plane_ext.scaleKeys->vals[k-1]) continue; if (frac > plane_ext.scaleKeys->vals[k]) continue; frac = gf_divfix(frac - plane_ext.scaleKeys->vals[k-1], kDiff); break; } scale.vals[j].x = gf_mulfix(plane_ext.scale->vals[k].x - plane_ext.scale->vals[k-1].x, frac) + plane_ext.scale->vals[k-1].x; scale.vals[j].y = gf_mulfix(plane_ext.scale->vals[k].y - plane_ext.scale->vals[k-1].y, frac) + plane_ext.scale->vals[k-1].y; } } } mesh_extrude_path_ext(stack->mesh, geo, &spine_vec, plane_ext.creaseAngle, bounds.x, bounds.y-bounds.height, bounds.width, bounds.height, plane_ext.beginCap, plane_ext.endCap, &ori, &scale, plane_ext.txAlongSpine); gf_sg_vrml_mf_reset(&ori, GF_SG_VRML_MFROTATION); gf_sg_vrml_mf_reset(&scale, GF_SG_VRML_MFVEC2F); } gf_sg_vrml_mf_reset(&spine_vec, GF_SG_VRML_MFVEC3F); } mesh_update_bounds(stack->mesh); gf_mesh_build_aabbtree(stack->mesh); } if (tr_state->traversing_mode==TRAVERSE_DRAW_3D) { visual_3d_draw(tr_state, stack->mesh); } else if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) { tr_state->bbox = stack->mesh->bounds; } }
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; /*FIXME - this can't work with multitexturing*/ 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); } /*according to X3D spec, if normal field is set, it is ALWAYS as normal per vertex*/ 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]; } /*X3D says nothing about default texture mapping here...*/ 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); } /*get rid of -1*/ 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; /*first face normal*/ 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++; } /*and assign center normal*/ 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 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; /*FIXME - this can't work with multitexturing*/ 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); } /*according to X3D spec, if normal field is set, it is ALWAYS as normal per vertex*/ 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]; } /*X3D says nothing about default texture mapping here...*/ 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) { /*duplicate last 2 vertices (we really need independent vertices to handle normals per face)*/ 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); } /*get rid of -1*/ 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; } /*reorder everything to CCW*/ 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; } /*first face normal*/ MESH_GET_NORMAL(n_0, mesh->vertices[mesh->indices[3*cur_face]]); /*second face normal*/ 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); /*assign to second point of first face and first of second face*/ 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++) { /*get normal (use second pt of current face since first has been updated)*/ 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); /*last of prev face*/ MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*cur_face - 1]], n_avg); /*second of current face*/ mesh->vertices[mesh->indices[3*cur_face + 1]].normal = mesh->vertices[mesh->indices[3*cur_face - 1]].normal; /*first of next face*/ 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 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; /*FIXME - this can't work with multitexturing*/ 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]; } /*X3D says nothing about default texture mapping here...*/ 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 back_build_dome(GF_Mesh *mesh, MFFloat *angles, MFColor *color, Bool ground_dome) { u32 i, j, last_idx, ang_idx, new_idx; Bool pad; u32 step_div_h; GF_Vertex vx; SFColorRGBA start_col, end_col, fcol; Fixed start_angle, next_angle, angle, r, frac, first_angle; start_angle = 0; mesh_reset(mesh); start_col.red = start_col.green = start_col.blue = 0; end_col = start_col; if (color->count) { COL_TO_RGBA(start_col, color->vals[0]); end_col = start_col; if (color->count>1) COL_TO_RGBA(end_col, color->vals[1]); } start_col.alpha = end_col.alpha = FIX_ONE; vx.texcoords.x = vx.texcoords.y = 0; vx.color = MESH_MAKE_COL(start_col); vx.pos.x = vx.pos.z = 0; vx.pos.y = FIX_ONE; vx.normal.x = vx.normal.z = 0; vx.normal.y = -MESH_NORMAL_UNIT; mesh_set_vertex_vx(mesh, &vx); last_idx = 0; ang_idx = 0; pad = 1; next_angle = first_angle = 0; if (angles->count) { next_angle = angles->vals[0]; first_angle = 7*next_angle/8; pad = 0; } step_div_h = DOME_STEP_H; i=0; if (ground_dome) { step_div_h *= 2; i=1; } for (; i<DOME_STEP_V; i++) { if (ground_dome) { angle = first_angle + (i * (GF_PI2-first_angle) / DOME_STEP_V); } else { angle = (i * GF_PI / DOME_STEP_V); } /*switch cols*/ if (angle >= next_angle) { if (ang_idx+1<=angles->count) { start_angle = next_angle; next_angle = angles->vals[ang_idx+1]; if (next_angle>GF_PI) next_angle=GF_PI; start_col = end_col; ang_idx++; if (ang_idx+1<color->count) { COL_TO_RGBA(end_col, color->vals[ang_idx+1]); } else { pad = 1; } } else { if (ground_dome) break; pad = 1; } } if (pad) { fcol = end_col; } else { frac = gf_divfix(angle - start_angle, next_angle - start_angle) ; fcol.red = gf_mulfix(end_col.red - start_col.red, frac) + start_col.red; fcol.green = gf_mulfix(end_col.green - start_col.green, frac) + start_col.green; fcol.blue = gf_mulfix(end_col.blue - start_col.blue, frac) + start_col.blue; fcol.alpha = FIX_ONE; } vx.color = MESH_MAKE_COL(fcol); vx.pos.y = gf_sin(GF_PI2 - angle); r = gf_sqrt(FIX_ONE - gf_mulfix(vx.pos.y, vx.pos.y)); new_idx = mesh->v_count; for (j = 0; j < step_div_h; j++) { SFVec3f n; Fixed lon = 2 * GF_PI * j / step_div_h; vx.pos.x = gf_mulfix(gf_sin(lon), r); vx.pos.z = gf_mulfix(gf_cos(lon), r); n = gf_vec_scale(vx.pos, FIX_ONE /*-FIX_ONE*/); gf_vec_norm(&n); MESH_SET_NORMAL(vx, n); mesh_set_vertex_vx(mesh, &vx); if (j) { if (i>1) { mesh_set_triangle(mesh, last_idx+j, new_idx+j, new_idx+j-1); mesh_set_triangle(mesh, last_idx+j, new_idx+j-1, last_idx+j-1); } else { mesh_set_triangle(mesh, 0, new_idx+j, new_idx+j-1); } } } if (i>1) { mesh_set_triangle(mesh, last_idx, new_idx, new_idx+step_div_h-1); mesh_set_triangle(mesh, last_idx, new_idx+step_div_h-1, last_idx+step_div_h-1); } else { mesh_set_triangle(mesh, 0, new_idx, new_idx+step_div_h-1); } last_idx = new_idx; } if (!ground_dome) { new_idx = mesh->v_count; vx.pos.x = vx.pos.z = 0; vx.pos.y = -FIX_ONE; vx.normal.x = vx.normal.z = 0; vx.normal.y = MESH_NORMAL_UNIT; mesh_set_vertex_vx(mesh, &vx); for (j=1; j < step_div_h; j++) { mesh_set_triangle(mesh, last_idx+j-1, last_idx+j, new_idx); } mesh_set_triangle(mesh, last_idx+step_div_h-1, last_idx, new_idx); } mesh->flags |= MESH_HAS_COLOR | MESH_NO_TEXTURE; mesh_update_bounds(mesh); }