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

📄 loadobj.cpp

📁 OPENGL选取对象放大/鼠标点击图形进行放大
💻 CPP
字号:
// LoadOBJ.cpp: implementation of the CLoadOBJ class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MyPick1.h"
#include "LoadOBJ.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
// String normalization (remove all unused characters)
static char *NormalizeString(char *s)
{
	while (*s == ' ') s++;

	ULONG l = strlen(s);
	for (ULONG i=(l-1); i>0; i--)
		if (s[i] < 33) s[i] = 0;
		else break;

	return s;
}

static void ParseFloat(char *s, float *a, float *b, float *c)
{
	int i, j;
	int x, y, z;
  
	s = NormalizeString(s);
	x = 0; y = -1; z = -1;
	j = (int)strlen(s);
	for (i=0; i<j; i++)
	{
		if ((s[i] == ' ') || (s[i] == '\n'))
		{
			s[i] = 0;
			if (y == -1) y = i+1;
			else
			if (z == -1) z = i+1;
		}
	}
	*a = (float)atof(&s[x]);
	*b = (float)atof(&s[y]);
	*c = (float)atof(&s[z]);
}

static int Parse3(char *s, int *a, int *b, int *c)
{
	int i, j;
	char *sp;
	int stage=0;

	j = (int)strlen(s);
	sp = s;
	for (i=0; i<j; i++)
	{
		if ((s[i] == '/') || (i == j-1))
		{
			if (i != j-1) s[i] = 0;
			switch (stage)
			{
				case 0: *a = atoi(sp); break;
				case 1: *b = atoi(sp); break;
				case 2: *c = atoi(sp); break;
			}
			stage++;
			sp = &s[i+1];
		}
	}
	return stage;
}

static int ParseFace(char *s, int *a, int *ta, int *na, int *b, int *tb, int *nb, int *c, int *tc, int *nc)
{
	int i, j, stage=0, total;
	char *sp;

	s = NormalizeString(s);
	j = (int)strlen(s);

	sp = s;
	for (i=0; i<j; i++)
	{
		if ((s[i] == ' ') || (i == j-1))
		{
			if (i != j-1) s[i] = 0;
			 
			switch (stage)
			{
				case 0: total = Parse3(sp, a, ta, na); break;
				case 1: total = Parse3(sp, b, tb, nb); break;
				case 2: total = Parse3(sp, c, tc, nc); break;
			}
			stage++;
			sp = &s[i+1];
		}
	}
	return total;
}


CTexture::CTexture()
{
	cur_texture = 0;
}

CTexture::~CTexture()
{
	// 删除所有的纹理
	if (cur_texture > 0) glDeleteTextures(cur_texture, &textures[0]);
}

void CTexture::Init()
{
	glGenTextures(MAX_TEXTURES, textures);
}


GLuint CTexture::AddNewTexture(char *lpszName)
{
	unsigned *teximage;
	int texwid, texht;
	int texcomps;

	teximage = 	myTex->read_texture(lpszName, &texwid, &texht, &texcomps);
	if (!teximage) return -1;
	
	glBindTexture(GL_TEXTURE_2D, textures[cur_texture]);
	cur_texture++;
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	glTexImage2D(GL_TEXTURE_2D, 0, 3, texwid, texht, 0, GL_RGBA, GL_UNSIGNED_BYTE, teximage);
	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, texwid, texht, GL_RGBA, GL_UNSIGNED_BYTE, teximage);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); 
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
	free(teximage);

	return textures[cur_texture-1];
}

CLoadOBJ::CLoadOBJ()
{
	m_lpMtlName = NULL;
	Materials = NULL;
	tb = NULL;
	tx = NULL;
	ty = NULL;
	vx = NULL;
	vy = NULL;
	vz = NULL;
	vnx = NULL;
	vny = NULL;
	vnz = NULL;
	m_vtotal = 0;
	m_vttotal = 0;
	m_vntotal = 0;
}

CLoadOBJ::~CLoadOBJ()
{
	delete [] m_lpMtlName;
	if (vx) delete [] vx;
	if (vy) delete [] vy;
	if (vz) delete [] vz;
	if (vnx) delete [] vnx;
	if (vny) delete [] vny;
	if (vnz) delete [] vnz;
	if (tx) delete [] tx;
	if (ty) delete [] ty;
}


int CLoadOBJ::GetMtlName(FILE *f)
{
	char buffer[512];
	char *str;
	
	while (!feof(f))
	{
		fgets(buffer, 512, f);
		str = NormalizeString(buffer);

		if (str[0] == '#') continue;
		for (ULONG i=0; i<strlen(str); i++)
		{
			if (str[i] == ' ')
			{
				str[i] = 0;
				if (!strcmp(str, "mtllib")) 
				{
					if (m_lpMtlName) delete [] m_lpMtlName;
					m_lpMtlName = new char [MAX_FILE_NAME];
					strcpy(m_lpMtlName, &str[i+1]);
					return 0;

				} else break;
			}
			else continue;
		}
	}
	return -1; 
}

int CLoadOBJ::LoadObjFile(FILE *f)
{
	struct vertx
	{
		float x, y, z;
		struct vertx *next;
	};
	struct tcoord
	{
		float x, y;
		struct tcoord *next;
	};
	struct vertx *vrt=NULL, *vrt_cur, *vrt_temp;
	struct vertx *nrm=NULL, *nrm_cur, *nrm_temp;
	struct tcoord *tc=NULL, *tc_cur, *tc_temp;

	char buffer[512];
	char *str;
	float zzz;
	ULONG i;
	struct STriangleBlock *tb_cur, *tb_temp;
	struct STriangle *tr_cur, *tr_temp;

	int pa, pb, pc, pat, pbt, pct, pan, pbn, pcn, total; 

	m_vtotal = 0;
	m_vttotal = 0;

	while (!feof(f))
	{
		fgets(buffer, 512, f);
		str = NormalizeString(buffer);

		if (str[0] == '#' || str[0] == 'g' || str[0] == 0) continue;

		for (i=0; i<strlen(str); i++)
		{
			if (str[i] == ' ')
			{
				str[i] = 0;
				if (!strcmp(str, "v")) // 顶点坐标
				{
					if (!vrt)
					{
						vrt = new vertx;
						vrt_cur = vrt;
					}
					else
					{
						vrt_temp = new vertx;
						vrt_cur->next = vrt_temp;
						vrt_cur = vrt_temp;
					}
					vrt_cur->next = NULL;
					ParseFloat(&str[i+1], &vrt_cur->x, &vrt_cur->y, &vrt_cur->z);
					m_vtotal++;
					break;
				}
				else
				if (!strcmp(str, "vt")) // 纹理坐标
				{
					if (!tc)
					{
						tc = new tcoord;
						tc_cur = tc;
					}
					else
					{
						tc_temp = new tcoord;
						tc_cur->next = tc_temp;
						tc_cur = tc_temp;
					}
					tc_cur->next = NULL;
					ParseFloat(&str[i+1], &tc_cur->x, &tc_cur->y, &zzz);
					m_vttotal++;
					break;
				} 
				else
				if (!strcmp(str, "vn")) // 法向量坐标
				{
					if (!nrm)
					{
						nrm = new vertx;
						nrm_cur = nrm;
					}
					else
					{
						nrm_temp = new vertx;
						nrm_cur->next = nrm_temp;
						nrm_cur = nrm_temp;
					}
					nrm_cur->next = NULL;
					ParseFloat(&str[i+1], &nrm_cur->x, &nrm_cur->y, &nrm_cur->z);
					m_vntotal++;
					break;
				}
				else
				if (!strcmp(str, "usemtl")) 
				{
					if (!tb)
					{
						tb = new STriangleBlock;
						tb_cur = tb;

					} else
					{
						tb_temp = new STriangleBlock;
						tb_cur->next = tb_temp;
						tb_cur = tb_temp;
					}
					tb_cur->next = NULL;
					tb_cur->mat = GetMaterialByName(&str[i+1]);
					tb_cur->tr = NULL;
					break;
				}
				else
				if (!strcmp(str, "f"))
				{
					total = ParseFace(&str[i+1], &pa, &pat, &pan, &pb, &pbt, &pbn, &pc, &pct, &pcn);
					if (!tb_cur->tr)
					{
						tb_cur->tr = new STriangle;
						tr_cur = tb_cur->tr;
					}
					else
					{
						tr_temp = new STriangle;
						tr_cur->next = tr_temp;
						tr_cur = tr_temp;
					}
					tr_cur->next = NULL;
					
					if (total > 0)
					{
						tr_cur->a = pa;
						tr_cur->b = pb;
						tr_cur->c = pc;
					}
					if (total > 1)
					{
						tr_cur->ta = pat;
						tr_cur->tb = pbt;
						tr_cur->tc = pct;
					}
					if (total > 2)
					{
						tr_cur->na = pan;
						tr_cur->nb = pbn;
						tr_cur->nc = pcn;
					}
					break;
				}
			}
			else continue;
		}
	}
	// 为顶点序列分配存储空间
	vx = new float [m_vtotal];
	vy = new float [m_vtotal];
	vz = new float [m_vtotal];
	// 为法向量序列分配存储空间
	vnx = new float [m_vntotal];
	vny = new float [m_vntotal];
	vnz = new float [m_vntotal];
	// 为纹理坐标序列分配存储空间
	tx = new float [m_vttotal];
	ty = new float [m_vttotal];
	i = 0;
	// 保存并删除顶点序列
	vrt_cur = vrt;
	while (vrt_cur)
	{
		vx[i] = vrt_cur->x;
		vy[i] = vrt_cur->y;
		vz[i] = vrt_cur->z;
		i++;
		vrt_temp = vrt_cur->next;
		delete vrt_cur;
		vrt_cur = vrt_temp;
	}
	i = 0;
	// 保存并删除法向量序列
	nrm_cur = nrm;
	while (nrm_cur)
	{
		vnx[i] = nrm_cur->x;
		vny[i] = nrm_cur->y;
		vnz[i] = nrm_cur->z;
		i++;
		nrm_temp = nrm_cur->next;
		delete nrm_cur;
		nrm_cur = nrm_temp;
	}
	// 保存并删除纹理坐标序列
	i = 0;
	tc_cur = tc;
	while (tc_cur)
	{
		tx[i] = tc_cur->x;
		ty[i] = tc_cur->y;
		i++;
		tc_temp = tc_cur->next;
		delete tc_cur;
		tc_cur = tc_temp;
	}
	return -1;
}


int CLoadOBJ::LoadMtlFile(FILE *f, CTexture *tex_obj)
{
	char buffer[512];
	char *str;
	char *name;
	struct SMat *cur_mat = NULL;
	struct SMat *temp_mat = NULL;

	while (!feof(f))
	{
		fgets(buffer, 512, f);
		str = NormalizeString(buffer);

		for (ULONG i=0; i<strlen(str); i++)
		{
			if (str[i] == ' ')
			{
				str[i] = 0;
				if (!strcmp(str, "newmtl"))
				{
					name = &str[i+1];

					// 添加新材质
					if (!Materials)
					{
						Materials = new SMat;
						cur_mat = Materials;
					}
					else
					{
						temp_mat = new SMat;
						cur_mat->next = temp_mat;
						cur_mat = temp_mat;
					}
					cur_mat->next = NULL;

					cur_mat->MatName = new char [strlen(name)+1];
					strcpy(cur_mat->MatName, name);
					cur_mat->texture = -1;
				} else
				if (!strcmp(str, "map_Kd")) 
				{
					cur_mat->texture = tex_obj->AddNewTexture(&str[i+1]); 
					if (cur_mat->texture == -1) return -1;
				}
				else 
				if (!strcmp(str, "Ka"))
				{
					ParseFloat(&str[i+1], &cur_mat->ar, &cur_mat->ag, &cur_mat->ab);
				}
				else 
				if (!strcmp(str, "Kd"))
				{
					ParseFloat(&str[i+1], &cur_mat->dr, &cur_mat->dg, &cur_mat->db);
				}
				else 
				if (!strcmp(str, "Ks"))
				{
					ParseFloat(&str[i+1], &cur_mat->sr, &cur_mat->sg, &cur_mat->sb);
				}
				else break;
			}
			else continue;
		}
	}
	return -1;
}


int CLoadOBJ::LoadFromFile(char *lpszName, CTexture *tex_obj)
{
	FILE *f, *fmtl;
	f = fopen(lpszName, "rb");
	m_lpMtlName = new char[strlen(lpszName)+1];
	strcpy(m_lpMtlName, lpszName);
	m_lpMtlName[strlen(m_lpMtlName)-1] = 'l';
	m_lpMtlName[strlen(m_lpMtlName)-2] = 't';
	m_lpMtlName[strlen(m_lpMtlName)-3] = 'm';
	fmtl = fopen(m_lpMtlName, "rb");
	LoadMtlFile(fmtl, tex_obj);
	LoadObjFile(f);
	fclose(fmtl);
	fclose(f);
	return 0;
}

SMat *CLoadOBJ::GetMaterialByName(char *lpszName)
{
	SMat *temp;

	temp = Materials;
	while (temp)
	{
		if (!strcmp(temp->MatName, lpszName)) return temp;
		temp = temp->next;
	}
	return NULL;
}


static void setMaterial(float ambr, float ambg, float ambb,
                 float difr, float difg, float difb,
                 float specr, float specg, float specb,
                 float shine)
{
	float mat[4];

	mat[0] = ambr; mat[1] = ambg; mat[2] = ambb; mat[3] = 1.0;
	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat);
	mat[0] = difr; mat[1] = difg; mat[2] = difb; mat[3] = 1.0;
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat);
	mat[0] = specr; mat[1] = specg; mat[2] = specb; mat[3] = 1.0;
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat);
	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shine*128.0f);
}

void CLoadOBJ::Draw()
{
	STriangleBlock *temp;
	STriangle *temp1;

	temp = tb;
	while (temp)
	{

		setMaterial(temp->mat->ar, temp->mat->ag, temp->mat->ab,
					temp->mat->dr, temp->mat->dg, temp->mat->db,
					temp->mat->sr, temp->mat->sg, temp->mat->sb, 1.0);

		glColor3f(temp->mat->ar, temp->mat->ag, temp->mat->ab);
		glBegin(GL_TRIANGLES);
		temp1 = temp->tr;
		while (temp1)
		{
			glNormal3f(vnx[temp1->a-1], vny[temp1->a-1], vnz[temp1->a-1]);
			glVertex3f(vx[temp1->a-1], vy[temp1->a-1], vz[temp1->a-1]);
			
			glNormal3f(vnx[temp1->b-1], vny[temp1->b-1], vnz[temp1->b-1]);
			glVertex3f(vx[temp1->b-1], vy[temp1->b-1], vz[temp1->b-1]);

			glNormal3f(vnx[temp1->c-1], vny[temp1->c-1], vnz[temp1->c-1]);
			glVertex3f(vx[temp1->c-1], vy[temp1->c-1], vz[temp1->c-1]);
			
			temp1 = temp1->next;
		}
		glEnd();
		temp = temp->next;		
	}
	glEnd();
}

⌨️ 快捷键说明

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