Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
//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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}
Beispiel #7
0
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;
}
Beispiel #8
0
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)));
}
Beispiel #9
0
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;
}
Beispiel #10
0
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);
}