diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Samples/SampleBase/wavefront.cpp | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'PhysX_3.4/Samples/SampleBase/wavefront.cpp')
| -rw-r--r-- | PhysX_3.4/Samples/SampleBase/wavefront.cpp | 946 |
1 files changed, 946 insertions, 0 deletions
diff --git a/PhysX_3.4/Samples/SampleBase/wavefront.cpp b/PhysX_3.4/Samples/SampleBase/wavefront.cpp new file mode 100644 index 00000000..b6d712e6 --- /dev/null +++ b/PhysX_3.4/Samples/SampleBase/wavefront.cpp @@ -0,0 +1,946 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <ctype.h> + +#include "wavefront.h" +#include "FrameworkFoundation.h" +#include "PxTkFile.h" + +namespace WAVEFRONT +{ + + /*******************************************************************/ + /******************** InParser.h ********************************/ + /*******************************************************************/ + class InPlaceParserInterface + { + public: + virtual int ParseLine(int lineno,int argc,const char **argv) =0; // return TRUE to continue parsing, return FALSE to abort parsing process + virtual ~InPlaceParserInterface() {} + }; + + enum SeparatorType + { + ST_DATA, // is data + ST_HARD, // is a hard separator + ST_SOFT, // is a soft separator + ST_EOS // is a comment symbol, and everything past this character should be ignored + }; + + class InPlaceParser + { + public: + InPlaceParser(void) + { + Init(); + } + + InPlaceParser(char *data,int len) + { + Init(); + SetSourceData(data,len); + } + + InPlaceParser(const char *fname) + { + Init(); + SetFile(fname); + } + + ~InPlaceParser(void); + + void Init(void) + { + mQuoteChar = 34; + mData = 0; + mLen = 0; + mMyAlloc = false; + for (int i=0; i<256; i++) + { + mHard[i] = ST_DATA; + mHardString[i*2] = i; + mHardString[i*2+1] = 0; + } + mHard[0] = ST_EOS; + mHard[32] = ST_SOFT; + mHard[9] = ST_SOFT; + mHard[13] = ST_SOFT; + mHard[10] = ST_SOFT; + } + + void SetFile(const char *fname); // use this file as source data to parse. + + void SetSourceData(char *data,int len) + { + mData = data; + mLen = len; + mMyAlloc = false; + } + + int Parse(InPlaceParserInterface *callback); // returns true if entire file was parsed, false if it aborted for some reason + + int ProcessLine(int lineno,char *line,InPlaceParserInterface *callback); + + const char ** GetArglist(char *source,int &count); // convert source string into an arg list, this is a destructive parse. + + void SetHardSeparator(char c) // add a hard separator + { + mHard[(unsigned int)c] = ST_HARD; + } + + void SetHard(char c) // add a hard separator + { + mHard[(unsigned int)c] = ST_HARD; + } + + + void SetCommentSymbol(char c) // comment character, treated as 'end of string' + { + mHard[(unsigned int)c] = ST_EOS; + } + + void ClearHardSeparator(char c) + { + mHard[(unsigned int)c] = ST_DATA; + } + + + void DefaultSymbols(void); // set up default symbols for hard seperator and comment symbol of the '#' character. + + bool EOS(char c) + { + if ( mHard[(unsigned int)c] == ST_EOS ) + { + return true; + } + return false; + } + + void SetQuoteChar(char c) + { + mQuoteChar = c; + } + + private: + + + inline char * AddHard(int &argc,const char **argv,char *foo); + inline bool IsHard(char c); + inline char * SkipSpaces(char *foo); + inline bool IsWhiteSpace(char c); + inline bool IsNonSeparator(char c); // non seperator,neither hard nor soft + + bool mMyAlloc; // whether or not *I* allocated the buffer and am responsible for deleting it. + char *mData; // ascii data to parse. + int mLen; // length of data + SeparatorType mHard[256]; + char mHardString[256*2]; + char mQuoteChar; + }; + + /*******************************************************************/ + /******************** InParser.cpp ********************************/ + /*******************************************************************/ + void InPlaceParser::SetFile(const char* fname) + { + if ( mMyAlloc ) + free(mData); + + mData = 0; + mLen = 0; + mMyAlloc = false; + + SampleFramework::File* fph = NULL; + PxToolkit::fopen_s(&fph, fname, "rb"); + if ( fph ) + { + fseek(fph,0L,SEEK_END); + mLen = (int)ftell(fph); + fseek(fph,0L,SEEK_SET); + if ( mLen ) + { + mData = (char *) malloc(sizeof(char)*(mLen+1)); + int ok = int(fread(mData, 1, mLen, fph)); + if ( !ok ) + { + free(mData); + mData = 0; + } + else + { + mData[mLen] = 0; // zero byte terminate end of file marker. + mMyAlloc = true; + } + } + fclose(fph); + } + } + + InPlaceParser::~InPlaceParser(void) + { + if ( mMyAlloc ) + free(mData); + } + +#define MAXARGS 512 + + bool InPlaceParser::IsHard(char c) + { + return mHard[(unsigned int)c] == ST_HARD; + } + + char * InPlaceParser::AddHard(int &argc,const char **argv,char *foo) + { + while ( IsHard(*foo) ) + { + const char *hard = &mHardString[*foo*2]; + if ( argc < MAXARGS ) + { + argv[argc++] = hard; + } + foo++; + } + return foo; + } + + bool InPlaceParser::IsWhiteSpace(char c) + { + return mHard[(unsigned int)c] == ST_SOFT; + } + + char * InPlaceParser::SkipSpaces(char *foo) + { + while ( !EOS(*foo) && IsWhiteSpace(*foo) ) foo++; + return foo; + } + + bool InPlaceParser::IsNonSeparator(char c) + { + if ( !IsHard(c) && !IsWhiteSpace(c) && c != 0 ) return true; + return false; + } + + + int InPlaceParser::ProcessLine(int lineno,char *line,InPlaceParserInterface *callback) + { + int ret = 0; + + const char *argv[MAXARGS]; + int argc = 0; + + char *foo = line; + + while ( !EOS(*foo) && argc < MAXARGS ) + { + + foo = SkipSpaces(foo); // skip any leading spaces + + if ( EOS(*foo) ) break; + + if ( *foo == mQuoteChar ) // if it is an open quote + { + foo++; + if ( argc < MAXARGS ) + { + argv[argc++] = foo; + } + while ( !EOS(*foo) && *foo != mQuoteChar ) foo++; + if ( !EOS(*foo) ) + { + *foo = 0; // replace close quote with zero byte EOS + foo++; + } + } + else + { + + foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces + + if ( IsNonSeparator(*foo) ) // add non-hard argument. + { + bool quote = false; + if ( *foo == mQuoteChar ) + { + foo++; + quote = true; + } + + if ( argc < MAXARGS ) + { + argv[argc++] = foo; + } + + if ( quote ) + { + while (*foo && *foo != mQuoteChar ) foo++; + if ( *foo ) *foo = 32; + } + + // continue..until we hit an eos .. + while ( !EOS(*foo) ) // until we hit EOS + { + if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit + { + *foo = 0; + foo++; + break; + } + else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument + { + const char *hard = &mHardString[*foo*2]; + *foo = 0; + if ( argc < MAXARGS ) + { + argv[argc++] = hard; + } + foo++; + break; + } + foo++; + } // end of while loop... + } + } + } + + if ( argc ) + { + ret = callback->ParseLine(lineno, argc, argv ); + } + + return ret; + } + + int InPlaceParser::Parse(InPlaceParserInterface *callback) // returns true if entire file was parsed, false if it aborted for some reason + { + assert( callback ); + if ( !mData ) return 0; + + int ret = 0; + + int lineno = 0; + + char *foo = mData; + char *begin = foo; + + + while ( *foo ) + { + if ( *foo == 10 || *foo == 13 ) + { + lineno++; + *foo = 0; + + if ( *begin ) // if there is any data to parse at all... + { + int v = ProcessLine(lineno,begin,callback); + if ( v ) ret = v; + } + + foo++; + if ( *foo == 10 ) foo++; // skip line feed, if it is in the carraige-return line-feed format... + begin = foo; + } + else + { + foo++; + } + } + + lineno++; // last line. + + int v = ProcessLine(lineno,begin,callback); + if ( v ) ret = v; + return ret; + } + + + void InPlaceParser::DefaultSymbols(void) + { + SetHardSeparator(','); + SetHardSeparator('('); + SetHardSeparator(')'); + SetHardSeparator('='); + SetHardSeparator('['); + SetHardSeparator(']'); + SetHardSeparator('{'); + SetHardSeparator('}'); + SetCommentSymbol('#'); + } + + + const char ** InPlaceParser::GetArglist(char *line,int &count) // convert source string into an arg list, this is a destructive parse. + { + const char **ret = 0; + + static const char *argv[MAXARGS]; + int argc = 0; + + char *foo = line; + + while ( !EOS(*foo) && argc < MAXARGS ) + { + + foo = SkipSpaces(foo); // skip any leading spaces + + if ( EOS(*foo) ) break; + + if ( *foo == mQuoteChar ) // if it is an open quote + { + foo++; + if ( argc < MAXARGS ) + { + argv[argc++] = foo; + } + while ( !EOS(*foo) && *foo != mQuoteChar ) foo++; + if ( !EOS(*foo) ) + { + *foo = 0; // replace close quote with zero byte EOS + foo++; + } + } + else + { + + foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces + + if ( IsNonSeparator(*foo) ) // add non-hard argument. + { + bool quote = false; + if ( *foo == mQuoteChar ) + { + foo++; + quote = true; + } + + if ( argc < MAXARGS ) + { + argv[argc++] = foo; + } + + if ( quote ) + { + while (*foo && *foo != mQuoteChar ) foo++; + if ( *foo ) *foo = 32; + } + + // continue..until we hit an eos .. + while ( !EOS(*foo) ) // until we hit EOS + { + if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit + { + *foo = 0; + foo++; + break; + } + else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument + { + const char *hard = &mHardString[*foo*2]; + *foo = 0; + if ( argc < MAXARGS ) + { + argv[argc++] = hard; + } + foo++; + break; + } + foo++; + } // end of while loop... + } + } + } + + count = argc; + if ( argc ) + { + ret = argv; + } + + return ret; + } + + /*******************************************************************/ + /******************** Geometry.h ********************************/ + /*******************************************************************/ + + class GeometryVertex + { + public: + float mPos[3]; + float mNormal[3]; + float mTexel[2]; + }; + + + class GeometryInterface + { + public: + + virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3, bool textured) + { + } + + virtual ~GeometryInterface() {} + + }; + + + /*******************************************************************/ + /******************** Obj.h ********************************/ + /*******************************************************************/ + + + class OBJ : public InPlaceParserInterface + { + public: + int LoadMesh(const char *fname,GeometryInterface *callback, bool textured); + int ParseLine(int lineno,int argc,const char **argv); // return TRUE to continue parsing, return FALSE to abort parsing process + + OBJ() : mVerts(NULL), mTexels(NULL), mNormals(NULL), mTextured(false), mCallback(NULL) { Clear(); } + ~OBJ() { Clear(); } + + private: + + void Clear(); + void GetVertex(GeometryVertex &v,const char *face) const; + + float* mVerts; + unsigned mNumVerts; // this is the tripled number of verts + unsigned mMaxVerts; + + float* mTexels; // doubled number of texcoords + unsigned mNumTexels; + unsigned mMaxTexels; + + float* mNormals; // tripled number of normals + unsigned mNumNormals; + unsigned mMaxNormals; + + bool mTextured; + GeometryInterface* mCallback; + }; + + + /*******************************************************************/ + /******************** Obj.cpp ********************************/ + /*******************************************************************/ + + int OBJ::LoadMesh(const char *fname, GeometryInterface *iface, bool textured) + { + Clear(); + + mTextured = textured; + int ret = 0; + mCallback = iface; + + InPlaceParser ipp(fname); + + ipp.Parse(this); + + return ret; + } + + void OBJ::Clear() + { + if (mVerts) + delete[] mVerts; + mMaxVerts = 0; + mNumVerts = 0; + + if (mTexels) + delete[] mTexels; + mMaxTexels = 0; + mNumTexels = 0; + + if (mNormals) + delete[] mNormals; + mMaxNormals = 0; + mNumNormals = 0; + } + + void OBJ::GetVertex(GeometryVertex &v,const char *face) const + { + v.mPos[0] = 0; + v.mPos[1] = 0; + v.mPos[2] = 0; + + v.mTexel[0] = 0; + v.mTexel[1] = 0; + + v.mNormal[0] = 0; + v.mNormal[1] = 1; + v.mNormal[2] = 0; + + int index = atoi( face )-1; + + const char *texel = strstr(face,"/"); + + if ( texel ) + { + int tindex = atoi( texel+1) - 1; + + if ( tindex >=0 && tindex < (int)(mNumTexels/2) ) + { + const float *t = &mTexels[tindex*2]; + + v.mTexel[0] = t[0]; + v.mTexel[1] = t[1]; + + } + + const char *normal = strstr(texel+1,"/"); + if ( normal ) + { + int nindex = atoi( normal+1 ) - 1; + + if (nindex >= 0 && nindex < (int)(mNumNormals/3) ) + { + const float *n = &mNormals[nindex*3]; + + v.mNormal[0] = n[0]; + v.mNormal[1] = n[1]; + v.mNormal[2] = n[2]; + } + } + } + + if ( index >= 0 && index < (int)(mNumVerts/3) ) + { + + const float *p = &mVerts[index*3]; + + v.mPos[0] = p[0]; + v.mPos[1] = p[1]; + v.mPos[2] = p[2]; + } else + assert(0 == "Negative face vertex indices are not supported in wavefront loader."); + } + + template<typename T> + void Resize(T*& data, unsigned& capacity, unsigned count, unsigned new_count) + { + if (new_count >= capacity) + { + capacity = new_count*2; + T* tmp = new T[capacity]; + memcpy(tmp, data, count*sizeof(T)); + delete[] data; + data = tmp; + } + } + + int OBJ::ParseLine(int lineno,int argc,const char **argv) // return TRUE to continue parsing, return FALSE to abort parsing process + { + int ret = 0; + + if ( argc >= 1 ) + { + const char *foo = argv[0]; + if ( *foo != '#' ) + { + if (strcmp(argv[0], "v") == 0 && argc == 4 ) + { + float vx = (float) atof( argv[1] ); + float vy = (float) atof( argv[2] ); + float vz = (float) atof( argv[3] ); + Resize(mVerts, mMaxVerts, mNumVerts, mNumVerts + 3); + mVerts[mNumVerts++] = vx; + mVerts[mNumVerts++] = vy; + mVerts[mNumVerts++] = vz; + } + else if (strcmp(argv[0],"vt") == 0 && (argc == 3 || argc == 4)) + { + // ignore 4rd component if present + float tx = (float) atof( argv[1] ); + float ty = (float) atof( argv[2] ); + Resize(mTexels, mMaxTexels, mNumTexels, mNumTexels + 2); + mTexels[mNumTexels++] = tx; + mTexels[mNumTexels++] = ty; + } + else if (strcmp(argv[0],"vn") == 0 && argc == 4 ) + { + float normalx = (float) atof(argv[1]); + float normaly = (float) atof(argv[2]); + float normalz = (float) atof(argv[3]); + Resize(mNormals, mMaxNormals, mNumNormals, mNumNormals + 3); + mNormals[mNumNormals++] = normalx; + mNormals[mNumNormals++] = normaly; + mNormals[mNumNormals++] = normalz; + + } + else if (strcmp(argv[0],"f") == 0 && argc >= 4 ) + { + GeometryVertex v[32]; + + int vcount = argc-1; + + for (int i=1; i<argc; i++) + { + GetVertex(v[i-1],argv[i] ); + } + + // need to generate a normal! +#if 0 // not currently implemented + if ( mNormals.empty() ) + { + Vector3d<float> p1( v[0].mPos ); + Vector3d<float> p2( v[1].mPos ); + Vector3d<float> p3( v[2].mPos ); + + Vector3d<float> n; + n.ComputeNormal(p3,p2,p1); + + for (int i=0; i<vcount; i++) + { + v[i].mNormal[0] = n.x; + v[i].mNormal[1] = n.y; + v[i].mNormal[2] = n.z; + } + + } +#endif + + mCallback->NodeTriangle(&v[0],&v[1],&v[2], mTextured); + + if ( vcount >=3 ) // do the fan + { + for (int i=2; i<(vcount-1); i++) + { + mCallback->NodeTriangle(&v[0],&v[i],&v[i+1], mTextured); + } + } + + } + } + } + + return ret; + } + + class BuildMesh : public GeometryInterface + { + public: + BuildMesh() : mVertices(NULL), mTexCoords(NULL), mIndices(NULL) { Clear(); } + ~BuildMesh() { Clear(); } + + void Clear() + { + if (mVertices) + delete[] mVertices; + mMaxVertices = 0; + mNumVertices = 0; + + if (mTexCoords) + delete[] mTexCoords; + mMaxTexCoords = 0; + mNumTexCoords = 0; + + if (mIndices) + delete[] mIndices; + mMaxIndices = 0; + mNumIndices = 0; + } + + int GetIndex(const float *p, const float *texCoord) + { + + int vcount = mNumVertices/3; + + if(vcount>0) + { + //New MS STL library checks indices in debug build, so zero causes an assert if it is empty. + const float *v = &mVertices[0]; + const float *t = texCoord != NULL ? &mTexCoords[0] : NULL; + + for (int i=0; i<vcount; i++) + { + if ( v[0] == p[0] && v[1] == p[1] && v[2] == p[2] ) + { + if (texCoord == NULL || (t[0] == texCoord[0] && t[1] == texCoord[1])) + { + return i; + } + } + v+=3; + if (t != NULL) + t += 2; + } + } + + Resize(mVertices, mMaxVertices, mNumVertices, mNumVertices + 3); + mVertices[mNumVertices++] = p[0]; + mVertices[mNumVertices++] = p[1]; + mVertices[mNumVertices++] = p[2]; + + if (texCoord != NULL) + { + Resize(mTexCoords, mMaxTexCoords, mNumTexCoords, mNumTexCoords + 2); + mTexCoords[mNumTexCoords++] = texCoord[0]; + mTexCoords[mNumTexCoords++] = texCoord[1]; + } + + return vcount; + } + + virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3, bool textured) + { + Resize(mIndices, mMaxIndices, mNumIndices, mNumIndices + 3); + + mIndices[mNumIndices++] = GetIndex(v1->mPos, textured ? v1->mTexel : NULL); + mIndices[mNumIndices++] = GetIndex(v2->mPos, textured ? v2->mTexel : NULL); + mIndices[mNumIndices++] = GetIndex(v3->mPos, textured ? v3->mTexel : NULL); + } + + + const float* GetVertices() const { return mVertices; } + unsigned GetNumVertices() const { return mNumVertices; } + + const float* GetTexCoords(void) const { return mTexCoords; } + unsigned GetNumTexCoords(void) const { return mNumTexCoords; } + + const int* GetIndices() const { return mIndices; } + unsigned GetNumIndices() const {return mNumIndices; } + + + private: + float* mVertices; + unsigned mMaxVertices; + unsigned mNumVertices; + + float* mTexCoords; + unsigned mMaxTexCoords; + unsigned mNumTexCoords; + + int* mIndices; + unsigned mMaxIndices; + unsigned mNumIndices; + }; + +}; + +using namespace WAVEFRONT; + +WavefrontObj::WavefrontObj(void) +{ + mVertexCount = 0; + mTriCount = 0; + mIndices = 0; + mVertices = NULL; + mTexCoords = NULL; +} + +WavefrontObj::~WavefrontObj(void) +{ + delete []mIndices; + delete []mVertices; + if (mTexCoords) + delete[] mTexCoords; +} + +unsigned int WavefrontObj::loadObj(const char *fname, bool textured) // load a wavefront obj returns number of triangles that were loaded. Data is persists until the class is destructed. +{ + unsigned int ret = 0; + delete []mVertices; + mVertices = 0; + delete []mIndices; + mIndices = 0; + mVertexCount = 0; + mTriCount = 0; + + BuildMesh bm; + OBJ obj; + obj.LoadMesh(fname, &bm, textured); + + if (bm.GetNumVertices()) + { + mVertexCount = bm.GetNumVertices()/3; + mVertices = new float[mVertexCount*3]; + memcpy(mVertices, bm.GetVertices(), sizeof(float)*mVertexCount*3); + + if (textured) + { + mTexCoords = new float[mVertexCount * 2]; + memcpy(mTexCoords, bm.GetTexCoords(), sizeof(float) * mVertexCount * 2); + } + + mTriCount = bm.GetNumIndices()/3; + mIndices = new int[mTriCount*3]; + memcpy(mIndices, bm.GetIndices(), sizeof(int)*mTriCount*3); + ret = mTriCount; + } + + return ret; +} + + + +bool LoadWavefrontBinary(const char* filename, WavefrontObj& wfo) +{ + SampleFramework::File* fp = NULL; + PxToolkit::fopen_s(&fp, filename, "rb"); + if(!fp) return false; + + size_t numRead = fread(&wfo.mVertexCount, 1, sizeof(int), fp); + if(numRead != sizeof(int)) { fclose(fp); return false; } + + wfo.mVertices = new float[wfo.mVertexCount*3]; + numRead = fread(wfo.mVertices, 1, sizeof(float)*wfo.mVertexCount*3, fp); + if(numRead != sizeof(float)*wfo.mVertexCount*3) { fclose(fp); return false; } + + numRead = fread(&wfo.mTriCount, 1, sizeof(int), fp); + if(numRead != sizeof(int)) { fclose(fp); return false; } + + wfo.mIndices = new int[wfo.mTriCount*3]; + numRead = fread(wfo.mIndices, 1, sizeof(int)*wfo.mTriCount*3, fp); + if(numRead != sizeof(int)*wfo.mTriCount*3) { fclose(fp); return false; } + + // NB: mTexCoords not supported + + fclose(fp); + return true; +} + +bool SaveWavefrontBinary(const char* filename, const WavefrontObj& wfo) +{ + SampleFramework::File* fp = NULL; + PxToolkit::fopen_s(&fp, filename, "wb"); + if(!fp) return false; + + fwrite(&wfo.mVertexCount, 1, sizeof(int), fp); + fwrite(wfo.mVertices, 1, wfo.mVertexCount*3*sizeof(float), fp); + + fwrite(&wfo.mTriCount, 1, sizeof(int), fp); + fwrite(wfo.mIndices, 1, wfo.mTriCount*3*sizeof(int), fp); + + // NB: mTexCoords not supported + + fclose(fp); + return true; +} |