2019-01-26 16:01:35 +11:00
|
|
|
//
|
|
|
|
// 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>
|
2019-01-26 19:43:42 +11:00
|
|
|
|
2019-01-26 16:01:35 +11:00
|
|
|
#define _USE_MATH_DEFINES
|
2019-01-26 19:43:42 +11:00
|
|
|
|
2019-01-26 16:01:35 +11:00
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
rcMeshLoaderObj::rcMeshLoaderObj() :
|
2019-01-26 19:43:42 +11:00
|
|
|
m_scale( 1.0f ),
|
|
|
|
m_verts( 0 ),
|
|
|
|
m_tris( 0 ),
|
|
|
|
m_normals( 0 ),
|
|
|
|
m_vertCount( 0 ),
|
|
|
|
m_triCount( 0 )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
rcMeshLoaderObj::~rcMeshLoaderObj()
|
|
|
|
{
|
2019-01-26 19:43:42 +11:00
|
|
|
delete[] m_verts;
|
|
|
|
delete[] m_normals;
|
|
|
|
delete[] m_tris;
|
2019-01-26 16:01:35 +11:00
|
|
|
}
|
|
|
|
|
2019-01-26 19:43:42 +11:00
|
|
|
void rcMeshLoaderObj::addVertex( float x, float y, float z, int& cap )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
2019-01-26 19:43:42 +11:00
|
|
|
if( m_vertCount + 1 > cap )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
2019-01-26 19:43:42 +11:00
|
|
|
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;
|
2019-01-26 16:01:35 +11:00
|
|
|
m_verts = nv;
|
|
|
|
}
|
2019-01-26 19:43:42 +11:00
|
|
|
float* dst = &m_verts[ m_vertCount * 3 ];
|
|
|
|
*dst++ = x * m_scale;
|
|
|
|
*dst++ = y * m_scale;
|
|
|
|
*dst++ = z * m_scale;
|
2019-01-26 16:01:35 +11:00
|
|
|
m_vertCount++;
|
|
|
|
}
|
|
|
|
|
2019-01-26 19:43:42 +11:00
|
|
|
void rcMeshLoaderObj::addTriangle( int a, int b, int c, int& cap )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
2019-01-26 19:43:42 +11:00
|
|
|
if( m_triCount + 1 > cap )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
2019-01-26 19:43:42 +11:00
|
|
|
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;
|
2019-01-26 16:01:35 +11:00
|
|
|
m_tris = nv;
|
|
|
|
}
|
2019-01-26 19:43:42 +11:00
|
|
|
int* dst = &m_tris[ m_triCount * 3 ];
|
2019-01-26 16:01:35 +11:00
|
|
|
*dst++ = a;
|
|
|
|
*dst++ = b;
|
|
|
|
*dst++ = c;
|
|
|
|
m_triCount++;
|
|
|
|
}
|
|
|
|
|
2019-01-26 19:43:42 +11:00
|
|
|
static char* parseRow( char* buf, char* bufEnd, char* row, int len )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
|
|
|
bool start = true;
|
|
|
|
bool done = false;
|
|
|
|
int n = 0;
|
2019-01-26 19:43:42 +11:00
|
|
|
while( !done && buf < bufEnd )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
|
|
|
char c = *buf;
|
|
|
|
buf++;
|
|
|
|
// multirow
|
2019-01-26 19:43:42 +11:00
|
|
|
switch( c )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
|
|
|
case '\\':
|
|
|
|
break;
|
|
|
|
case '\n':
|
2019-01-26 19:43:42 +11:00
|
|
|
if( start )
|
|
|
|
break;
|
2019-01-26 16:01:35 +11:00
|
|
|
done = true;
|
|
|
|
break;
|
|
|
|
case '\r':
|
|
|
|
break;
|
|
|
|
case '\t':
|
|
|
|
case ' ':
|
2019-01-26 19:43:42 +11:00
|
|
|
if( start )
|
|
|
|
break;
|
2019-01-26 16:01:35 +11:00
|
|
|
// else falls through
|
|
|
|
default:
|
|
|
|
start = false;
|
2019-01-26 19:43:42 +11:00
|
|
|
row[ n++ ] = c;
|
|
|
|
if( n >= len - 1 )
|
2019-01-26 16:01:35 +11:00
|
|
|
done = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-01-26 19:43:42 +11:00
|
|
|
row[ n ] = '\0';
|
2019-01-26 16:01:35 +11:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2019-01-26 19:43:42 +11:00
|
|
|
static int parseFace( char* row, int* data, int n, int vcnt )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
|
|
|
int j = 0;
|
2019-01-26 19:43:42 +11:00
|
|
|
while( *row != '\0' )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
|
|
|
// Skip initial white space
|
2019-01-26 19:43:42 +11:00
|
|
|
while( *row != '\0' && ( *row == ' ' || *row == '\t' ) )
|
2019-01-26 16:01:35 +11:00
|
|
|
row++;
|
|
|
|
char* s = row;
|
|
|
|
// Find vertex delimiter and terminated the string there for conversion.
|
2019-01-26 19:43:42 +11:00
|
|
|
while( *row != '\0' && *row != ' ' && *row != '\t' )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
2019-01-26 19:43:42 +11:00
|
|
|
if( *row == '/' )
|
|
|
|
*row = '\0';
|
2019-01-26 16:01:35 +11:00
|
|
|
row++;
|
|
|
|
}
|
2019-01-26 19:43:42 +11:00
|
|
|
if( *s == '\0' )
|
2019-01-26 16:01:35 +11:00
|
|
|
continue;
|
2019-01-26 19:43:42 +11:00
|
|
|
int vi = atoi( s );
|
|
|
|
data[ j++ ] = vi < 0 ? vi + vcnt : vi - 1;
|
|
|
|
if( j >= n )
|
|
|
|
return j;
|
2019-01-26 16:01:35 +11:00
|
|
|
}
|
|
|
|
return j;
|
|
|
|
}
|
|
|
|
|
2019-01-26 19:43:42 +11:00
|
|
|
bool rcMeshLoaderObj::load( const std::string& filename )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
|
|
|
char* buf = 0;
|
2019-01-26 19:43:42 +11:00
|
|
|
FILE* fp = fopen( filename.c_str(), "rb" );
|
|
|
|
if( !fp )
|
2019-01-26 16:01:35 +11:00
|
|
|
return false;
|
2019-01-26 19:43:42 +11:00
|
|
|
if( fseek( fp, 0, SEEK_END ) != 0 )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
2019-01-26 19:43:42 +11:00
|
|
|
fclose( fp );
|
2019-01-26 16:01:35 +11:00
|
|
|
return false;
|
|
|
|
}
|
2019-01-26 19:43:42 +11:00
|
|
|
long bufSize = ftell( fp );
|
|
|
|
if( bufSize < 0 )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
2019-01-26 19:43:42 +11:00
|
|
|
fclose( fp );
|
2019-01-26 16:01:35 +11:00
|
|
|
return false;
|
|
|
|
}
|
2019-01-26 19:43:42 +11:00
|
|
|
if( fseek( fp, 0, SEEK_SET ) != 0 )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
2019-01-26 19:43:42 +11:00
|
|
|
fclose( fp );
|
2019-01-26 16:01:35 +11:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
buf = new char[bufSize];
|
2019-01-26 19:43:42 +11:00
|
|
|
if( !buf )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
2019-01-26 19:43:42 +11:00
|
|
|
fclose( fp );
|
2019-01-26 16:01:35 +11:00
|
|
|
return false;
|
|
|
|
}
|
2019-01-26 19:43:42 +11:00
|
|
|
size_t readLen = fread( buf, bufSize, 1, fp );
|
|
|
|
fclose( fp );
|
2019-01-26 16:01:35 +11:00
|
|
|
|
2019-01-26 19:43:42 +11:00
|
|
|
if( readLen != 1 )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
|
|
|
delete[] buf;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* src = buf;
|
|
|
|
char* srcEnd = buf + bufSize;
|
|
|
|
char row[512];
|
|
|
|
int face[32];
|
2019-01-26 19:43:42 +11:00
|
|
|
float x, y, z;
|
2019-01-26 16:01:35 +11:00
|
|
|
int nv;
|
|
|
|
int vcap = 0;
|
|
|
|
int tcap = 0;
|
|
|
|
|
2019-01-26 19:43:42 +11:00
|
|
|
while( src < srcEnd )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
|
|
|
// Parse one row
|
2019-01-26 19:43:42 +11:00
|
|
|
row[ 0 ] = '\0';
|
|
|
|
src = parseRow( src, srcEnd, row, sizeof( row ) / sizeof( char ) );
|
2019-01-26 16:01:35 +11:00
|
|
|
// Skip comments
|
2019-01-26 19:43:42 +11:00
|
|
|
if( row[ 0 ] == '#' )
|
|
|
|
continue;
|
|
|
|
if( row[ 0 ] == 'v' && row[ 1 ] != 'n' && row[ 1 ] != 't' )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
|
|
|
// Vertex pos
|
2019-01-26 19:43:42 +11:00
|
|
|
sscanf( row + 1, "%f %f %f", &x, &y, &z );
|
|
|
|
addVertex( x, y, z, vcap );
|
2019-01-26 16:01:35 +11:00
|
|
|
}
|
2019-01-26 19:43:42 +11:00
|
|
|
if( row[ 0 ] == 'f' )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
|
|
|
// Faces
|
2019-01-26 19:43:42 +11:00
|
|
|
nv = parseFace( row + 1, face, 32, m_vertCount );
|
|
|
|
for( int i = 2; i < nv; ++i )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
2019-01-26 19:43:42 +11:00
|
|
|
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 )
|
2019-01-26 16:01:35 +11:00
|
|
|
continue;
|
2019-01-26 19:43:42 +11:00
|
|
|
addTriangle( a, b, c, tcap );
|
2019-01-26 16:01:35 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-26 19:43:42 +11:00
|
|
|
delete[] buf;
|
2019-01-26 16:01:35 +11:00
|
|
|
|
|
|
|
// Calculate normals.
|
2019-01-26 19:43:42 +11:00
|
|
|
m_normals = new float[m_triCount * 3];
|
|
|
|
for( int i = 0; i < m_triCount * 3; i += 3 )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
2019-01-26 19:43:42 +11:00
|
|
|
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 ];
|
2019-01-26 16:01:35 +11:00
|
|
|
float e0[3], e1[3];
|
2019-01-26 19:43:42 +11:00
|
|
|
for( int j = 0; j < 3; ++j )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
2019-01-26 19:43:42 +11:00
|
|
|
e0[ j ] = v1[ j ] - v0[ j ];
|
|
|
|
e1[ j ] = v2[ j ] - v0[ j ];
|
2019-01-26 16:01:35 +11:00
|
|
|
}
|
2019-01-26 19:43:42 +11:00
|
|
|
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 )
|
2019-01-26 16:01:35 +11:00
|
|
|
{
|
2019-01-26 19:43:42 +11:00
|
|
|
d = 1.0f / d;
|
|
|
|
n[ 0 ] *= d;
|
|
|
|
n[ 1 ] *= d;
|
|
|
|
n[ 2 ] *= d;
|
2019-01-26 16:01:35 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_filename = filename;
|
|
|
|
return true;
|
|
|
|
}
|