mirror of
https://github.com/ncblakely/GiantsTools
synced 2024-11-27 08:03:09 +01:00
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;
|
|
}
|