forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			246 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			246 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | //
 | ||
|  | // Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
 | ||
|  | //
 | ||
|  | // This software is provided 'as-is', without any express or implied
 | ||
|  | // warranty.  In no event will the authors be held liable for any damages
 | ||
|  | // arising from the use of this software.
 | ||
|  | // Permission is granted to anyone to use this software for any purpose,
 | ||
|  | // including commercial applications, and to alter it and redistribute it
 | ||
|  | // freely, subject to the following restrictions:
 | ||
|  | // 1. The origin of this software must not be misrepresented; you must not
 | ||
|  | //    claim that you wrote the original software. If you use this software
 | ||
|  | //    in a product, an acknowledgment in the product documentation would be
 | ||
|  | //    appreciated but is not required.
 | ||
|  | // 2. Altered source versions must be plainly marked as such, and must not be
 | ||
|  | //    misrepresented as being the original software.
 | ||
|  | // 3. This notice may not be removed or altered from any source distribution.
 | ||
|  | //
 | ||
|  | 
 | ||
|  | #include "MeshLoaderObj.h"
 | ||
|  | #include <stdio.h>
 | ||
|  | #include <stdlib.h>
 | ||
|  | #include <cstring>
 | ||
|  | #define _USE_MATH_DEFINES
 | ||
|  | #include <math.h>
 | ||
|  | 
 | ||
|  | rcMeshLoaderObj::rcMeshLoaderObj() : | ||
|  | 	m_scale(1.0f), | ||
|  | 	m_verts(0), | ||
|  | 	m_tris(0), | ||
|  | 	m_normals(0), | ||
|  | 	m_vertCount(0), | ||
|  | 	m_triCount(0) | ||
|  | { | ||
|  | } | ||
|  | 
 | ||
|  | rcMeshLoaderObj::~rcMeshLoaderObj() | ||
|  | { | ||
|  | 	delete [] m_verts; | ||
|  | 	delete [] m_normals; | ||
|  | 	delete [] m_tris; | ||
|  | } | ||
|  | 		 | ||
|  | void rcMeshLoaderObj::addVertex(float x, float y, float z, int& cap) | ||
|  | { | ||
|  | 	if (m_vertCount+1 > cap) | ||
|  | 	{ | ||
|  | 		cap = !cap ? 8 : cap*2; | ||
|  | 		float* nv = new float[cap*3]; | ||
|  | 		if (m_vertCount) | ||
|  | 			memcpy(nv, m_verts, m_vertCount*3*sizeof(float)); | ||
|  | 		delete [] m_verts; | ||
|  | 		m_verts = nv; | ||
|  | 	} | ||
|  | 	float* dst = &m_verts[m_vertCount*3]; | ||
|  | 	*dst++ = x*m_scale; | ||
|  | 	*dst++ = y*m_scale; | ||
|  | 	*dst++ = z*m_scale; | ||
|  | 	m_vertCount++; | ||
|  | } | ||
|  | 
 | ||
|  | void rcMeshLoaderObj::addTriangle(int a, int b, int c, int& cap) | ||
|  | { | ||
|  | 	if (m_triCount+1 > cap) | ||
|  | 	{ | ||
|  | 		cap = !cap ? 8 : cap*2; | ||
|  | 		int* nv = new int[cap*3]; | ||
|  | 		if (m_triCount) | ||
|  | 			memcpy(nv, m_tris, m_triCount*3*sizeof(int)); | ||
|  | 		delete [] m_tris; | ||
|  | 		m_tris = nv; | ||
|  | 	} | ||
|  | 	int* dst = &m_tris[m_triCount*3]; | ||
|  | 	*dst++ = a; | ||
|  | 	*dst++ = b; | ||
|  | 	*dst++ = c; | ||
|  | 	m_triCount++; | ||
|  | } | ||
|  | 
 | ||
|  | static char* parseRow(char* buf, char* bufEnd, char* row, int len) | ||
|  | { | ||
|  | 	bool start = true; | ||
|  | 	bool done = false; | ||
|  | 	int n = 0; | ||
|  | 	while (!done && buf < bufEnd) | ||
|  | 	{ | ||
|  | 		char c = *buf; | ||
|  | 		buf++; | ||
|  | 		// multirow
 | ||
|  | 		switch (c) | ||
|  | 		{ | ||
|  | 			case '\\': | ||
|  | 				break; | ||
|  | 			case '\n': | ||
|  | 				if (start) break; | ||
|  | 				done = true; | ||
|  | 				break; | ||
|  | 			case '\r': | ||
|  | 				break; | ||
|  | 			case '\t': | ||
|  | 			case ' ': | ||
|  | 				if (start) break; | ||
|  | 				// else falls through
 | ||
|  | 			default: | ||
|  | 				start = false; | ||
|  | 				row[n++] = c; | ||
|  | 				if (n >= len-1) | ||
|  | 					done = true; | ||
|  | 				break; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	row[n] = '\0'; | ||
|  | 	return buf; | ||
|  | } | ||
|  | 
 | ||
|  | static int parseFace(char* row, int* data, int n, int vcnt) | ||
|  | { | ||
|  | 	int j = 0; | ||
|  | 	while (*row != '\0') | ||
|  | 	{ | ||
|  | 		// Skip initial white space
 | ||
|  | 		while (*row != '\0' && (*row == ' ' || *row == '\t')) | ||
|  | 			row++; | ||
|  | 		char* s = row; | ||
|  | 		// Find vertex delimiter and terminated the string there for conversion.
 | ||
|  | 		while (*row != '\0' && *row != ' ' && *row != '\t') | ||
|  | 		{ | ||
|  | 			if (*row == '/') *row = '\0'; | ||
|  | 			row++; | ||
|  | 		} | ||
|  | 		if (*s == '\0') | ||
|  | 			continue; | ||
|  | 		int vi = atoi(s); | ||
|  | 		data[j++] = vi < 0 ? vi+vcnt : vi-1; | ||
|  | 		if (j >= n) return j; | ||
|  | 	} | ||
|  | 	return j; | ||
|  | } | ||
|  | 
 | ||
|  | bool rcMeshLoaderObj::load(const std::string& filename) | ||
|  | { | ||
|  | 	char* buf = 0; | ||
|  | 	FILE* fp = fopen(filename.c_str(), "rb"); | ||
|  | 	if (!fp) | ||
|  | 		return false; | ||
|  | 	if (fseek(fp, 0, SEEK_END) != 0) | ||
|  | 	{ | ||
|  | 		fclose(fp); | ||
|  | 		return false; | ||
|  | 	} | ||
|  | 	long bufSize = ftell(fp); | ||
|  | 	if (bufSize < 0) | ||
|  | 	{ | ||
|  | 		fclose(fp); | ||
|  | 		return false; | ||
|  | 	} | ||
|  | 	if (fseek(fp, 0, SEEK_SET) != 0) | ||
|  | 	{ | ||
|  | 		fclose(fp); | ||
|  | 		return false; | ||
|  | 	} | ||
|  | 	buf = new char[bufSize]; | ||
|  | 	if (!buf) | ||
|  | 	{ | ||
|  | 		fclose(fp); | ||
|  | 		return false; | ||
|  | 	} | ||
|  | 	size_t readLen = fread(buf, bufSize, 1, fp); | ||
|  | 	fclose(fp); | ||
|  | 
 | ||
|  | 	if (readLen != 1) | ||
|  | 	{ | ||
|  | 		delete[] buf; | ||
|  | 		return false; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	char* src = buf; | ||
|  | 	char* srcEnd = buf + bufSize; | ||
|  | 	char row[512]; | ||
|  | 	int face[32]; | ||
|  | 	float x,y,z; | ||
|  | 	int nv; | ||
|  | 	int vcap = 0; | ||
|  | 	int tcap = 0; | ||
|  | 	 | ||
|  | 	while (src < srcEnd) | ||
|  | 	{ | ||
|  | 		// Parse one row
 | ||
|  | 		row[0] = '\0'; | ||
|  | 		src = parseRow(src, srcEnd, row, sizeof(row)/sizeof(char)); | ||
|  | 		// Skip comments
 | ||
|  | 		if (row[0] == '#') continue; | ||
|  | 		if (row[0] == 'v' && row[1] != 'n' && row[1] != 't') | ||
|  | 		{ | ||
|  | 			// Vertex pos
 | ||
|  | 			sscanf(row+1, "%f %f %f", &x, &y, &z); | ||
|  | 			addVertex(x, y, z, vcap); | ||
|  | 		} | ||
|  | 		if (row[0] == 'f') | ||
|  | 		{ | ||
|  | 			// Faces
 | ||
|  | 			nv = parseFace(row+1, face, 32, m_vertCount); | ||
|  | 			for (int i = 2; i < nv; ++i) | ||
|  | 			{ | ||
|  | 				const int a = face[0]; | ||
|  | 				const int b = face[i-1]; | ||
|  | 				const int c = face[i]; | ||
|  | 				if (a < 0 || a >= m_vertCount || b < 0 || b >= m_vertCount || c < 0 || c >= m_vertCount) | ||
|  | 					continue; | ||
|  | 				addTriangle(a, b, c, tcap); | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	delete [] buf; | ||
|  | 
 | ||
|  | 	// Calculate normals.
 | ||
|  | 	m_normals = new float[m_triCount*3]; | ||
|  | 	for (int i = 0; i < m_triCount*3; i += 3) | ||
|  | 	{ | ||
|  | 		const float* v0 = &m_verts[m_tris[i]*3]; | ||
|  | 		const float* v1 = &m_verts[m_tris[i+1]*3]; | ||
|  | 		const float* v2 = &m_verts[m_tris[i+2]*3]; | ||
|  | 		float e0[3], e1[3]; | ||
|  | 		for (int j = 0; j < 3; ++j) | ||
|  | 		{ | ||
|  | 			e0[j] = v1[j] - v0[j]; | ||
|  | 			e1[j] = v2[j] - v0[j]; | ||
|  | 		} | ||
|  | 		float* n = &m_normals[i]; | ||
|  | 		n[0] = e0[1]*e1[2] - e0[2]*e1[1]; | ||
|  | 		n[1] = e0[2]*e1[0] - e0[0]*e1[2]; | ||
|  | 		n[2] = e0[0]*e1[1] - e0[1]*e1[0]; | ||
|  | 		float d = sqrtf(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]); | ||
|  | 		if (d > 0) | ||
|  | 		{ | ||
|  | 			d = 1.0f/d; | ||
|  | 			n[0] *= d; | ||
|  | 			n[1] *= d; | ||
|  | 			n[2] *= d; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	 | ||
|  | 	m_filename = filename; | ||
|  | 	return true; | ||
|  | } |