You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
438 lines
12 KiB
438 lines
12 KiB
// |
|
// Copyright (c) 2010-2011 Matthew Jack and Doug Binks |
|
// |
|
// 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 "AURenMesh.h" |
|
|
|
|
|
#ifndef _WIN32 |
|
#define NO_ASSIMP //Currently not adding assimp support to other platforms |
|
#endif |
|
|
|
|
|
#include "../Common/AUVec3f.inl" //for cross product used in calculateing normals |
|
|
|
// Windows Requirements |
|
#ifdef _WIN32 |
|
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers |
|
#include <windows.h> |
|
#endif //_WIN32 |
|
|
|
|
|
#ifdef __MACH__ |
|
#include <OpenGL/gl.h> |
|
#else |
|
// OpenGL requirements |
|
#include <GL/gl.h> |
|
#endif //__MACH__ |
|
|
|
#ifndef NO_ASSIMP |
|
#include <assimp.hpp> |
|
#include <aiScene.h> |
|
#include <aiPostProcess.h> |
|
#endif //NO_ASSIMP |
|
|
|
#ifndef _WIN32 |
|
#include <string.h> |
|
int _stricmp( const char* pS1, const char* pS2 ) |
|
{ |
|
return strcasecmp( pS1, pS2 ); |
|
} |
|
#endif |
|
|
|
#include <fstream> |
|
#include <assert.h> |
|
|
|
AURenMesh::AURenMesh() : |
|
m_pafVertexCoordinates( NULL ), |
|
m_pafTextureCoordinates( NULL ), |
|
m_pafNormals( NULL ), |
|
m_pausTriangleIndices( NULL ), |
|
m_uiNumVertices( 0 ), |
|
m_uiNumTriangles( 0 ) |
|
{ |
|
} |
|
|
|
AURenMesh::~AURenMesh() |
|
{ |
|
Clear(); |
|
} |
|
|
|
void AURenMesh::Clear() |
|
{ |
|
delete[] m_pafNormals; |
|
delete[] m_pafVertexCoordinates; |
|
delete[] m_pafTextureCoordinates; |
|
delete[] m_pausTriangleIndices; |
|
} |
|
|
|
bool AURenMesh::LoadFromFile( const std::string& strFilename ) |
|
{ |
|
// Safely delete any existing data before loading new mesh |
|
Clear(); |
|
|
|
int index = (int)strFilename.size() - 3; |
|
std::string extension = index >= 0 ? strFilename.substr(index, 3) : ""; |
|
if (!_stricmp(extension.c_str(), "aml")) |
|
{ |
|
return LoadFromFileAML(strFilename); |
|
} |
|
else |
|
{ |
|
return LoadFromFileImport(strFilename); |
|
} |
|
} |
|
|
|
bool AURenMesh::SaveToFile( const std::string& strFilename ) |
|
{ |
|
std::ofstream outFile; |
|
outFile.open(strFilename.c_str(), std::ios::binary); |
|
|
|
if( !outFile ) |
|
{ |
|
return false; |
|
} |
|
|
|
outFile << "AML Aurora File" << std::endl; |
|
outFile << 1 << std::endl; // version |
|
outFile << m_uiNumVertices << std::endl; |
|
outFile << m_uiNumTriangles << std::endl; |
|
|
|
outFile.write( reinterpret_cast<char*>( m_pafVertexCoordinates ), 3 * m_uiNumVertices * sizeof( float ) ); |
|
outFile.write( reinterpret_cast<char*>( m_pafTextureCoordinates ), 2 * m_uiNumVertices * sizeof( float ) ); |
|
outFile.write( reinterpret_cast<char*>( m_pafNormals ), 3 * m_uiNumVertices * sizeof( float ) ); |
|
outFile.write( reinterpret_cast<char*>( m_pausTriangleIndices ), 3 * m_uiNumTriangles * sizeof( unsigned short ) ); |
|
|
|
outFile.close(); |
|
|
|
return true; |
|
} |
|
|
|
bool AURenMesh::LoadFromFileAML( const std::string& strFilename_ ) |
|
{ |
|
std::ifstream inFile; |
|
inFile.open(strFilename_.c_str(), std::ios::binary); |
|
|
|
if( !inFile ) |
|
{ |
|
return false; |
|
} |
|
|
|
inFile.ignore(10000,'\n'); //ignore first line |
|
|
|
int iVersion; |
|
inFile >> iVersion; //currently ignore version number |
|
|
|
inFile >> m_uiNumVertices; |
|
|
|
inFile >> m_uiNumTriangles; |
|
|
|
//now discard end of line |
|
inFile.ignore(10000,'\n'); |
|
|
|
m_pafVertexCoordinates = new float[ 3 * m_uiNumVertices ]; |
|
m_pafNormals = new float[ 3 * m_uiNumVertices ]; |
|
m_pafTextureCoordinates = new float[ 2 * m_uiNumVertices ]; |
|
m_pausTriangleIndices = new unsigned short[ 3 * m_uiNumTriangles ]; |
|
|
|
inFile.read( reinterpret_cast<char*>( m_pafVertexCoordinates ), 3 * m_uiNumVertices * sizeof( float ) ); |
|
inFile.read( reinterpret_cast<char*>( m_pafTextureCoordinates ), 2 * m_uiNumVertices * sizeof( float ) ); |
|
inFile.read( reinterpret_cast<char*>( m_pafNormals ), 3 * m_uiNumVertices * sizeof( float ) ); |
|
inFile.read( reinterpret_cast<char*>( m_pausTriangleIndices ), 3 * m_uiNumTriangles * sizeof( unsigned short ) ); |
|
|
|
|
|
return true; |
|
} |
|
|
|
bool AURenMesh::LoadFromFileImport( const std::string& strFilename ) |
|
{ |
|
#ifndef NO_ASSIMP |
|
Assimp::Importer importer; |
|
|
|
const aiScene* pScene = importer.ReadFile( strFilename, aiProcessPreset_TargetRealtime_Fast ); |
|
|
|
if (!pScene || pScene->mNumMeshes == 0) |
|
{ |
|
return false; |
|
} |
|
|
|
ProcessScene(pScene); |
|
|
|
return true; |
|
#else |
|
assert( false ); |
|
return false; |
|
#endif |
|
} |
|
|
|
void AURenMesh::ProcessScene( const aiScene* pScene ) |
|
{ |
|
#ifndef NO_ASSIMP |
|
// Calculate total number of verts and tris across all meshes in scene |
|
m_uiNumVertices = 0; |
|
m_uiNumTriangles = 0; |
|
for (unsigned int i=0; i<pScene->mNumMeshes; ++i) |
|
{ |
|
aiMesh* pMesh = pScene->mMeshes[i]; |
|
m_uiNumVertices += pMesh->mNumVertices; |
|
m_uiNumTriangles += pMesh->mNumFaces; |
|
} |
|
|
|
// Allocate sufficent space for all data |
|
m_pafVertexCoordinates = new float[ 3 * m_uiNumVertices ]; |
|
m_pafNormals = new float[ 3 * m_uiNumVertices ]; |
|
m_pafTextureCoordinates = new float[ 2 * m_uiNumVertices ]; |
|
m_pausTriangleIndices = new unsigned short[ 3 * m_uiNumTriangles ]; |
|
|
|
// Iterate through all meshes and load data |
|
int vertIndex = 0; |
|
int normalIndex = 0; |
|
int texIndex = 0; |
|
int triIndex = 0; |
|
for (unsigned int i=0; i<pScene->mNumMeshes; ++i) |
|
{ |
|
aiMesh* pMesh = pScene->mMeshes[i]; |
|
|
|
// Load Verts |
|
for (unsigned int j=0; j<pMesh->mNumVertices; ++j) |
|
{ |
|
const aiVector3D& vec = pMesh->mVertices[j]; |
|
m_pafVertexCoordinates[vertIndex] = vec.x; |
|
m_pafVertexCoordinates[vertIndex+1] = vec.y; |
|
m_pafVertexCoordinates[vertIndex+2] = vec.z; |
|
vertIndex += 3; |
|
} |
|
|
|
// Load Normals |
|
for (unsigned int j=0; j<pMesh->mNumVertices; ++j) |
|
{ |
|
const aiVector3D& vec = pMesh->mNormals[j]; |
|
m_pafNormals[normalIndex] = vec.x; |
|
m_pafNormals[normalIndex+1] = vec.y; |
|
m_pafNormals[normalIndex+2] = vec.z; |
|
normalIndex += 3; |
|
} |
|
|
|
// Load Tex Coords |
|
if (pMesh->HasTextureCoords(0)) |
|
{ |
|
for (unsigned int j=0; j<pMesh->mNumVertices; ++j) |
|
{ |
|
const aiVector3D& vec = pMesh->mTextureCoords[0][j]; |
|
m_pafTextureCoordinates[texIndex] = vec.x; |
|
m_pafTextureCoordinates[texIndex+1] = vec.y; |
|
texIndex += 2; |
|
} |
|
} |
|
|
|
|
|
// Load Tris |
|
for (unsigned int j=0; j<pMesh->mNumFaces; ++j) |
|
{ |
|
const aiFace& tri = pMesh->mFaces[j]; |
|
m_pausTriangleIndices[triIndex] = tri.mIndices[0]; |
|
m_pausTriangleIndices[triIndex+1] = tri.mIndices[1]; |
|
m_pausTriangleIndices[triIndex+2] = tri.mIndices[2]; |
|
triIndex += 3; |
|
} |
|
} |
|
#endif |
|
} |
|
|
|
////////////////////////////////////////////////////////////////////////////////////////// |
|
// Function: AURenMesh::AURenMesh |
|
// |
|
// Last Modified by: Douglas John Binks (DJB) |
|
// |
|
// Last Modified: 21 June 2000 |
|
// |
|
// Purpose: Normalises the size and position of the object to be |
|
// centered around the origin and of the correct BCube extent. |
|
// |
|
// Inputs: fBCubeHalfWidth_ : float giving the half width of the |
|
// bounding cube. |
|
// |
|
// Outputs: None. |
|
// |
|
// Returns: None. |
|
// |
|
////////////////////////////////////////////////////////////////////////////////////////// |
|
void AURenMesh::NormaliseToBCubeHalfWidth( float fBCubeHalfWidth_ ) |
|
{ |
|
//set up min and max variablse for each axis and use a real value from the |
|
//array to initialise (as a `made up' value may be wrong unless we use |
|
//floatmax for min etc.). |
|
float fMinX = m_pafVertexCoordinates[0]; |
|
float fMaxX = m_pafVertexCoordinates[0]; |
|
float fMinY = m_pafVertexCoordinates[1]; |
|
float fMaxY = m_pafVertexCoordinates[1]; |
|
float fMinZ = m_pafVertexCoordinates[2]; |
|
float fMaxZ = m_pafVertexCoordinates[2]; |
|
|
|
//Go through array of vertices to find the real min and max |
|
unsigned int uiCountCoords; |
|
for( uiCountCoords = 0; |
|
uiCountCoords < 3 * m_uiNumVertices; |
|
uiCountCoords += 3 ) |
|
{ |
|
if( fMinX > m_pafVertexCoordinates[ uiCountCoords ] ) |
|
{ |
|
fMinX = m_pafVertexCoordinates[ uiCountCoords ]; |
|
} |
|
else |
|
{ |
|
if( fMaxX < m_pafVertexCoordinates[ uiCountCoords ] ) |
|
{ |
|
fMaxX = m_pafVertexCoordinates[ uiCountCoords ]; |
|
} |
|
} |
|
|
|
if( fMinY > m_pafVertexCoordinates[ uiCountCoords + 1 ] ) |
|
{ |
|
fMinY = m_pafVertexCoordinates[ uiCountCoords + 1 ]; |
|
} |
|
else |
|
{ |
|
if( fMaxY < m_pafVertexCoordinates[ uiCountCoords + 1 ] ) |
|
{ |
|
fMaxY = m_pafVertexCoordinates[ uiCountCoords + 1 ]; |
|
} |
|
} |
|
|
|
if( fMinZ > m_pafVertexCoordinates[ uiCountCoords + 2 ] ) |
|
{ |
|
fMinZ = m_pafVertexCoordinates[ uiCountCoords + 2 ]; |
|
} |
|
else |
|
{ |
|
if( fMaxZ < m_pafVertexCoordinates[ uiCountCoords + 2 ] ) |
|
{ |
|
fMaxZ = m_pafVertexCoordinates[ uiCountCoords + 2 ]; |
|
} |
|
} |
|
} |
|
|
|
//calulate the current center |
|
float fCenterX = ( fMaxX + fMinX )/2.0f; |
|
float fCenterY = ( fMaxY + fMinY )/2.0f; |
|
float fCenterZ = ( fMaxZ + fMinZ )/2.0f; |
|
|
|
//calculate the largest distance^2 from the center |
|
float fMaxDistance2 = 0.0f; |
|
float fDistance2; |
|
float fX2, fY2, fZ2; |
|
for( uiCountCoords = 0; |
|
uiCountCoords < 3 * m_uiNumVertices; |
|
uiCountCoords += 3 ) |
|
{ |
|
fX2 = m_pafVertexCoordinates[ uiCountCoords ] - fCenterX; |
|
fX2 *= fX2; |
|
fY2 = m_pafVertexCoordinates[ uiCountCoords + 1 ] - fCenterY; |
|
fY2 *= fY2; |
|
fZ2 = m_pafVertexCoordinates[ uiCountCoords + 2 ] - fCenterZ; |
|
fZ2 *= fZ2; |
|
fDistance2 = fX2 + fY2 + fZ2; |
|
if( fDistance2 > fMaxDistance2 ) |
|
{ |
|
fMaxDistance2 = fDistance2; |
|
} |
|
} |
|
|
|
//calculate normalising coefficient such that Xnew = cf * Xold |
|
float fCoefficient = fBCubeHalfWidth_ / sqrt( fMaxDistance2 ); |
|
|
|
//now do normalisation ( use seperate calcs for X,Y,Z so as to use possible |
|
//parallel floating point units). |
|
for( uiCountCoords = 0; |
|
uiCountCoords < 3 * m_uiNumVertices; |
|
uiCountCoords += 3 ) |
|
{ |
|
m_pafVertexCoordinates[ uiCountCoords ] = |
|
fCoefficient * ( m_pafVertexCoordinates[ uiCountCoords ] - fCenterX ); |
|
m_pafVertexCoordinates[ uiCountCoords + 1 ] = |
|
fCoefficient * ( m_pafVertexCoordinates[ uiCountCoords + 1 ] - fCenterY ); |
|
m_pafVertexCoordinates[ uiCountCoords + 2 ] = |
|
fCoefficient * ( m_pafVertexCoordinates[ uiCountCoords + 2 ] - fCenterZ ); |
|
} |
|
|
|
} |
|
|
|
////////////////////////////////////////////////////////////////////////////////////////// |
|
// Function: AURenMesh::Render |
|
// |
|
// Last Modified by: Douglas John Binks (DJB) |
|
// |
|
// Last Modified: 25 July 2000 |
|
// |
|
// Purpose: Draws the mesh. |
|
// |
|
// Inputs: None. |
|
// |
|
// Outputs: None. |
|
// |
|
// Returns: None. |
|
// |
|
////////////////////////////////////////////////////////////////////////////////////////// |
|
void AURenMesh::Render(const AUColor* pCol ) const |
|
{ |
|
if( 0 == m_uiNumVertices ) |
|
{ |
|
return; |
|
} |
|
|
|
const GLfloat pafDiffuseColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; |
|
const GLfloat pafSpecularColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; |
|
const GLfloat fShininess = 40.0f; |
|
|
|
|
|
if( 0 == pCol ) |
|
{ |
|
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, pafDiffuseColor); |
|
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pafDiffuseColor); |
|
} |
|
else |
|
{ |
|
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, pCol->m_Color.rgba ); |
|
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pCol->m_Color.rgba); |
|
} |
|
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, pafSpecularColor); |
|
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, fShininess); |
|
|
|
const GLint iNumCoordinatesPerVertex = 3; |
|
const GLsizei iStride = 0; |
|
|
|
//set up vertex arrays |
|
glEnableClientState( GL_VERTEX_ARRAY ); |
|
glEnableClientState( GL_NORMAL_ARRAY ); |
|
glVertexPointer( iNumCoordinatesPerVertex, GL_FLOAT, iStride, |
|
(const GLvoid*)m_pafVertexCoordinates ); |
|
glNormalPointer( GL_FLOAT, iStride, |
|
(const GLvoid*)m_pafNormals ); |
|
glEnableClientState( GL_TEXTURE_COORD_ARRAY ); |
|
glTexCoordPointer( 2, GL_FLOAT, iStride, |
|
(const GLvoid*)m_pafTextureCoordinates ); |
|
|
|
//do actual drawing |
|
glDrawElements( GL_TRIANGLES, 3 * m_uiNumTriangles, GL_UNSIGNED_SHORT, m_pausTriangleIndices ); |
|
|
|
|
|
//unset vertex arrays |
|
glDisableClientState( GL_TEXTURE_COORD_ARRAY ); |
|
glDisableClientState( GL_VERTEX_ARRAY ); |
|
glDisableClientState( GL_NORMAL_ARRAY ); |
|
|
|
}
|
|
|