static void mesh_extrude_path_intern()

in src/compositor/mesh.c [1693:2295]


static void mesh_extrude_path_intern(GF_Mesh *mesh, GF_Path *path, MFVec3f *thespine, Fixed creaseAngle, Fixed min_cx, Fixed min_cy, Fixed width_cx, Fixed width_cy, Bool begin_cap, Bool end_cap, MFRotation *spine_ori, MFVec2f *spine_scale, Bool tx_along_spine)
{
	GF_Mesh **faces;
	GF_Vertex vx;
	struct face_info *faces_info;
	struct pt_info *pts_info;
	GF_Matrix mx;
	SCP *SCPs, SCPbegin, SCPend;
	SCPInfo *SCPi;
	Bool smooth_normals, spine_closed, check_first_spine_vec, do_close;
	u32 i, j, k, nb_scp, nb_spine, face_count, pt_count, faces_per_cross, begin_face, end_face, face_spines, pts_per_cross, cur_pts_in_cross,cur, nb_pts, convexity;
	SFVec3f *spine, v1, v2, n, spine_vec;
	Fixed cross_len, spine_len, cur_cross, cur_spine;
	SFRotation r;
	SFVec2f scale;

	if (!path->n_contours) return;
	if (path->n_points<2) return;
	if (thespine->count<2) return;

	spine_closed = 0;
	if (gf_vec_equal(thespine->vals[0], thespine->vals[thespine->count-1])) spine_closed = 1;
	if (spine_closed && (thespine->count==2)) return;

	gf_path_flatten(path);

	memset(&vx, 0, sizeof(GF_Vertex));
	pts_per_cross = 0;
	cross_len = 0;
	cur = 0;
	for (i=0; i<path->n_contours; i++) {
		nb_pts = 1 + path->contours[i] - cur;
		pts_per_cross += nb_pts;
		v1.z = 0;
		for (j=1; j<nb_pts; j++) {
			v1.x = path->points[j+cur].x - path->points[j-1+cur].x;
			v1.y = path->points[j+cur].y - path->points[j-1+cur].y;
			cross_len += gf_vec_len(v1);
		}
	}

	faces_per_cross	= pts_per_cross - path->n_contours;
	begin_face = end_face = 0;
	face_spines = face_count = (thespine->count-1)*faces_per_cross;
	if (begin_cap) {
		begin_face = face_count;
		face_count ++;
	}
	if (end_cap) {
		end_face = face_count;
		face_count ++;
	}

	pt_count = pts_per_cross * thespine->count;
	smooth_normals = NEAR_ZERO(creaseAngle) ? 0 : 1;

	faces = (GF_Mesh**)gf_malloc(sizeof(GF_Mesh *)*face_count);
	for (i=0; i<face_count; i++) faces[i] = new_mesh();
	faces_info = NULL;
	pts_info = NULL;

	/*alloc face & normals tables*/
	if (smooth_normals) {
		faces_info = (struct face_info*)gf_malloc(sizeof(struct face_info)*face_count);
		memset(faces_info, 0, sizeof(struct face_info)*face_count);
		pts_info = (struct pt_info*)gf_malloc(sizeof(struct pt_info)*pt_count);
		memset(pts_info, 0, sizeof(struct pt_info)*pt_count);
	}


	spine = thespine->vals;
	nb_spine = thespine->count;
	SCPs = (SCP *)gf_malloc(sizeof(SCP) * nb_spine);
	memset(SCPs, 0, sizeof(SCP) * nb_spine);
	SCPi = (SCPInfo *) gf_malloc(sizeof(SCPInfo) * nb_spine);
	memset(SCPi, 0, sizeof(SCPInfo) * nb_spine);

	/*collect all # SCPs:
	1- if a spine has identical consecutive points with # orientation, these points use the same SCPs
	2- if 2 segs of the spine are colinear, they also use the same SCP
	*/
	SCPi[0].pt = spine[0];
	SCPi[0].max_idx = 0;
	nb_scp=1;
	spine_len = 0;
	check_first_spine_vec = 1;
	for (i=1; i<nb_spine; i++) {
		Fixed len;
		/*also get spine length for txcoord*/
		gf_vec_diff(v2, spine[i], spine[i-1]);
		len = gf_vec_len(v2);
		spine_len += len;
		if (check_first_spine_vec && len) {
			check_first_spine_vec = 0;
			spine_vec = v2;
		}

		/*case 1: same point, same SCP*/
		if (gf_vec_equal(SCPi[nb_scp-1].pt, spine[i])) {
			SCPi[nb_scp-1].max_idx = i;
			continue;
		}
		/*last point in spine*/
		if (i+1 == nb_spine) {
			nb_scp++;
			SCPi[nb_scp-1].pt = spine[i];
			SCPi[nb_scp-1].max_idx = i;
			break;
		}

		gf_vec_diff(v1, spine[i+1], spine[i]);
		gf_vec_diff(v2, SCPi[nb_scp-1].pt, spine[i]);
		n = gf_vec_cross(v1, v2);
		/*case 2: spine segs are colinear*/
		if (!n.x && !n.y && !n.z) {
			SCPi[nb_scp-1].max_idx = i;
		}
		/*OK new SCP*/
		else {
			nb_scp++;
			SCPi[nb_scp-1].pt = spine[i];
			SCPi[nb_scp-1].max_idx = i;
		}
	}

	/*all colinear!!*/
	if (nb_scp<=2) {
		SCPi[0].xaxis.x = FIX_ONE;
		SCPi[0].xaxis.y = 0;
		SCPi[0].xaxis.z = 0;
		SCPi[0].yaxis.x = 0;
		SCPi[0].yaxis.y = FIX_ONE;
		SCPi[0].yaxis.z = 0;
		SCPi[0].zaxis.x = 0;
		SCPi[0].zaxis.y = 0;
		SCPi[0].zaxis.z = FIX_ONE;
		/*compute rotation from (0, 1, 0) to spine_vec*/
		if (!check_first_spine_vec) {
			Fixed alpha, gamma;
			Fixed cos_a, sin_a, sin_g, cos_g;

			gf_vec_norm(&spine_vec);
			if (! NEAR_ZERO(spine_vec.x) ) {
				if (spine_vec.x >= FIX_ONE-FIX_EPSILON) alpha = GF_PI2;
				else if (spine_vec.x <= -FIX_ONE+FIX_EPSILON) alpha = -GF_PI2;
				else alpha = gf_asin(spine_vec.x);
				cos_a = gf_cos(alpha);
				sin_a = spine_vec.x;
				sin_g = 0;
				if (NEAR_ZERO(cos_a)) gamma = 0;
				else {
					Fixed __abs;
					gamma = gf_acos(gf_divfix(spine_vec.y, cos_a));
					sin_g = gf_sin(gamma);
					__abs = gf_divfix(spine_vec.z, cos_a) + sin_g;
					if (ABS(__abs) > ABS(sin_g) ) gamma *= -1;
				}
				cos_g = gf_cos(gamma);
				if (NEAR_ZERO(cos_g)) {
					cos_g = 0;
					sin_g = FIX_ONE;
				} else {
					sin_g = gf_sin(gamma);
				}
				SCPi[0].yaxis.y = gf_mulfix(cos_a, sin_g);
				SCPi[0].yaxis.z = gf_mulfix(cos_a, cos_g);
				SCPi[0].yaxis.x = sin_a;
				SCPi[0].zaxis.y = -gf_mulfix(sin_a, sin_g);
				SCPi[0].zaxis.z = -gf_mulfix(sin_a, cos_g);
				SCPi[0].zaxis.x = cos_a;
			}
			if (! NEAR_ZERO(spine_vec.z) ) {
				if (spine_vec.z >= FIX_ONE-FIX_EPSILON) alpha = GF_PI2;
				else if (spine_vec.z <= -FIX_ONE+FIX_EPSILON) alpha = -GF_PI2;
				else alpha = gf_asin(spine_vec.z);
				cos_a = gf_cos(alpha);
				sin_a = spine_vec.z;
				sin_g = 0;
				if (NEAR_ZERO(cos_a) ) gamma = 0;
				else {
					Fixed __abs;
					gamma = gf_acos(gf_divfix(spine_vec.y, cos_a));
					sin_g = gf_sin(gamma);
					__abs = gf_divfix(spine_vec.x, cos_a) + sin_g;
					if (ABS(__abs) > ABS(sin_g) ) gamma *= -1;
				}
				cos_g = gf_cos(gamma);
				sin_g = gf_sin(gamma);
				SCPi[0].yaxis.y = gf_mulfix(cos_a, sin_g);
				SCPi[0].yaxis.x = gf_mulfix(cos_a, cos_g);
				SCPi[0].yaxis.z = sin_a;
				SCPi[0].zaxis.y = -gf_mulfix(sin_a, sin_g);
				SCPi[0].zaxis.x = -gf_mulfix(sin_a, cos_g);
				SCPi[0].zaxis.z = cos_a;
			}
		}
		for (i=0; i<nb_spine; i++) {
			SCPs[i].xaxis = SCPi[0].xaxis;
			SCPs[i].yaxis = SCPi[0].yaxis;
			SCPs[i].zaxis = SCPi[0].zaxis;
		}
	}
	/*not colinear*/
	else {
		assert(nb_scp<=nb_spine);

		/*now non-cap SCPs axis*/
		for (i=1; i<nb_scp-1; i++) {
			/*get Y axis*/
			gf_vec_diff(SCPi[i].yaxis, SCPi[i+1].pt, SCPi[i-1].pt);
			/*get Z axis*/
			gf_vec_diff(v1, SCPi[i+1].pt, SCPi[i].pt);
			gf_vec_diff(v2, SCPi[i-1].pt, SCPi[i].pt);
			SCPi[i].zaxis = gf_vec_cross(v1, v2);
		}
		/*compute head and tail*/
		if (spine_closed) {
			gf_vec_diff(SCPi[0].yaxis, SCPi[1].pt, SCPi[nb_scp-2].pt);
			gf_vec_diff(v1, SCPi[1].pt, SCPi[0].pt);
			gf_vec_diff(v2, SCPi[nb_scp-2].pt, SCPi[0].pt);
			SCPi[0].zaxis = gf_vec_cross(v1, v2);
			SCPi[nb_scp-1].yaxis = SCPi[0].yaxis;
			SCPi[nb_scp-1].zaxis = SCPi[0].zaxis;
		} else {
			gf_vec_diff(SCPi[0].yaxis, SCPi[1].pt, SCPi[0].pt);
			SCPi[0].zaxis = SCPi[1].zaxis;
			gf_vec_diff(SCPi[nb_scp-1].yaxis, SCPi[nb_scp-1].pt, SCPi[nb_scp-2].pt);
			SCPi[nb_scp-1].zaxis = SCPi[nb_scp-2].zaxis;
		}
		/*check orientation*/
		for (i=1; i<nb_scp; i++) {
			Fixed res = gf_vec_dot(SCPi[i].zaxis, SCPi[i-1].zaxis);
			if (res<0) gf_vec_rev(SCPi[i].zaxis);
		}
		/*and assign SCPs*/
		j=0;
		for (i=0; i<nb_scp; i++) {
			/*compute X, norm vectors*/
			SCPi[i].xaxis = gf_vec_cross(SCPi[i].yaxis, SCPi[i].zaxis);
			gf_vec_norm(&SCPi[i].xaxis);
			gf_vec_norm(&SCPi[i].yaxis);
			gf_vec_norm(&SCPi[i].zaxis);
			/*assign SCPs*/
			while (j<=SCPi[i].max_idx) {
				SCPs[j].xaxis = SCPi[i].xaxis;
				SCPs[j].yaxis = SCPi[i].yaxis;
				SCPs[j].zaxis = SCPi[i].zaxis;
				j++;
			}
		}
	}
	gf_free(SCPi);

	SCPbegin = SCPs[0];
	SCPend = SCPs[nb_spine-1];

	r.x = r.q = r.z = 0;
	r.y = FIX_ONE;
	scale.x = scale.y = FIX_ONE;

	cur_spine = 0;
	/*insert all points of the extrusion*/
	for (i=0; i<nb_spine; i++) {
		u32 cur_face_in_cross;
		SCP *curSCP;

		if (spine_closed && (i+1==nb_spine)) {
			curSCP = &SCPs[0];
			do_close =  1;
		} else {
			curSCP = &SCPs[i];
			do_close =  0;

			/*compute X*/
			curSCP->xaxis = gf_vec_cross(curSCP->yaxis, curSCP->zaxis);
			gf_vec_norm(&curSCP->xaxis);
			gf_vec_norm(&curSCP->yaxis);
			gf_vec_norm(&curSCP->zaxis);

			if (spine_ori && (i<spine_ori->count)) r = spine_ori->vals[i];
			if (spine_scale && (i<spine_scale->count)) scale = spine_scale->vals[i];

			gf_mx_init(mx);
			gf_mx_add_rotation(&mx, r.q, r.x, r.y, r.z);
			gf_mx_apply_vec(&mx, &curSCP->xaxis);
			gf_mx_apply_vec(&mx, &curSCP->yaxis);
			gf_mx_apply_vec(&mx, &curSCP->zaxis);
		}

		vx.texcoords.y = gf_divfix(cur_spine, spine_len);

		cur_pts_in_cross = 0;
		cur_face_in_cross = 0;
		cur = 0;
		for (j=0; j<path->n_contours; j++) {
			Bool subpath_closed;
			nb_pts = 1+path->contours[j] - cur;
			cur_cross = 0;
			subpath_closed = 0;
			if ((path->points[cur].x==path->points[path->contours[j]].x) && (path->points[cur].y==path->points[path->contours[j]].y))
				subpath_closed = 1;

			for (k=0; k<nb_pts; k++) {
				u32 pidx = k + cur_pts_in_cross + i*pts_per_cross;
				if (do_close) pidx = k + cur_pts_in_cross;

				v1.x = path->points[k+cur].x;
				v1.z = path->points[k+cur].y;

				if (tx_along_spine) {
					vx.texcoords.x = gf_divfix(cur_cross, cross_len);
				} else {
					vx.texcoords.x = gf_divfix(v1.x - min_cx, width_cx);
					vx.texcoords.y = gf_divfix(v1.z - min_cy, width_cy);
				}

				/*handle closed cross-section*/
				if (subpath_closed && (k+1==nb_pts)) {
					pidx = cur_pts_in_cross + i*pts_per_cross;
					if (do_close) pidx = cur_pts_in_cross;

					v1.x = path->points[cur].x;
					v1.z = path->points[cur].y;
				}
				v1.x = gf_mulfix(v1.x, scale.x);
				v1.z = gf_mulfix(v1.z, scale.y);
				v1.y = 0;
				vx.pos.x = gf_mulfix(v1.x, curSCP->xaxis.x) + gf_mulfix(v1.y, curSCP->yaxis.x) + gf_mulfix(v1.z, curSCP->zaxis.x) + spine[i].x;
				vx.pos.y = gf_mulfix(v1.x, curSCP->xaxis.y) + gf_mulfix(v1.y, curSCP->yaxis.y) + gf_mulfix(v1.z, curSCP->zaxis.y) + spine[i].y;
				vx.pos.z = gf_mulfix(v1.x, curSCP->xaxis.z) + gf_mulfix(v1.y, curSCP->yaxis.z) + gf_mulfix(v1.z, curSCP->zaxis.z) + spine[i].z;

				/*in current spine*/
				if (i+1<nb_spine) {
					/*current face*/
					if (k<nb_pts-1) REGISTER_POINT_FACE(k + cur_face_in_cross + i*faces_per_cross);
					/*previous face*/
					if (k) REGISTER_POINT_FACE(k-1 + cur_face_in_cross + i*faces_per_cross);
				}
				/*first spine*/
				else if (smooth_normals && do_close) {
					if (k<nb_pts-1) {
						register_point_in_face(&faces_info[k + cur_face_in_cross], pidx);
						register_face_in_point(&pts_info[pidx], k + cur_face_in_cross);
					}
					/*previous face*/
					if (k) {
						register_point_in_face(&faces_info[k-1 + cur_face_in_cross], pidx);
						register_face_in_point(&pts_info[pidx], k-1 + cur_face_in_cross);
					}
				}
				/*in previous spine*/
				if (i) {
					/*face "below" face*/
					if (k<nb_pts-1) REGISTER_POINT_FACE(k + cur_face_in_cross + (i-1)*faces_per_cross);
					/*previous face "below" face*/
					if (k) REGISTER_POINT_FACE(k-1 + cur_face_in_cross + (i-1)*faces_per_cross);
				}

				if (k+1<nb_pts) {
					v1.z = 0;
					v1.x = path->points[k+1+cur].x - path->points[k+cur].x;
					v1.y = path->points[k+1+cur].y - path->points[k+cur].y;
					cur_cross += gf_vec_len(v1);
				}

			}
			cur_face_in_cross += nb_pts-1;
			cur_pts_in_cross += nb_pts;
			cur += nb_pts;
		}
		if (i+1<nb_spine) {
			gf_vec_diff(v1, spine[i+1], spine[i]);
			cur_spine += gf_vec_len(v1);
		}
	}

	/*generate triangles & normals*/
	for (i=0; i<face_spines; i++) {
		mesh_set_triangle(faces[i], 0, 1, 3);
		mesh_set_triangle(faces[i], 0, 3, 2);
		gf_vec_diff(v1, faces[i]->vertices[1].pos, faces[i]->vertices[0].pos);
		gf_vec_diff(v2, faces[i]->vertices[3].pos, faces[i]->vertices[0].pos);
		n = gf_vec_cross(v1, v2);
		gf_vec_norm(&n);
		for (j=0; j<faces[i]->v_count; j++) {
			MESH_SET_NORMAL(faces[i]->vertices[j], n);
			if (smooth_normals) faces_info[i].nor = n;
		}
	}


	/*generate begin cap*/
	if (begin_face) {
		SFVec3f n;
		scale.x = scale.y = FIX_ONE;
		if (spine_scale && spine_scale->count) scale = spine_scale->vals[0];

		/*get first SCP after rotation*/
		SCPbegin = SCPs[0];

		n = SCPbegin.yaxis;
		gf_vec_norm(&n);

		convexity = gf_polygone2d_get_convexity(path->points, path->n_points);
		switch (convexity) {
		case GF_POLYGON_CONVEX_CCW:
		case GF_POLYGON_COMPLEX_CCW:
			break;
		default:
			gf_vec_rev(n);
			break;
		}

		MESH_SET_NORMAL(vx, n);


		if (smooth_normals) {
			faces_info[begin_face].nor = n;
			assert(gf_vec_len(n));
		}
		cur_pts_in_cross = 0;
		cur = 0;
		for (i=0; i<path->n_contours; i++) {
			Bool subpath_closed = 0;
			nb_pts = 1 + path->contours[i] - cur;
			if ((path->points[cur].x==path->points[path->contours[i]].x) && (path->points[cur].y==path->points[path->contours[i]].y))
				subpath_closed = 1;

			for (j=0; j<nb_pts; j++) {
				u32 pidx = j + (pts_per_cross-1-cur_pts_in_cross);
				v1.x = path->points[j+cur].x;
				v1.z = path->points[j+cur].y;
				vx.texcoords.x = gf_divfix(v1.x - min_cx, width_cx);
				vx.texcoords.y = gf_divfix(v1.z - min_cy, width_cy);
				/*handle closed cross-section*/
				if (subpath_closed  && (j+1==nb_pts)) {
					pidx = (pts_per_cross-1-cur_pts_in_cross);
					v1.x = path->points[cur].x;
					v1.z = path->points[cur].y;
				}
				v1.x = gf_mulfix(v1.x , scale.x);
				v1.z = gf_mulfix(v1.z , scale.y);
				v1.y = 0;
				vx.pos.x = gf_mulfix(v1.x, SCPbegin.xaxis.x) + gf_mulfix(v1.y, SCPbegin.yaxis.x) + gf_mulfix(v1.z, SCPbegin.zaxis.x) + spine[0].x;
				vx.pos.y = gf_mulfix(v1.x, SCPbegin.xaxis.y) + gf_mulfix(v1.y, SCPbegin.yaxis.y) + gf_mulfix(v1.z, SCPbegin.zaxis.y) + spine[0].y;
				vx.pos.z = gf_mulfix(v1.x, SCPbegin.xaxis.z) + gf_mulfix(v1.y, SCPbegin.yaxis.z) + gf_mulfix(v1.z, SCPbegin.zaxis.z) + spine[0].z;
				REGISTER_POINT_FACE(begin_face);
			}
			cur_pts_in_cross += nb_pts;
			cur += nb_pts;
		}
	}

	/*generate end cap*/
	if (end_face) {
		SFVec3f n;
		scale.x = scale.y = FIX_ONE;
		if (spine_scale && (nb_spine-1<spine_scale->count)) scale = spine_scale->vals[nb_spine-1];
		/*get last SCP after rotation*/
		SCPend = SCPs[nb_spine-1];

		n = SCPend.yaxis;
		gf_vec_norm(&n);
		MESH_SET_NORMAL(vx, n);
		convexity = gf_polygone2d_get_convexity(path->points, path->n_points);
		switch (convexity) {
		case GF_POLYGON_CONVEX_CCW:
		case GF_POLYGON_COMPLEX_CCW:
			gf_vec_rev(vx.normal);
			gf_vec_rev(n);
			break;
		}

		if (smooth_normals) {
			faces_info[end_face].nor = n;
			assert(gf_vec_len(n));
		}
		cur_pts_in_cross = 0;

		cur = 0;
		for (i=0; i<path->n_contours; i++) {
			Bool subpath_closed = 0;
			nb_pts = 1 + path->contours[i] - cur;
			if ((path->points[cur].x==path->points[path->contours[i]].x) && (path->points[cur].y==path->points[path->contours[i]].y))
				subpath_closed = 1;

			for (j=0; j<nb_pts; j++) {
				u32 pidx = j + cur_pts_in_cross + (nb_spine-1)*pts_per_cross;
				v1.x = path->points[j+cur].x;
				v1.z = path->points[j+cur].y;
				vx.texcoords.x = gf_divfix(v1.x - min_cx, width_cx);
				vx.texcoords.y = gf_divfix(v1.z - min_cy, width_cy);
				/*handle closed cross-section*/
				if (subpath_closed && (j+1==nb_pts)) {
					pidx = cur_pts_in_cross + (nb_spine-1)*pts_per_cross;
					v1.x = path->points[cur].x;
					v1.z = path->points[cur].y;
				}
				v1.x = gf_mulfix(v1.x, scale.x);
				v1.z = gf_mulfix(v1.z, scale.y);
				v1.y = 0;
				vx.pos.x = gf_mulfix(v1.x, SCPend.xaxis.x) + gf_mulfix(v1.y, SCPend.yaxis.x) + gf_mulfix(v1.z, SCPend.zaxis.x) + spine[nb_spine-1].x;
				vx.pos.y = gf_mulfix(v1.x, SCPend.xaxis.y) + gf_mulfix(v1.y, SCPend.yaxis.y) + gf_mulfix(v1.z, SCPend.zaxis.y) + spine[nb_spine-1].y;
				vx.pos.z = gf_mulfix(v1.x, SCPend.xaxis.z) + gf_mulfix(v1.y, SCPend.yaxis.z) + gf_mulfix(v1.z, SCPend.zaxis.z) + spine[nb_spine-1].z;

				REGISTER_POINT_FACE(end_face);
			}
			cur_pts_in_cross += nb_pts;
			cur += nb_pts;
		}
	}


	if (smooth_normals) {
		Fixed cosCrease;
		/*we only support 0->PI, whatever exceeds is smoothest*/
		if (creaseAngle>GF_PI) cosCrease = -FIX_ONE;
		else cosCrease = gf_cos(creaseAngle);

		for (i=0; i<face_count; i++) {
			for (j=0; j<faces[i]->v_count; j++) {
				SFVec3f n = smooth_face_normals(pts_info, pt_count, faces_info, face_count, j, i, cosCrease);
				MESH_SET_NORMAL(faces[i]->vertices[j], n);
			}
		}

		if (faces_info) {
			for (i=0; i<face_count; i++) if (faces_info[i].idx) gf_free(faces_info[i].idx);
			gf_free(faces_info);
		}
		if (pts_info) {
			for (i=0; i<pt_count; i++) if (pts_info[i].faces) gf_free(pts_info[i].faces);
			gf_free(pts_info);
		}
		mesh->flags |= MESH_IS_SMOOTHED;
	}

	mesh->mesh_type = MESH_TRIANGLES;

	for (i=0; i<face_spines; i++) {
		if (faces[i]->v_count) {
			u32 init_idx;
			GF_Mesh *face = faces[i];
			init_idx = mesh->v_count;
			/*quads only*/
			mesh_set_vertex_vx(mesh, &face->vertices[0]);
			mesh_set_vertex_vx(mesh, &face->vertices[1]);
			mesh_set_vertex_vx(mesh, &face->vertices[2]);
			mesh_set_vertex_vx(mesh, &face->vertices[3]);
			mesh_set_triangle(mesh, init_idx + 0, init_idx + 1, init_idx + 3);
			mesh_set_triangle(mesh, init_idx + 0, init_idx + 3, init_idx + 2);
		}
		mesh_free(faces[i]);
	}
	if (begin_face) {
		if (path->n_contours>1) {
#ifdef GPAC_HAS_GLU
			u32 *ptsPerFace = gf_malloc(sizeof(u32)*path->n_contours);
			/*we reversed begin cap!!!*/
			cur = 0;
			for (i=0; i<path->n_contours; i++) {
				nb_pts = 1+path->contours[i] - cur;
				cur+=nb_pts;
				ptsPerFace[i] = nb_pts;
			}
			TesselateFaceMeshComplex(mesh, faces[begin_face], path->n_contours, ptsPerFace);
			gf_free(ptsPerFace);
#endif
		} else {
			TesselateFaceMesh(mesh, faces[begin_face]);
		}
		mesh_free(faces[begin_face]);
	}
	if (end_face) {
		if (path->n_contours>1) {
#ifdef GPAC_HAS_GLU
			u32 *ptsPerFace = gf_malloc(sizeof(u32)*path->n_contours);
			cur = 0;
			for (i=0; i<path->n_contours; i++) {
				nb_pts = 1+path->contours[i] - cur;
				cur+=nb_pts;
				ptsPerFace[i] = nb_pts;
			}
			TesselateFaceMeshComplex(mesh, faces[end_face], path->n_contours, ptsPerFace);
			gf_free(ptsPerFace);
#endif
		} else {
			TesselateFaceMesh(mesh, faces[end_face]);
		}
		mesh_free(faces[end_face]);
	}
	gf_free(faces);
	gf_free(SCPs);

	/*FIXME: this is correct except we need to handle path cw/ccw - until then no possibility
	to get correct lighting*/
	/*
		if (path->subpathlen && path->subpath[0]->closed && ((begin_face && end_face) || spine_closed))
			mesh->flags |= MESH_IS_SOLID;
		else
			mesh->flags &= ~MESH_IS_SOLID;
	*/
}