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; }
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; }
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); }