static GF_Err svg_rect_add_arc(GF_Path *gp, Fixed end_x, Fixed end_y, Fixed cx, Fixed cy, Fixed rx, Fixed ry) { Fixed angle, start_angle, end_angle, sweep, _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; //start angle and end angle start_angle = gf_atan2(start_y-cy, start_x-cx); end_angle = gf_atan2(end_y-cy, end_x-cx); sweep = end_angle - start_angle; if (sweep<0) sweep += 2*GF_PI; num_steps = 16; for (i=1; i<=num_steps; i++) { angle = start_angle + sweep*i/num_steps; _vx = cx + gf_mulfix(rx, gf_cos(angle)); _vy = cy + gf_mulfix(ry, gf_sin(angle)); gf_path_add_line_to(gp, _vx, _vy); } return GF_OK; }
void camera_set_vectors(GF_Camera *cam, SFVec3f pos, SFRotation ori, Fixed fov) { Fixed sin_a, cos_a, icos_a, tmp; cam->fieldOfView = fov; cam->last_pos = cam->position; cam->position = pos; /*compute up & target vectors in local system*/ sin_a = gf_sin(ori.q); cos_a = gf_cos(ori.q); icos_a = FIX_ONE - cos_a; tmp = gf_mulfix(icos_a, ori.z); cam->target.x = gf_mulfix(ori.x, tmp) + gf_mulfix(sin_a, ori.y); cam->target.y = gf_mulfix(ori.y, tmp) - gf_mulfix(sin_a, ori.x); cam->target.z = gf_mulfix(ori.z, tmp) + cos_a; gf_vec_norm(&cam->target); cam->target = gf_vec_scale(cam->target, -cam->vp_dist); gf_vec_add(cam->target, cam->target, pos); tmp = gf_mulfix(icos_a, ori.y); cam->up.x = gf_mulfix(ori.x, tmp) - gf_mulfix(sin_a, ori.z); cam->up.y = gf_mulfix(ori.y, tmp) + cos_a; cam->up.z = gf_mulfix(ori.z, tmp) + gf_mulfix(sin_a, ori.x); gf_vec_norm(&cam->up); cam->flags |= CAM_IS_DIRTY; }
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; }
GF_EXPORT GF_Err gf_path_add_ellipse(GF_Path *gp, Fixed cx, Fixed cy, Fixed a_axis, Fixed b_axis) { GF_Err e; Fixed _vx, _vy, cur; u32 i; a_axis /= 2; b_axis /= 2; e = gf_path_add_move_to(gp, cx+a_axis, cy); if (e) return e; for (i=1; i<GF_2D_DEFAULT_RES; i++) { cur = GF_2PI*i/GF_2D_DEFAULT_RES; _vx = gf_mulfix(a_axis, gf_cos(cur) ); _vy = gf_mulfix(b_axis, gf_sin(cur) ); e = gf_path_add_line_to(gp, _vx + cx, _vy + cy); if (e) return e; } return gf_path_close(gp); }
GF_EXPORT GF_Err gf_path_add_arc(GF_Path *gp, Fixed radius, Fixed start_angle, Fixed end_angle, u32 close_type) { GF_Err e; Fixed _vx, _vy, step, cur; s32 i, do_run; step = (end_angle - start_angle) / (GF_2D_DEFAULT_RES); radius *= 2; /*pie*/ i=0; if (close_type==2) { gf_path_add_move_to(gp, 0, 0); i=1; } do_run = 1; cur=start_angle; while (do_run) { if (cur>=end_angle) { do_run = 0; cur = end_angle; } _vx = gf_mulfix(radius, gf_cos(cur)); _vy = gf_mulfix(radius, gf_sin(cur)); if (!i) { e = gf_path_add_move_to(gp, _vx, _vy); i = 1; } else { e = gf_path_add_line_to(gp, _vx, _vy); } if (e) return e; cur+=step; } if (close_type) e = gf_path_close(gp); return e; }
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; }
//parses a rotation GF_Err Q_DecRotation(GF_BifsDecoder *codec, GF_BitStream *bs, u32 NbBits, void *field_ptr) { u32 i; Fixed q, sin2, comp[4]; GF_Err e; e = Q_DecCoordOnUnitSphere(codec, bs, NbBits, 3, comp); if (e) return e; q = 2 * gf_acos(comp[0]); sin2 = gf_sin(q / 2); if (ABS(sin2) <= FIX_EPSILON) { for (i=1; i<4; i++) comp[i] = 0; comp[3] = FIX_ONE; } else { for (i=1; i<4; i++) comp[i] = gf_divfix(comp[i], sin2); } ((SFRotation *)field_ptr)->x = comp[1]; ((SFRotation *)field_ptr)->y = comp[2]; ((SFRotation *)field_ptr)->z = comp[3]; ((SFRotation *)field_ptr)->q = q; return GF_OK; }
static void NLD_Apply(M_NonLinearDeformer *nld, GF_Mesh *mesh) { u32 i; GF_Matrix mx; SFVec3f n; Fixed param, z_min, z_max, v_min, v_max, f_min, f_max, frac, val, a_cos, a_sin; Bool needs_transform = NLD_GetMatrix(nld, &mx); param = nld->param; if (!param) param = 1; if (mesh->bounds.min_edge.z == mesh->bounds.max_edge.z) return; z_min = FIX_MAX; z_max = -FIX_MAX; if (needs_transform) { for (i=0; i<mesh->v_count; i++) { gf_mx_apply_vec(&mx, &mesh->vertices[i].pos); MESH_GET_NORMAL(n, mesh->vertices[i]); gf_mx_rotate_vector(&mx, &n); MESH_SET_NORMAL(mesh->vertices[i], n); if (mesh->vertices[i].pos.z<z_min) z_min = mesh->vertices[i].pos.z; if (mesh->vertices[i].pos.z>z_max) z_max = mesh->vertices[i].pos.z; } } else { z_min = mesh->bounds.min_edge.z; z_max = mesh->bounds.max_edge.z; } for (i=0; i<mesh->v_count; i++) { SFVec3f old = mesh->vertices[i].pos; frac = gf_divfix(old.z - z_min, z_max - z_min); NLD_GetKey(nld, frac, &f_min, &v_min, &f_max, &v_max); if (f_max == f_min) { val = v_min; } else { frac = gf_divfix(frac-f_min, f_max - f_min); val = gf_mulfix(v_max - v_min, frac) + v_min; } val = gf_mulfix(val, param); switch (nld->type) { /*taper*/ case 0: mesh->vertices[i].pos.x = gf_mulfix(mesh->vertices[i].pos.x, val); mesh->vertices[i].pos.y = gf_mulfix(mesh->vertices[i].pos.y, val); MESH_GET_NORMAL(old, mesh->vertices[i]); n=old; n.x = gf_mulfix(n.x, val); n.y = gf_mulfix(n.y, val); gf_vec_norm(&n); MESH_SET_NORMAL(mesh->vertices[i], n); break; /*twist*/ case 1: a_cos = gf_cos(val); a_sin = gf_sin(val); mesh->vertices[i].pos.x = gf_mulfix(a_cos, old.x) - gf_mulfix(a_sin, old.y); mesh->vertices[i].pos.y = gf_mulfix(a_sin, old.x) + gf_mulfix(a_cos, old.y); MESH_GET_NORMAL(old, mesh->vertices[i]); n=old; n.x = gf_mulfix(a_cos, old.x) - gf_mulfix(a_sin, old.y); n.y = gf_mulfix(a_sin, old.x) + gf_mulfix(a_cos, old.y); gf_vec_norm(&n); MESH_SET_NORMAL(mesh->vertices[i], n); break; /*bend*/ case 2: a_cos = gf_cos(val); a_sin = gf_sin(val); mesh->vertices[i].pos.x = gf_mulfix(a_sin, old.z) + gf_mulfix(a_cos, old.x); mesh->vertices[i].pos.z = gf_mulfix(a_cos, old.z) - gf_mulfix(a_sin, old.x); MESH_GET_NORMAL(old, mesh->vertices[i]); n=old; n.x = gf_mulfix(a_sin, old.z) + gf_mulfix(a_cos, old.x); n.z = gf_mulfix(a_cos, old.z) - gf_mulfix(a_sin, old.x); gf_vec_norm(&n); MESH_SET_NORMAL(mesh->vertices[i], n); break; /*pinch, not standard (taper on X dim only)*/ case 3: mesh->vertices[i].pos.x = gf_mulfix(mesh->vertices[i].pos.x, val); MESH_GET_NORMAL(old, mesh->vertices[i]); n=old; n.x = gf_mulfix(n.x, val); gf_vec_norm(&n); MESH_SET_NORMAL(mesh->vertices[i], n); break; } } if (needs_transform) { gf_mx_inverse(&mx); for (i=0; i<mesh->v_count; i++) { gf_mx_apply_vec(&mx, &mesh->vertices[i].pos); MESH_GET_NORMAL(n, mesh->vertices[i]); gf_mx_rotate_vector(&mx, &n); MESH_SET_NORMAL(mesh->vertices[i], n); } } mesh_update_bounds(mesh); gf_mesh_build_aabbtree(mesh); }
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; }
Bool gf_sc_fit_world_to_screen(GF_Compositor *compositor) { GF_TraverseState tr_state; SFVec3f pos, diff; Fixed dist, d; GF_Camera *cam; GF_Node *top; #ifndef GPAC_DISABLE_VRML // if (gf_list_count(compositor->visual->back_stack)) return; if (gf_list_count(compositor->visual->view_stack)) return 0; #endif gf_mx_p(compositor->mx); top = gf_sg_get_root_node(compositor->scene); if (!top) { gf_mx_v(compositor->mx); return 0; } memset(&tr_state, 0, sizeof(GF_TraverseState)); gf_mx_init(tr_state.model_matrix); tr_state.traversing_mode = TRAVERSE_GET_BOUNDS; tr_state.visual = compositor->visual; gf_node_traverse(top, &tr_state); if (gf_node_dirty_get(top)) { tr_state.bbox.is_set = 0; } if (!tr_state.bbox.is_set) { gf_mx_v(compositor->mx); /*empty world ...*/ if (tr_state.bbox.radius==-1) return 1; /*2D world with 3D camera forced*/ if (tr_state.bounds.width&&tr_state.bounds.height) return 1; return 0; } cam = &compositor->visual->camera; cam->world_bbox = tr_state.bbox; /*fit is based on bounding sphere*/ dist = gf_divfix(tr_state.bbox.radius, gf_sin(cam->fieldOfView/2) ); gf_vec_diff(diff, cam->center, tr_state.bbox.center); /*do not update if camera is outside the scene bounding sphere and dist is too close*/ if (gf_vec_len(diff) > tr_state.bbox.radius + cam->radius) { gf_vec_diff(diff, cam->vp_position, tr_state.bbox.center); d = gf_vec_len(diff); if (d<dist) { gf_mx_v(compositor->mx); return 1; } } diff = gf_vec_scale(camera_get_pos_dir(cam), dist); gf_vec_add(pos, tr_state.bbox.center, diff); diff = cam->position; camera_set_vectors(cam, pos, cam->vp_orientation, cam->fieldOfView); cam->position = diff; camera_move_to(cam, pos, cam->target, cam->up); cam->examine_center = tr_state.bbox.center; cam->flags |= CF_STORE_VP; if (cam->z_far < dist) cam->z_far = 10*dist; camera_changed(compositor, cam); gf_mx_v(compositor->mx); return 1; }
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); }