GF_EXPORT GF_Err gf_path_add_arc_to(GF_Path *gp, Fixed end_x, Fixed end_y, Fixed fa_x, Fixed fa_y, Fixed fb_x, Fixed fb_y, Bool cw) { GF_Matrix2D mat, inv; Fixed angle, start_angle, end_angle, sweep, axis_w, axis_h, tmp, cx, cy, _vx, _vy, start_x, start_y; s32 i, num_steps; if (!gp->n_points) return GF_BAD_PARAM; start_x = gp->points[gp->n_points-1].x; start_y = gp->points[gp->n_points-1].y; cx = (fb_x + fa_x)/2; cy = (fb_y + fa_y)/2; angle = gf_atan2(fb_y-fa_y, fb_x-fa_x); gf_mx2d_init(mat); gf_mx2d_add_rotation(&mat, 0, 0, angle); gf_mx2d_add_translation(&mat, cx, cy); gf_mx2d_copy(inv, mat); gf_mx2d_inverse(&inv); gf_mx2d_apply_coords(&inv, &start_x, &start_y); gf_mx2d_apply_coords(&inv, &end_x, &end_y); gf_mx2d_apply_coords(&inv, &fa_x, &fa_y); gf_mx2d_apply_coords(&inv, &fb_x, &fb_y); //start angle and end angle start_angle = gf_atan2(start_y, start_x); end_angle = gf_atan2(end_y, end_x); tmp = gf_mulfix((start_x - fa_x), (start_x - fa_x)) + gf_mulfix((start_y - fa_y), (start_y - fa_y)); axis_w = gf_sqrt(tmp); tmp = gf_mulfix((start_x - fb_x) , (start_x - fb_x)) + gf_mulfix((start_y - fb_y), (start_y - fb_y)); axis_w += gf_sqrt(tmp); axis_w /= 2; axis_h = gf_sqrt(gf_mulfix(axis_w, axis_w) - gf_mulfix(fa_x,fa_x)); sweep = end_angle - start_angle; if (cw) { if (sweep>0) sweep -= 2*GF_PI; } else { if (sweep<0) sweep += 2*GF_PI; } num_steps = GF_2D_DEFAULT_RES/2; for (i=1; i<=num_steps; i++) { angle = start_angle + sweep*i/num_steps; _vx = gf_mulfix(axis_w, gf_cos(angle)); _vy = gf_mulfix(axis_h, gf_sin(angle)); /*re-invert*/ gf_mx2d_apply_coords(&mat, &_vx, &_vy); gf_path_add_line_to(gp, _vx, _vy); } return GF_OK; }
static Bool NLD_GetMatrix(M_NonLinearDeformer *nld, GF_Matrix *mx) { SFVec3f v1, v2; SFRotation r; Fixed l1, l2, dot; /*compute rotation matrix from NLD axis to 0 0 1*/ v1 = nld->axis; gf_vec_norm(&v1); v2.x = v2.y = 0; v2.z = FIX_ONE; if (gf_vec_equal(v1, v2)) return 0; l1 = gf_vec_len(v1); l2 = gf_vec_len(v2); dot = gf_divfix(gf_vec_dot(v1, v2), gf_mulfix(l1, l2)); r.x = gf_mulfix(v1.y, v2.z) - gf_mulfix(v2.y, v1.z); r.y = gf_mulfix(v1.z, v2.x) - gf_mulfix(v2.z, v1.x); r.z = gf_mulfix(v1.x, v2.y) - gf_mulfix(v2.x, v1.y); r.q = gf_atan2(gf_sqrt(FIX_ONE - gf_mulfix(dot, dot)), dot); gf_mx_init(*mx); gf_mx_add_rotation(mx, r.q, r.x, r.y, r.z); return 1; }
//SFRotation and SFVec3f are quantized as normalized vectors ,mapped on a cube //in the UnitSphere (R=1.0) GF_Err Q_DecCoordOnUnitSphere(GF_BifsDecoder *codec, GF_BitStream *bs, u32 NbBits, u32 NbComp, Fixed *m_ft) { u32 i, orient, sign; s32 value; Fixed tang[4], delta; s32 dir; if (NbComp != 2 && NbComp != 3) return GF_BAD_PARAM; //only 2 or 3 comp in the quantized version dir = 1; if(NbComp == 2) dir -= 2 * gf_bs_read_int(bs, 1); orient = gf_bs_read_int(bs, 2); for(i=0; i<NbComp; i++) { value = gf_bs_read_int(bs, NbBits) - (1 << (NbBits-1) ); sign = (value >= 0) ? 1 : -1; m_ft[i] = sign * Q_InverseQuantize(0, 1, NbBits-1, sign*value); } delta = 1; for (i=0; i<NbComp; i++) { tang[i] = gf_tan(gf_mulfix(GF_PI/4, m_ft[i]) ); delta += gf_mulfix(tang[i], tang[i]); } delta = gf_divfix(INT2FIX(dir), gf_sqrt(delta) ); m_ft[orient] = delta; for (i=0; i<NbComp; i++) { m_ft[ (orient + i+1) % (NbComp+1) ] = gf_mulfix(tang[i], delta); } return GF_OK; }
GF_EXPORT GF_PathIterator *gf_path_iterator_new(GF_Path *gp) { GF_Path *flat; GF_PathIterator *it; u32 i, j, cur; GF_Point2D start, end; GF_SAFEALLOC(it, GF_PathIterator); if (!it) return NULL; flat = gf_path_get_flatten(gp); if (!flat) { gf_free(it); return NULL; } it->seg = (IterInfo *) gf_malloc(sizeof(IterInfo) * flat->n_points); it->num_seg = 0; it->length = 0; cur = 0; for (i=0; i<flat->n_contours; i++) { Fixed dx, dy; u32 nb_pts = 1+flat->contours[i]-cur; start = flat->points[cur]; for (j=1; j<nb_pts; j++) { end = flat->points[cur+j]; it->seg[it->num_seg].start_x = start.x; it->seg[it->num_seg].start_y = start.y; dx = it->seg[it->num_seg].dx = end.x - start.x; dy = it->seg[it->num_seg].dy = end.y - start.y; it->seg[it->num_seg].len = gf_sqrt(gf_mulfix(dx, dx) + gf_mulfix(dy, dy)); it->length += it->seg[it->num_seg].len; start = end; it->num_seg++; } cur += nb_pts; } gf_path_del(flat); return it; }
GF_Err PMF_UnquantizeRotation(PredMF *pmf, GF_FieldInfo *field) { u32 i; void *slot; Fixed comp[4]; Fixed tang[3]; Fixed sine, delta = FIX_ONE; for (i=0; i<3; i++) { Fixed v = PMF_UnquantizeFloat(pmf->current_val[i] - (1<<(pmf->QNbBits - 1)), 0, FIX_ONE, pmf->QNbBits, 1); tang[i] = gf_tan(gf_mulfix(GF_PI / 4, v)); delta += gf_mulfix(tang[i], tang[i]); } delta = gf_divfix(pmf->direction , gf_sqrt(delta) ); comp[(pmf->orientation)%4] = delta; for (i=0; i<3; i++) comp[(pmf->orientation + i+1)%4] = gf_mulfix(tang[i], delta); gf_sg_vrml_mf_get_item(field->far_ptr, field->fieldType, &slot, pmf->cur_field); delta = 2 * gf_acos(comp[0]); sine = gf_sin(delta / 2); if (sine != 0) { for(i=1; i<4; i++) comp[i] = gf_divfix(comp[i], sine); ((SFRotation *)slot)->x = comp[1]; ((SFRotation *)slot)->y = comp[2]; ((SFRotation *)slot)->z = comp[3]; } else { ((SFRotation *)slot)->x = FIX_ONE; ((SFRotation *)slot)->y = 0; ((SFRotation *)slot)->z = 0; } ((SFRotation *)slot)->q = delta; return GF_OK; }
GF_Err PMF_UnquantizeNormal(PredMF *pmf, GF_FieldInfo *field) { void *slot; Fixed comp[3]; Fixed tang[2]; u32 i; Fixed delta=FIX_ONE; for (i=0; i<2; i++) { Fixed v = PMF_UnquantizeFloat(pmf->current_val[i] - (1<< (pmf->QNbBits -1) ), 0 , FIX_ONE, pmf->QNbBits, 1); tang[i]= gf_tan(gf_mulfix(GF_PI * 4, v)); delta += gf_mulfix(tang[i], tang[i]); } delta = gf_divfix(pmf->direction, gf_sqrt(delta) ); comp[(pmf->orientation) % 3] = delta; for (i=0; i<2; i++) comp[(pmf->orientation + i+1)%3] = gf_mulfix(tang[i], delta); gf_sg_vrml_mf_get_item(field->far_ptr, field->fieldType, &slot, pmf->cur_field); ((SFVec3f *)slot)->x = comp[0]; ((SFVec3f *)slot)->y = comp[1]; ((SFVec3f *)slot)->z = comp[2]; return GF_OK; }
GF_EXPORT GF_Err gf_path_add_svg_arc_to(GF_Path *gp, Fixed end_x, Fixed end_y, Fixed r_x, Fixed r_y, Fixed x_axis_rotation, Bool large_arc_flag, Bool sweep_flag) { Fixed start_x, start_y; Fixed xmid,ymid; Fixed xmidp,ymidp; Fixed xmidpsq,ymidpsq; Fixed phi, cos_phi, sin_phi; Fixed c_x, c_y; Fixed cxp, cyp; Fixed scale; Fixed rxsq, rysq; Fixed start_angle, sweep_angle; Fixed radius_scale; Fixed vx, vy, normv; Fixed ux, uy, normu; Fixed sign; u32 i, num_steps; if (!gp->n_points) return GF_BAD_PARAM; if (!r_x || !r_y) { gf_path_add_line_to(gp, end_x, end_y); return GF_OK; } if (r_x < 0) r_x = -r_x; if (r_y < 0) r_y = -r_y; start_x = gp->points[gp->n_points-1].x; start_y = gp->points[gp->n_points-1].y; phi = gf_mulfix(gf_divfix(x_axis_rotation, 180), GF_PI); cos_phi = gf_cos(phi); sin_phi = gf_sin(phi); xmid = (start_x - end_x)/2; ymid = (start_y - end_y)/2; if (!xmid && !ymid) { gf_path_add_line_to(gp, end_x, end_y); return GF_OK; } xmidp = gf_mulfix(cos_phi, xmid) + gf_mulfix(sin_phi, ymid); ymidp = gf_mulfix(-sin_phi, xmid) + gf_mulfix(cos_phi, ymid); xmidpsq = gf_mulfix(xmidp, xmidp); ymidpsq = gf_mulfix(ymidp, ymidp); rxsq = gf_mulfix(r_x, r_x); rysq = gf_mulfix(r_y, r_y); assert(rxsq && rxsq); radius_scale = gf_divfix(xmidpsq, rxsq) + gf_divfix(ymidpsq, rysq); if (radius_scale > FIX_ONE) { r_x = gf_mulfix(gf_sqrt(radius_scale), r_x); r_y = gf_mulfix(gf_sqrt(radius_scale), r_y); rxsq = gf_mulfix(r_x, r_x); rysq = gf_mulfix(r_y, r_y); } #if 0 /* Old code with overflow problems in fixed point, sign was sometimes negative (cf tango SVG icons appointment-new.svg)*/ sign = gf_mulfix(rxsq,ymidpsq) + gf_mulfix(rysq, xmidpsq); scale = FIX_ONE; /*FIXME - what if scale is 0 ??*/ if (sign) scale = gf_divfix( (gf_mulfix(rxsq,rysq) - gf_mulfix(rxsq, ymidpsq) - gf_mulfix(rysq,xmidpsq)), sign ); #else /* New code: the sign variable computation is split into simpler cases and the expression is divided by rxsq to reduce the range */ if ((rxsq == 0 || ymidpsq ==0) && (rysq == 0 || xmidpsq == 0)) { scale = FIX_ONE; } else if (rxsq == 0 || ymidpsq ==0) { scale = gf_divfix(rxsq,xmidpsq) - FIX_ONE; } else if (rysq == 0 || xmidpsq == 0) { scale = gf_divfix(rysq,ymidpsq) - FIX_ONE; } else { Fixed tmp; tmp = gf_mulfix(gf_divfix(rysq, rxsq), xmidpsq); sign = ymidpsq + tmp; scale = gf_divfix((rysq - ymidpsq - tmp),sign); } #endif /* precision problem may lead to negative value around zero, we need to take care of it before sqrt */ scale = gf_sqrt(ABS(scale)); cxp = gf_mulfix(scale, gf_divfix(gf_mulfix(r_x, ymidp),r_y)); cyp = gf_mulfix(scale, -gf_divfix(gf_mulfix(r_y, xmidp),r_x)); cxp = (large_arc_flag == sweep_flag ? - cxp : cxp); cyp = (large_arc_flag == sweep_flag ? - cyp : cyp); c_x = gf_mulfix(cos_phi, cxp) - gf_mulfix(sin_phi, cyp) + (start_x + end_x)/2; c_y = gf_mulfix(sin_phi, cxp) + gf_mulfix(cos_phi, cyp) + (start_y + end_y)/2; ux = FIX_ONE; uy = 0; normu = FIX_ONE; vx = gf_divfix(xmidp-cxp,r_x); vy = gf_divfix(ymidp-cyp,r_y); normv = gf_sqrt(gf_mulfix(vx, vx) + gf_mulfix(vy,vy)); sign = vy; start_angle = gf_acos(gf_divfix(vx,normv)); start_angle = (sign > 0 ? start_angle: -start_angle); ux = vx; uy = vy; normu = normv; vx = gf_divfix(-xmidp-cxp,r_x); vy = gf_divfix(-ymidp-cyp,r_y); normu = gf_sqrt(gf_mulfix(ux, ux) + gf_mulfix(uy,uy)); sign = gf_mulfix(ux, vy) - gf_mulfix(uy, vx); sweep_angle = gf_divfix( gf_mulfix(ux,vx) + gf_mulfix(uy, vy), gf_mulfix(normu, normv) ); /*numerical stability safety*/ sweep_angle = MAX(-FIX_ONE, MIN(sweep_angle, FIX_ONE)); sweep_angle = gf_acos(sweep_angle); sweep_angle = (sign > 0 ? sweep_angle: -sweep_angle); if (sweep_flag == 0) { if (sweep_angle > 0) sweep_angle -= GF_2PI; } else { if (sweep_angle < 0) sweep_angle += GF_2PI; } num_steps = GF_2D_DEFAULT_RES/2; for (i=1; i<=num_steps; i++) { Fixed _vx, _vy; Fixed _vxp, _vyp; Fixed angle = start_angle + sweep_angle*i/num_steps; _vx = gf_mulfix(r_x, gf_cos(angle)); _vy = gf_mulfix(r_y, gf_sin(angle)); _vxp = gf_mulfix(cos_phi, _vx) - gf_mulfix(sin_phi, _vy) + c_x; _vyp = gf_mulfix(sin_phi, _vx) + gf_mulfix(cos_phi, _vy) + c_y; gf_path_add_line_to(gp, _vxp, _vyp); } return GF_OK; }
static Fixed snd_compute_gain(Fixed min_b, Fixed min_f, Fixed max_b, Fixed max_f, SFVec3f pos) { Fixed sqpos_x, sqpos_z; Fixed y_pos, x_pos, dist_ellip, viewp_dist, dist_from_foci_min, dist_from_foci_max, d_min, d_max, sqb_min, sqb_max; Fixed a_in = (min_f+min_b)/2; Fixed b_in = gf_sqrt(gf_mulfix(min_b, min_f)); Fixed alpha_min = (min_f-min_b)/2; Fixed dist_foci_min = (min_f-min_b); Fixed a_out = (max_f+max_b)/2; //first ellipse axis Fixed b_out = gf_sqrt(gf_mulfix(max_b, max_f)); Fixed alpha_max = (max_f-max_b)/2; //origo from focus Fixed dist_foci_max = (max_f-max_b); Fixed x_min = 0; Fixed x_max = 0; Fixed y_min = 0; Fixed y_max = 0; Fixed k = (ABS(pos.z) >= FIX_EPSILON) ? gf_divfix(pos.x, pos.z) : 0; sqpos_x = gf_mulfix(pos.x, pos.x); sqpos_z = gf_mulfix(pos.z, pos.z); dist_from_foci_min = gf_sqrt(sqpos_z + sqpos_x) + gf_sqrt( gf_mulfix(pos.z - dist_foci_min, pos.z - dist_foci_min) + sqpos_x); dist_from_foci_max = gf_sqrt(sqpos_z + sqpos_x) + gf_sqrt( gf_mulfix(pos.z - dist_foci_max, pos.z - dist_foci_max) + sqpos_x); d_min = min_f+min_b; d_max = max_f+max_b; if(dist_from_foci_max > d_max) return 0; else if (dist_from_foci_min <= d_min) return FIX_ONE; sqb_min = gf_mulfix(b_in, b_in); sqb_max = gf_mulfix(b_out, b_out); if (ABS(pos.z) > FIX_ONE/10000) { s32 sign = (pos.z>0) ? 1 : -1; Fixed a_in_k_sq, a_out_k_sq; a_in_k_sq = gf_mulfix(a_in, k); a_in_k_sq = gf_mulfix(a_in_k_sq, a_in_k_sq); x_min = gf_mulfix(alpha_min, sqb_min) + sign*gf_mulfix( gf_mulfix(a_in, b_in), gf_sqrt(a_in_k_sq + sqb_min - gf_mulfix( gf_mulfix(alpha_min, k), gf_mulfix(alpha_min, k)))); x_min = gf_divfix(x_min, sqb_min + a_in_k_sq); y_min = gf_mulfix(k, x_min); a_out_k_sq = gf_mulfix(a_out, k); a_out_k_sq = gf_mulfix(a_out_k_sq, a_out_k_sq); x_max = gf_mulfix(alpha_max, sqb_max) + sign*gf_mulfix( gf_mulfix(a_out, b_out), gf_sqrt( a_out_k_sq + sqb_max - gf_mulfix( gf_mulfix(alpha_max, k), gf_mulfix(alpha_max, k)))); x_max = gf_divfix(x_max, sqb_max + a_out_k_sq); y_max = gf_mulfix(k, x_max); } else { x_min = x_max = 0; y_min = gf_mulfix(b_in, gf_sqrt(FIX_ONE - gf_mulfix( gf_divfix(alpha_min,a_in), gf_divfix(alpha_min,a_in)) ) ); y_max = gf_mulfix(b_out, gf_sqrt(FIX_ONE - gf_mulfix( gf_divfix(alpha_max,a_out), gf_divfix(alpha_max,a_out)) ) ); } y_pos = gf_sqrt(sqpos_x) - y_min; x_pos = pos.z - x_min; x_max -= x_min; y_max -= y_min; dist_ellip = gf_sqrt( gf_mulfix(y_max, y_max) + gf_mulfix(x_max, x_max)); viewp_dist = gf_sqrt( gf_mulfix(y_pos, y_pos) + gf_mulfix(x_pos, x_pos)); viewp_dist = gf_divfix(viewp_dist, dist_ellip); return FLT2FIX ( (Float) pow(10.0,- FIX2FLT(viewp_dist))); }
static void TraverseSound(GF_Node *node, void *rs, Bool is_destroy) { GF_TraverseState *tr_state = (GF_TraverseState*) rs; M_Sound *snd = (M_Sound *)node; SoundStack *st = (SoundStack *)gf_node_get_private(node); if (is_destroy) { gf_free(st); return; } if (!snd->source) return; tr_state->sound_holder = &st->snd_ifce; /*forward in case we're switched off*/ if (tr_state->switched_off) { gf_node_traverse((GF_Node *) snd->source, tr_state); } else if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) { /*we can't cull sound since*/ tr_state->disable_cull = 1; } else if (tr_state->traversing_mode==TRAVERSE_SORT) { GF_Matrix mx; SFVec3f usr, snd_dir, pos; Fixed mag, ang; /*this implies no DEF/USE for real location...*/ gf_mx_copy(st->mx, tr_state->model_matrix); gf_mx_copy(mx, tr_state->model_matrix); gf_mx_inverse(&mx); snd_dir = snd->direction; gf_vec_norm(&snd_dir); /*get user location*/ usr = tr_state->camera->position; gf_mx_apply_vec(&mx, &usr); /*recenter to ellipse focal*/ gf_vec_diff(usr, usr, snd->location); mag = gf_vec_len(usr); if (!mag) mag = FIX_ONE/10; ang = gf_divfix(gf_vec_dot(snd_dir, usr), mag); usr.z = gf_mulfix(ang, mag); usr.x = gf_sqrt(gf_mulfix(mag, mag) - gf_mulfix(usr.z, usr.z)); usr.y = 0; if (!gf_vec_equal(usr, st->last_pos)) { st->intensity = snd_compute_gain(snd->minBack, snd->minFront, snd->maxBack, snd->maxFront, usr); st->intensity = gf_mulfix(st->intensity, snd->intensity); st->last_pos = usr; } st->identity = (st->intensity==FIX_ONE) ? 1 : 0; if (snd->spatialize) { Fixed ang, sign; SFVec3f cross; pos = snd->location; gf_mx_apply_vec(&tr_state->model_matrix, &pos); gf_vec_diff(pos, pos, tr_state->camera->position); gf_vec_diff(usr, tr_state->camera->target, tr_state->camera->position); gf_vec_norm(&pos); gf_vec_norm(&usr); ang = gf_acos(gf_vec_dot(usr, pos)); /*get orientation*/ cross = gf_vec_cross(usr, pos); sign = gf_vec_dot(cross, tr_state->camera->up); if (sign>0) ang *= -1; ang = (FIX_ONE + gf_sin(ang)) / 2; st->lgain = (FIX_ONE - gf_mulfix(ang, ang)); st->rgain = FIX_ONE - gf_mulfix(FIX_ONE - ang, FIX_ONE - ang); /*renorm between 0 and 1*/ st->lgain = gf_mulfix(st->lgain, 4*st->intensity/3); st->rgain = gf_mulfix(st->rgain, 4*st->intensity/3); if (st->identity && ((st->lgain!=FIX_ONE) || (st->rgain!=FIX_ONE))) st->identity = 0; } else { st->lgain = st->rgain = FIX_ONE; } gf_node_traverse((GF_Node *) snd->source, tr_state); } tr_state->sound_holder = NULL; }
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); }