⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tesselate.c

📁 一个用于智能手机的多媒体库适合S60 WinCE的跨平台开发库
💻 C
字号:
/* *			GPAC - Multimedia Framework C SDK * *			Copyright (c) Jean Le Feuvre 2000-2005 *					All rights reserved * *  This file is part of GPAC / 3D rendering module * *  GPAC is free software; you can redistribute it and/or modify *  it under the terms of the GNU Lesser General Public License as published by *  the Free Software Foundation; either version 2, or (at your option) *  any later version. *    *  GPAC is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU Lesser General Public License for more details. *    *  You should have received a copy of the GNU Lesser General Public *  License along with this library; see the file COPYING.  If not, write to *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  * */#include "visual_surface.h"#include "gl_inc.h"#ifndef CALLBACK#define CALLBACK#endif#ifndef GPAC_USE_OGL_EStypedef struct{	/*for tesselation*/	GLUtesselator *tess_obj;	GF_Mesh *mesh;	/*vertex indices: we cannot use a static array because reallocating the array will likely change memory 	address of indices, hence break triangulator*/	GF_List *vertex_index;} MeshTess;static void CALLBACK mesh_tess_begin(GLenum which) { assert(which==GL_TRIANGLES); }static void CALLBACK mesh_tess_end(void) { }static void CALLBACK mesh_tess_error(GLenum error_code) { GF_LOG(GF_LOG_ERROR, GF_LOG_RENDER, ("[Render 3D] Tesselate error %s\n", gluErrorString(error_code))); }/*only needed to force GL_TRIANGLES*/static void CALLBACK mesh_tess_edgeflag(GLenum flag) { }static void CALLBACK mesh_tess_vertex(void *vertexData, void *user_data){	MeshTess *tess = (MeshTess *) user_data;	mesh_set_index(tess->mesh, *(u32*)vertexData);}static void CALLBACK mesh_tess_combine(GLdouble coords[3], void* vertex_data[4], GLfloat weight[4], void** out_data, void *user_data){	u32 i, idx;	u32 *new_idx;	SFVec3f n;	SFVec2f tx;	SFColor col;	MeshTess *tess = (MeshTess *) user_data;	col.red = col.green = col.blue = 0;	if (tess->mesh->flags & MESH_HAS_COLOR) {		for (i=0; i<4; i++) {			if (weight[i]) {				Fixed _weight = FLT2FIX(weight[i]);				idx = * (u32 *) vertex_data[i];				col.red += gf_mulfix(_weight, tess->mesh->vertices[idx].color.red);				col.green += gf_mulfix(_weight, tess->mesh->vertices[idx].color.green);				col.blue += gf_mulfix(_weight, tess->mesh->vertices[idx].color.blue);			}		}	}	n.x = n.y = n.z = 0;	if (tess->mesh->flags & MESH_IS_2D) {		n.z = FIX_ONE;	} else {		for (i=0; i<4; i++) {			if (weight[i]) {				Fixed _weight = FLT2FIX(weight[i]);				idx = * (u32 *) vertex_data[i];				n.x += gf_mulfix(_weight, tess->mesh->vertices[idx].normal.x);				n.y += gf_mulfix(_weight, tess->mesh->vertices[idx].normal.y);				n.z += gf_mulfix(_weight, tess->mesh->vertices[idx].normal.z);			}		}	}	tx.x = tx.y = 0;	if (!(tess->mesh->flags & MESH_NO_TEXTURE)) {		for (i=0; i<4; i++) {			if (weight[i]) {				Fixed _weight = FLT2FIX(weight[i]);				idx = * (u32 *) vertex_data[i];				tx.x += gf_mulfix(_weight, tess->mesh->vertices[idx].texcoords.x);				tx.y += gf_mulfix(_weight, tess->mesh->vertices[idx].texcoords.y);			}		}	}	new_idx = (u32 *) malloc(sizeof(u32));	gf_list_add(tess->vertex_index, new_idx);	*new_idx = tess->mesh->v_count;	mesh_set_vertex(tess->mesh, FLT2FIX( (Float) coords[0]), FLT2FIX( (Float) coords[1]), FLT2FIX( (Float) coords[2]), n.x, n.y, n.z, tx.x, tx.y);	*out_data = new_idx;}void TesselatePath(GF_Mesh *mesh, GF_Path *path, u32 outline_style){	u32 i, j, cur, nb_pts;	u32 *idx;	Fixed w, h, min_y;	GF_Rect rc;	GLdouble vertex[3];	MeshTess *tess;	if (!mesh || !path || !path->n_contours) return;	tess = malloc(sizeof(MeshTess));	if (!tess) return;	memset(tess, 0, sizeof(MeshTess));    tess->tess_obj = gluNewTess();    if (!tess->tess_obj) {		free(tess);		return;	}	tess->vertex_index = gf_list_new();	mesh_reset(mesh);	mesh->flags |= MESH_IS_2D;	if (outline_style==1) mesh->flags |= MESH_NO_TEXTURE;		tess->mesh = mesh;    gluTessCallback(tess->tess_obj, GLU_TESS_VERTEX_DATA, (void (CALLBACK*)()) &mesh_tess_vertex);    gluTessCallback(tess->tess_obj, GLU_TESS_BEGIN, (void (CALLBACK*)()) &mesh_tess_begin);    gluTessCallback(tess->tess_obj, GLU_TESS_END, (void (CALLBACK*)()) &mesh_tess_end);    gluTessCallback(tess->tess_obj, GLU_TESS_COMBINE_DATA, (void (CALLBACK*)()) &mesh_tess_combine);    gluTessCallback(tess->tess_obj, GLU_TESS_ERROR, (void (CALLBACK*)()) &mesh_tess_error);	gluTessCallback(tess->tess_obj, GLU_EDGE_FLAG,(void (CALLBACK*)()) &mesh_tess_edgeflag);	if (path->flags & GF_PATH_FILL_ZERO_NONZERO) gluTessProperty(tess->tess_obj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);    gluTessBeginPolygon(tess->tess_obj, tess);	gluTessNormal(tess->tess_obj, 0, 0, 1);	gf_path_flatten(path);	gf_path_get_bounds(path, &rc);	w = rc.width;	h = rc.height;	min_y = rc.y - h;	vertex[2] = 0;	/*since we're not sure whether subpaths overlaps or not, tesselate everything*/	cur = 0;	for (i=0; i<path->n_contours; i++) {		nb_pts = 1+path->contours[i]-cur;		gluTessBeginContour(tess->tess_obj);		for (j=0; j<nb_pts; j++) {			GF_Point2D pt = path->points[cur+j];			Fixed u = gf_divfix(pt.x - rc.x, w);			Fixed v = gf_divfix(pt.y - min_y, h);			idx = (u32 *) malloc(sizeof(u32));			*idx = mesh->v_count;			gf_list_add(tess->vertex_index, idx);			mesh_set_vertex(mesh, pt.x, pt.y, 0, 0, 0, FIX_ONE, u, v);			vertex[0] = (Double) FIX2FLT(pt.x);			vertex[1] = (Double) FIX2FLT(pt.y);			gluTessVertex(tess->tess_obj, vertex, idx);		}		gluTessEndContour(tess->tess_obj);		cur+=nb_pts;	}    gluTessEndPolygon(tess->tess_obj);	gluDeleteTess(tess->tess_obj);	while (gf_list_count(tess->vertex_index)) {		u32 *idx = gf_list_get(tess->vertex_index, 0);		gf_list_rem(tess->vertex_index, 0);		free(idx);	}	gf_list_del(tess->vertex_index);	free(tess);	mesh->bounds.min_edge.x = rc.x;	mesh->bounds.min_edge.y = rc.y-rc.height;	mesh->bounds.max_edge.x = rc.x+rc.width;	mesh->bounds.max_edge.y = rc.y;	mesh->bounds.min_edge.z = mesh->bounds.max_edge.z = 0;	gf_bbox_refresh(&mesh->bounds);}#elsevoid TesselatePath(GF_Mesh *mesh, GF_Path *path, u32 outline_style) { }#endif#define GetPoint2D(pt, apt) \	if (!direction) { pt.x = - apt.pos.z; pt.y = apt.pos.y;	}	\	else if (direction==1) { pt.x = apt.pos.z; pt.y = apt.pos.x; }	\	else if (direction==2) { pt.x = apt.pos.x; pt.y = apt.pos.y; } \#define ConvCompare(delta)	\    ( (delta.x > 0) ? -1 :		\      (delta.x < 0) ?	1 :		\      (delta.y > 0) ? -1 :		\      (delta.y < 0) ?	1 :	\      0 )#define ConvGetPointDelta(delta, pprev, pcur )			\    /* Given a previous point 'pprev', read a new point into 'pcur' */	\    /* and return delta in 'delta'.				    */	\    GetPoint2D(pcur, pts[iread]); iread++;			\    delta.x = pcur.x - pprev.x;					\    delta.y = pcur.y - pprev.y;					\#define ConvCross(p, q) gf_mulfix(p.x,q.y) - gf_mulfix(p.y,q.x);#define ConvCheckTriple						\    if ( (thisDir = ConvCompare(dcur)) == -curDir ) {			\	  ++dirChanges;							\	  /* if ( dirChanges > 2 ) return NotConvex;		     */ \    }									\    curDir = thisDir;							\    cross = ConvCross(dprev, dcur);					\    if ( cross > 0 ) { \		if ( angleSign == -1 ) return GF_POLYGON_COMPLEX;		\		angleSign = 1;					\	}							\    else if (cross < 0) {	\		if (angleSign == 1) return GF_POLYGON_COMPLEX;		\		angleSign = -1;				\	}						\    pSecond = pThird;		\    dprev.x = dcur.x;		\    dprev.y = dcur.y;							\u32 polygon_check_convexity(GF_Vertex *pts, u32 len, u32 direction){	s32 curDir, thisDir = 0, dirChanges = 0, angleSign = 0;	u32 iread;	Fixed cross;	GF_Point2D pSecond, pThird, pSaveSecond;	GF_Point2D dprev, dcur;	if (len<3) return GF_POLYGON_CONVEX_LINE;	pSecond.x = pSecond.y = 0;	pThird = pSecond;	GetPoint2D(pThird, pts[0]);    /* Get different point, return if less than 3 diff points. */    if (len < 3 ) return GF_POLYGON_CONVEX_LINE;    iread = 1;	ConvGetPointDelta(dprev, pThird, pSecond);    pSaveSecond = pSecond;	/*initial direction */    curDir = ConvCompare(dprev);    while ( iread < len) {		/* Get different point, break if no more points */		ConvGetPointDelta(dcur, pSecond, pThird );		if ( (dcur.x == 0) && (dcur.y == 0) ) continue;		/* Check current three points */		ConvCheckTriple;    }    /* Must check for direction changes from last vertex back to first */	/* Prepare for 'ConvexCheckTriple' */	GetPoint2D(pThird, pts[0]);    dcur.x = pThird.x - pSecond.x;    dcur.y = pThird.y - pSecond.y;    if ( ConvCompare(dcur) ) ConvCheckTriple;    /* and check for direction changes back to second vertex */    dcur.x = pSaveSecond.x - pSecond.x;    dcur.y = pSaveSecond.y - pSecond.y;	/* Don't care about 'pThird' now */    ConvCheckTriple;			    /* Decide on polygon type given accumulated status */    if ( dirChanges > 2 ) return GF_POLYGON_COMPLEX;    if ( angleSign > 0 ) return GF_POLYGON_CONVEX_CCW;    if ( angleSign < 0 ) return GF_POLYGON_CONVEX_CW;    return GF_POLYGON_CONVEX_LINE;}void TesselateFaceMesh(GF_Mesh *dest, GF_Mesh *orig){	u32 poly_type, i, nb_pts, init_idx, direction;    Fixed max_nor_coord, c;	SFVec3f nor;#ifndef GPAC_USE_OGL_ES	u32 *idx;	GLdouble vertex[3];	MeshTess *tess;#endif	/*get normal*/	if (orig->flags & MESH_IS_2D) {		nor.x = nor.y = 0; nor.z = FIX_ONE;	} else {		nor = orig->vertices[0].normal;	}	/*select projection direction*/	direction = 0;	max_nor_coord = ABS(nor.x);	c = ABS(nor.y);	if (c>max_nor_coord) {		direction = 1;		max_nor_coord = c;	}	c = ABS(nor.z);	if (c>max_nor_coord) direction = 2;	/*if this is a convex polygone don't triangulate*/	poly_type = polygon_check_convexity(orig->vertices, orig->v_count, direction);	switch (poly_type) {	case GF_POLYGON_CONVEX_LINE:	/*do NOT try to make face CCW otherwise we loose front/back faces...*/	case GF_POLYGON_CONVEX_CW:	case GF_POLYGON_CONVEX_CCW:		init_idx = dest->v_count;		nb_pts = orig->v_count;		for (i=0; i<nb_pts; i++) {			mesh_set_vertex_vx(dest, &orig->vertices[i]);		}		nb_pts -= 1;		for (i=1; i<nb_pts; i++) {			mesh_set_triangle(dest, init_idx, init_idx + i, init_idx + i+1);		}		return;	default:		break;	}#ifndef GPAC_USE_OGL_ES		/*tesselate it*/	tess = malloc(sizeof(MeshTess));	if (!tess) return;	memset(tess, 0, sizeof(MeshTess));    tess->tess_obj = gluNewTess();    if (!tess->tess_obj) {		free(tess);		return;	}	tess->vertex_index = gf_list_new();	tess->mesh = dest;    gluTessCallback(tess->tess_obj, GLU_TESS_VERTEX_DATA, (void (CALLBACK*)()) &mesh_tess_vertex);    gluTessCallback(tess->tess_obj, GLU_TESS_BEGIN, (void (CALLBACK*)()) &mesh_tess_begin);    gluTessCallback(tess->tess_obj, GLU_TESS_END, (void (CALLBACK*)()) &mesh_tess_end);    gluTessCallback(tess->tess_obj, GLU_TESS_COMBINE_DATA, (void (CALLBACK*)()) &mesh_tess_combine);    gluTessCallback(tess->tess_obj, GLU_TESS_ERROR, (void (CALLBACK*)()) &mesh_tess_error);	gluTessCallback(tess->tess_obj, GLU_EDGE_FLAG,(void (CALLBACK*)()) &mesh_tess_edgeflag);    gluTessBeginPolygon(tess->tess_obj, tess);	gluTessBeginContour(tess->tess_obj);	for (i=0; i<orig->v_count; i++) {		idx = (u32 *) malloc(sizeof(u32));		*idx = dest->v_count;		gf_list_add(tess->vertex_index, idx);		mesh_set_vertex_vx(dest, &orig->vertices[i]);		vertex[0] = (Double) FIX2FLT(orig->vertices[i].pos.x);		vertex[1] = (Double) FIX2FLT(orig->vertices[i].pos.y);		vertex[2] = (Double) FIX2FLT(orig->vertices[i].pos.z);		gluTessVertex(tess->tess_obj, vertex, idx);	}	gluTessEndContour(tess->tess_obj);    gluTessEndPolygon(tess->tess_obj);	gluDeleteTess(tess->tess_obj);	while (gf_list_count(tess->vertex_index)) {		u32 *idx = gf_list_get(tess->vertex_index, 0);		gf_list_rem(tess->vertex_index, 0);		free(idx);	}	gf_list_del(tess->vertex_index);	free(tess);#endif}#ifndef GPAC_USE_OGL_ESvoid TesselateFaceMeshComplex(GF_Mesh *dest, GF_Mesh *orig, u32 nbFaces, u32 *ptsPerFaces){	u32 i, cur_pt_faces, cur_face;	u32 *idx;	GLdouble vertex[3];	MeshTess *tess;		/*tesselate it*/	tess = malloc(sizeof(MeshTess));	if (!tess) return;	memset(tess, 0, sizeof(MeshTess));    tess->tess_obj = gluNewTess();    if (!tess->tess_obj) {		free(tess);		return;	}	tess->vertex_index = gf_list_new();	tess->mesh = dest;    gluTessCallback(tess->tess_obj, GLU_TESS_VERTEX_DATA, (void (CALLBACK*)()) &mesh_tess_vertex);    gluTessCallback(tess->tess_obj, GLU_TESS_BEGIN, (void (CALLBACK*)()) &mesh_tess_begin);    gluTessCallback(tess->tess_obj, GLU_TESS_END, (void (CALLBACK*)()) &mesh_tess_end);    gluTessCallback(tess->tess_obj, GLU_TESS_COMBINE_DATA, (void (CALLBACK*)()) &mesh_tess_combine);    gluTessCallback(tess->tess_obj, GLU_TESS_ERROR, (void (CALLBACK*)()) &mesh_tess_error);	gluTessCallback(tess->tess_obj, GLU_EDGE_FLAG,(void (CALLBACK*)()) &mesh_tess_edgeflag);    gluTessBeginPolygon(tess->tess_obj, tess);	gluTessBeginContour(tess->tess_obj);	cur_pt_faces = 0;	cur_face = 0;	for (i=0; i<orig->v_count; i++) {				if (i>= cur_pt_faces + ptsPerFaces[cur_face]) {			cur_pt_faces += ptsPerFaces[cur_face];			cur_face++;			if (cur_face>=nbFaces) break;			gluTessEndContour(tess->tess_obj);			gluTessBeginContour(tess->tess_obj);		}		idx = (u32 *) malloc(sizeof(u32));		*idx = dest->v_count;		gf_list_add(tess->vertex_index, idx);		mesh_set_vertex_vx(dest, &orig->vertices[i]);		vertex[0] = (Double) FIX2FLT(orig->vertices[i].pos.x);		vertex[1] = (Double) FIX2FLT(orig->vertices[i].pos.y);		vertex[2] = (Double) FIX2FLT(orig->vertices[i].pos.z);		gluTessVertex(tess->tess_obj, vertex, idx);	}	gluTessEndContour(tess->tess_obj);    gluTessEndPolygon(tess->tess_obj);	gluDeleteTess(tess->tess_obj);	while (gf_list_count(tess->vertex_index)) {		u32 *idx = gf_list_get(tess->vertex_index, 0);		gf_list_rem(tess->vertex_index, 0);		free(idx);	}	gf_list_del(tess->vertex_index);	free(tess);}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -