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

📄 3dsload.cpp

📁 这是书上的代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/////////////////////////////////////////////////////////////////////////////////////////////////		3dsload.cpp	2001.12.13 Edited by JiangZibin
//		3D Studio to OpenGL Converter //		3D Studio object reader///////////////////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <setjmp.h>#include <assert.h>
#include <math.h>
#include "3dsload.h"

#ifndef PI
#define PI 3.1415926
#endif
jmp_buf EnvState;FILE *InFile=NULL;H3dsScene *Scene=NULL;
M3DSObject *Obj3DS=NULL;
int doublesided=0;
int alphablending=0;int defaultmaterialwarning=0;
//该模块用到的全局变量
/* Module Globals */
unsigned int NumVertex=0;
OUTGL_VERTEX *VertexList;		//顶点集(顶点及法向量列表)          
unsigned int NumPolyLists=0;
//多边形列表,其中的顶点将用下标表示,OpenGL将这个数组视为一个顶点数组(Vertec array).这里存储的
//法向量是每一个顶点的法向量,而不是多边形的法向量。
POLYGONLIST *PolyList;	
TRIANGLENODE **CommonTriangleList;	//相关三角形列表

//查找
static int FindMaterialIndex(char *);
//计算面的法向量
static int CalculateSurfaceNormal(OUTGL_SURFACE *);
//计算2个面的夹角的余弦
static GLfloat cos_angle(OUTGL_SURFACE *, OUTGL_SURFACE *);
//计算一个三角形在某个顶点处的夹角
static GLfloat angle(OUTGL_SURFACE *, GLuint);
//计算2个三维点之间的距离
static double distance(OUTGL_VERTEX *, OUTGL_VERTEX *);
//建立每个顶点的相关三角形列表
static void LinkVerticesToPolygons();
//计算每个顶点的法向量
static void CalculateVertexNormals();
//建立三角形列表,每个三角形中记载其顶点在顶点列表中的下标
static void MakeTriangleIndexList();

#define JOB_DONE           0	//表明是否完成
#define DEGENERATE_SURFACE 1	//非退化三角形
//读取3DS文件到自定义的图形数据结构中static GLfloat OutputAbs(GLfloat f);
static GLfloat OutputMax(GLfloat a,GLfloat b);



/********************************************************/
/* Finds the index of the material in question */
//查找材质的下标
int FindMaterialIndex(char *name) {
	unsigned int n;

	for (n=0; n<NumPolyLists; n++) {
		if (strcmp(name, PolyList[n].name) == 0) {
			return n;
		}
	}
	return -1;	

}


//往顶点列表中加入一个顶点Edited by JiangZibin
/* Adds a vertex to the vertex list */
void OutGLAddVertex(OUTGL_VERTEX v) {
	
	void *mem;
	if ((mem = realloc(VertexList, sizeof(OUTGL_VERTEX) * (NumVertex+1))) == 0) {
		exit(-1);
	}
	VertexList = (OUTGL_VERTEX *)mem;
	VertexList[NumVertex] = v;

   /* 
   * Add a slot into the array we're building to keep track of which   
   * triangles are part of which vertices, which will be used to build 
   * vertex normals.                                                   
   */
	/*向正在创建的数组中加入一个“槽”,使之能够记载哪些三角形拥有共同
	的某个顶点,加入这项内容的目的是用来创建顶点的法向量*/
	if ((mem = realloc(CommonTriangleList, sizeof(TRIANGLENODE **) * (NumVertex+1))) == 0) {
		exit(-1);
	}
	CommonTriangleList = (TRIANGLENODE **)mem;
	CommonTriangleList[NumVertex] = 0;

	NumVertex++;
}

//加入一个多边形的材质
/* Add a polygon of the material */
void OutGLAddPolygon(OUTGL_TRIANGLE tri, char *MaterialName) {
	void *mem;
	int MatNum;
	POLYGONLIST *list;
	OUTGL_SURFACE TempSurface;

	TempSurface.p0 = tri.p0;
	TempSurface.p1 = tri.p1;
	TempSurface.p2 = tri.p2;
	//忽略退化多边形
	/* Ignore degenerate polygons */
	if (CalculateSurfaceNormal(&TempSurface) == DEGENERATE_SURFACE)
		return;
	//查找材质在多边形列表中的下标
	/* Find the polygon list index we belong to */
	MatNum = FindMaterialIndex(MaterialName);
	list = &PolyList[MatNum];
	//将一个新三角形列表中
	/* Attach a new triangle to the polygon list */
	if ((mem = realloc(list->TriangleIndexList, 
		     sizeof(OUTGL_SURFACE) * (list->NumTriangles+1))) == 0) {
		exit(-1);
	}
	list->TriangleIndexList = (OUTGL_SURFACE *)mem;
	list->TriangleIndexList[list->NumTriangles].p0 = tri.p0;
	list->TriangleIndexList[list->NumTriangles].p1 = tri.p1;
	list->TriangleIndexList[list->NumTriangles].p2 = tri.p2;
	CalculateSurfaceNormal(&list->TriangleIndexList[list->NumTriangles]);
	list->NumTriangles++;

	if (PolyList[MatNum].doublesided) {
		//将一个新的三角形加到多边形列表中
		/* Attach a new triangle to the polygon list */
		if ((mem = realloc(list->TriangleIndexList, 
		       sizeof(OUTGL_SURFACE) * (list->NumTriangles+1))) == 0) {
			exit(-1);
		}
		list->TriangleIndexList = (OUTGL_SURFACE *)mem;
		list->TriangleIndexList[list->NumTriangles].p0 = tri.p0;
		list->TriangleIndexList[list->NumTriangles].p1 = tri.p2;
		list->TriangleIndexList[list->NumTriangles].p2 = tri.p1;
		CalculateSurfaceNormal(&list->TriangleIndexList[list->NumTriangles]);
		list->NumTriangles++;
	}
}


//给模型加入材质
/* Add a material to the model */
void OutGLAddMaterial(OUTGL_RGB ambient, OUTGL_RGB diffuse, OUTGL_RGB specular, char *name, char *texname, int doublesided) {
	void *mem;
	if ((mem =realloc(PolyList, sizeof(POLYGONLIST) * (NumPolyLists+1))) == 0) {
		exit(-1);
	}

	PolyList = (POLYGONLIST *)mem;
	strcpy(PolyList[NumPolyLists].name, name);
	strcpy(PolyList[NumPolyLists].texturename, texname);
	PolyList[NumPolyLists].ambient = ambient;
	PolyList[NumPolyLists].diffuse = diffuse;
	PolyList[NumPolyLists].specular = specular;
	PolyList[NumPolyLists].doublesided = doublesided;
	PolyList[NumPolyLists].NumTriangles = 0;
	PolyList[NumPolyLists].TriangleIndexList = 0;

	NumPolyLists++;

}

/*********************************************************************************************/

/*
 * Performs some model clean-up that can only be done once we have the entire
 * model. This includes finding the vertex normals (instead of the polygon
 * normals we already calculated), centering the object around 0,0,0, crunching
 * the vertex data into vertex arrays for OpenGL, and compiling the display list. 
 * Note that this code finds the vertex normals by first calculating the angle 
 * that each polygon shares with that vertex. It then averages all the normals 
 * together, each one weighted on how much of an angle they contribute to the 
 * vertex. Also, if the user specified a threshold for normals so that surface 
 * edges are preserved, we have to add a new vertex to the list with the same 
 * X,Y,Z coordinates but different normal coordinates. Thus, edge preservation 
 * may look good, but it's expensive.
 ********************************************************************************************/
/*OutGLFinishModel函数在读入整个模型之后对模型的数据进行一些整理工作,其内容
包括:查找顶点的法向量(而不是前面求出的法向量),将模型居中(即定位于(0,0,0)位
置),顶点数据放入数组中,并且编译显示列表。注意,在求顶点法向量时,所用的方
法是:先求出该顶点周围的所有面的法向量,在根据每个面对顶点法向量贡献的大小
加权平均得到。*/

void OutGLFinishModel()
{
	LinkVerticesToPolygons();
	
	CalculateVertexNormals();
	
	MakeTriangleIndexList();
}


//Build links from the vertices back to the polygon lists
 
//建立每个顶点的相关三角形列表,使用的方法是:将三角形加入
//其每一个顶点的三角形列表中,处理完所有的三角形后,就建立
//了所有顶点的三角形列表
static void LinkVerticesToPolygons() {

	unsigned int i,j;
	OUTGL_SURFACE *ThisTriangle;
	OUTGL_TRIANGLENODE *TempPtr;

	for (i=0; i<NumPolyLists; i++) {
		for (j=0; j<(unsigned int)PolyList[i].NumTriangles; j++) {
    
			/* For each triangle, insert a pointer to the triangle */
			/* into a linked list hanging off of each of the three */
			/* vertices it touches.                                */
			//将每个三角形加入其三个顶点的相关三角形列表
			ThisTriangle = &PolyList[i].TriangleIndexList[j];

			/* Point One */
			TempPtr = (OUTGL_TRIANGLENODE *) malloc(sizeof(OUTGL_TRIANGLENODE));
			TempPtr->triangle = ThisTriangle;
			TempPtr->next = CommonTriangleList[ThisTriangle->p0];
			CommonTriangleList[ThisTriangle->p0] = TempPtr;
      
			/* Point Two */
			TempPtr = (OUTGL_TRIANGLENODE *) malloc(sizeof(OUTGL_TRIANGLENODE));
			TempPtr->triangle = ThisTriangle;
			TempPtr->next = CommonTriangleList[ThisTriangle->p1];
			CommonTriangleList[ThisTriangle->p1] = TempPtr;
      
			/* Point Three */
			TempPtr = (OUTGL_TRIANGLENODE *) malloc(sizeof(OUTGL_TRIANGLENODE));
			TempPtr->triangle = ThisTriangle;
			TempPtr->next = CommonTriangleList[ThisTriangle->p2];
			CommonTriangleList[ThisTriangle->p2] = TempPtr;
		}
	}
}

/*
 * Generate the per-vertex normals. Make new vertices if two surfaces are
 * more than a threshold angle apart. Thus, a cube would have six surface
 * normals but if the threshold was 90 degrees, it would have 24 
 * vertex/normal pairs.
 */
//计算每个顶点的法向量
//计算每个顶点的法向量有多种方法,可以简单地将周围三角形的法向量直接相加
//得到,也可以由其周围三角形加权平均得到。权值的取法也有多种,可以是每个
//三角形的面积,也可以是每个三角形在该点处的夹角。本例就是用每个三角形在
//该点处的夹角作为权值的方法来求顶点得方向量
static void CalculateVertexNormals() 
{
	unsigned int i;
	GLfloat VertexAngle;
	GLfloat TotalAngles;
	OUTGL_TRIANGLENODE *ThisSurface;
	GLfloat sum, magnitude;
	ThisSurface=NULL;
	//计算每个顶点的法向量
	/* Calculate a normal for every vertex */
	for (i=0; i<NumVertex; i++) {
		VertexList[i].nx = VertexList[i].ny = VertexList[i].nz = 0;
		ThisSurface = CommonTriangleList[i];
		TotalAngles = 0;
		
		/* Traverse the linked list of triangles that touch this vertex */
		//遍历该顶点的所有相关三角形
		while (ThisSurface) {
	 /* 
	 * Since it's less then the threshold angle, calculate the angle that this
	 * polygon shares with the vertex 
	 */		VertexAngle = angle(ThisSurface->triangle, i);
			VertexList[i].nx += ThisSurface->triangle->n0 * VertexAngle;
			VertexList[i].ny += ThisSurface->triangle->n1 * VertexAngle;
			VertexList[i].nz += ThisSurface->triangle->n2 * VertexAngle;
			TotalAngles += VertexAngle;

			ThisSurface = ThisSurface->next;
		}
    /* Calculate the normal for this vertex */
		VertexList[i].nx /= TotalAngles;
		VertexList[i].ny /= TotalAngles;
		VertexList[i].nz /= TotalAngles;

    /* Make it a unit vector again */
		sum = ((VertexList[i].nx * VertexList[i].nx) +
			(VertexList[i].ny * VertexList[i].ny) +
			(VertexList[i].nz * VertexList[i].nz));
		magnitude = 1/(GLfloat)sqrt(sum);

		VertexList[i].nx *= magnitude;
		VertexList[i].ny *= magnitude;
		VertexList[i].nz *= magnitude;
	}
}


/********************************************************************************************* 
 * Make a list of triangle indexes for OpenGL's vertex arrays
 * This does not produce the more optimized TRIANGLE_STRIPS
 *********************************************************************************************/
//建立三角形列表,对于每个三角形记载其每个顶点在顶点列表中的下标
static void MakeTriangleIndexList() {
	unsigned int i,j;
  
	for (i=0; i<NumPolyLists; i++) {
		PolyList[i].CrunchedTriangleIndexList =(OUTGL_TRIANGLE*)malloc(sizeof(OUTGL_TRIANGLE)\
			* (PolyList[i].NumTriangles+1));
		for (j=0; j<(unsigned int)PolyList[i].NumTriangles; j++) {
			PolyList[i].CrunchedTriangleIndexList[j].p0 = \
				PolyList[i].TriangleIndexList[j].p0;
			PolyList[i].CrunchedTriangleIndexList[j].p1 =\
				PolyList[i].TriangleIndexList[j].p1;
			PolyList[i].CrunchedTriangleIndexList[j].p2 = \
				PolyList[i].TriangleIndexList[j].p2;
		}
	}

}

//计算三角形法向量函数
/**********************************************************************************************
 * Returns the normal for the triangle (not a vertex normal,
 * but a surface normal) 
 **********************************************************************************************/
//计算面的法向量:顺序地从三角形中找出两条有向边,计算其叉积
//得到的结果就是三角形的法向量,一般情况下还要对结果进行单位化
int CalculateSurfaceNormal(OUTGL_SURFACE *ThisTriangle)
{
	OUTGL_NORMAL ThisNormal;
	GLfloat Ai, Aj, Ak;
	GLfloat Bi, Bj, Bk;
	GLfloat sum, magnitude;

	/*
    Calculate the polygon's normal using a cross product.
    A,B are vectors; i,j,k are their xyz components
    */
	//求出三角形的2条有向边向量A,B,i,j,k分别是其3个坐标分量
	Ai = VertexList[ThisTriangle->p1].x - VertexList[ThisTriangle->p0].x;
	Aj = VertexList[ThisTriangle->p1].y - VertexList[ThisTriangle->p0].y;
	Ak = VertexList[ThisTriangle->p1].z - VertexList[ThisTriangle->p0].z;

	Bi = VertexList[ThisTriangle->p2].x - VertexList[ThisTriangle->p1].x;
	Bj = VertexList[ThisTriangle->p2].y - VertexList[ThisTriangle->p1].y;
	Bk = VertexList[ThisTriangle->p2].z - VertexList[ThisTriangle->p1].z;
	//用叉乘来计算多边形的法向量
	/* Find the cross product */
	ThisNormal.n0 = Aj*Bk - Ak*Bj;
	ThisNormal.n1 = Ak*Bi - Ai*Bk;
	ThisNormal.n2 = Ai*Bj - Aj*Bi;
	//计算法向量模的平方
	/* Make the normal a unit vector */
	sum = (ThisNormal.n0 * ThisNormal.n0) +
		(ThisNormal.n1 * ThisNormal.n1) +
		(ThisNormal.n2 * ThisNormal.n2);

	/*
	* This will be zero only if the cross product's 
	* normal has all zero components. That won't happen 
	* as long as the triangle has three separate vertices.
	* Otherwise, the next step would be to divide 1 by the
	* square root of zero... not a pretty site.
	*/
	//只要三角形3个顶点不全部在一点上,法向量的模就不等于0。
	if (sum == 0)		//否则为退化三角形
		return DEGENERATE_SURFACE;

	magnitude = 1/(GLfloat)sqrt(sum);
	//向量单位化
	ThisNormal.n0 *= magnitude;
	ThisNormal.n1 *= magnitude;
	ThisNormal.n2 *= magnitude;
	//将结果记入三角形中
	ThisTriangle->n0 = ThisNormal.n0;
	ThisTriangle->n1 = ThisNormal.n1;
	ThisTriangle->n2 = ThisNormal.n2;

⌨️ 快捷键说明

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