7
/*----------------------------------------------------------------------
8
Copyright (c) 2004 Open Dynamics Framework Group
12
Redistribution and use in source and binary forms, with or without modification, are permitted provided
13
that the following conditions are met:
15
Redistributions of source code must retain the above copyright notice, this list of conditions
16
and the following disclaimer.
18
Redistributions in binary form must reproduce the above copyright notice,
19
this list of conditions and the following disclaimer in the documentation
20
and/or other materials provided with the distribution.
22
Neither the name of the Open Dynamics Framework Group nor the names of its contributors may
23
be used to endorse or promote products derived from this software without specific prior written permission.
25
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES,
26
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27
DISCLAIMED. IN NO EVENT SHALL THE INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
30
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
-----------------------------------------------------------------------*/
34
// http://codesuppository.blogspot.com
36
// mailto: jratcliff@infiniplex.net
38
// http://www.amillionpixels.us
40
#include "float_math.h"
42
#include "cd_wavefront.h"
45
using namespace ConvexDecomposition;
47
/*----------------------------------------------------------------------
48
Copyright (c) 2004 Open Dynamics Framework Group
52
Redistribution and use in source and binary forms, with or without modification, are permitted provided
53
that the following conditions are met:
55
Redistributions of source code must retain the above copyright notice, this list of conditions
56
and the following disclaimer.
58
Redistributions in binary form must reproduce the above copyright notice,
59
this list of conditions and the following disclaimer in the documentation
60
and/or other materials provided with the distribution.
62
Neither the name of the Open Dynamics Framework Group nor the names of its contributors may
63
be used to endorse or promote products derived from this software without specific prior written permission.
65
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES,
66
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
67
DISCLAIMED. IN NO EVENT SHALL THE INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
68
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
69
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
70
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
71
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72
-----------------------------------------------------------------------*/
76
namespace ConvexDecomposition
79
typedef std::vector< int > IntVector;
80
typedef std::vector< float > FloatVector;
82
#if defined(__APPLE__) || defined(__CELLOS_LV2__)
83
#define stricmp(a, b) strcasecmp((a), (b))
86
/*******************************************************************/
87
/******************** InParser.h ********************************/
88
/*******************************************************************/
89
class InPlaceParserInterface
92
virtual ~InPlaceParserInterface () {} ;
94
virtual int ParseLine(int lineno,int argc,const char **argv) =0; // return TRUE to continue parsing, return FALSE to abort parsing process
100
ST_HARD, // is a hard separator
101
ST_SOFT, // is a soft separator
102
ST_EOS // is a comment symbol, and everything past this character should be ignored
113
InPlaceParser(char *data,int len)
116
SetSourceData(data,len);
119
InPlaceParser(const char *fname)
125
~InPlaceParser(void);
133
for (int i=0; i<256; i++)
136
mHardString[i*2] = i;
137
mHardString[i*2+1] = 0;
146
void SetFile(const char *fname); // use this file as source data to parse.
148
void SetSourceData(char *data,int len)
155
int Parse(InPlaceParserInterface *callback); // returns true if entire file was parsed, false if it aborted for some reason
157
int ProcessLine(int lineno,char *line,InPlaceParserInterface *callback);
159
const char ** GetArglist(char *source,int &count); // convert source string into an arg list, this is a destructive parse.
161
void SetHardSeparator(char c) // add a hard separator
163
mHard[(int)c] = ST_HARD;
166
void SetHard(char c) // add a hard separator
168
mHard[(int)c] = ST_HARD;
172
void SetCommentSymbol(char c) // comment character, treated as 'end of string'
174
mHard[(int)c] = ST_EOS;
177
void ClearHardSeparator(char c)
179
mHard[(int)c] = ST_DATA;
183
void DefaultSymbols(void); // set up default symbols for hard seperator and comment symbol of the '#' character.
187
if ( mHard[(int)c] == ST_EOS )
194
void SetQuoteChar(char c)
202
inline char * AddHard(int &argc,const char **argv,char *foo);
203
inline bool IsHard(char c);
204
inline char * SkipSpaces(char *foo);
205
inline bool IsWhiteSpace(char c);
206
inline bool IsNonSeparator(char c); // non seperator,neither hard nor soft
208
bool mMyAlloc; // whether or not *I* allocated the buffer and am responsible for deleting it.
209
char *mData; // ascii data to parse.
210
int mLen; // length of data
211
SeparatorType mHard[256];
212
char mHardString[256*2];
216
/*******************************************************************/
217
/******************** InParser.cpp ********************************/
218
/*******************************************************************/
219
void InPlaceParser::SetFile(const char *fname)
230
FILE *fph = fopen(fname,"rb");
233
fseek(fph,0L,SEEK_END);
235
fseek(fph,0L,SEEK_SET);
238
mData = (char *) malloc(sizeof(char)*(mLen+1));
239
int ok = fread(mData, mLen, 1, fph);
247
mData[mLen] = 0; // zero byte terminate end of file marker.
255
InPlaceParser::~InPlaceParser(void)
265
bool InPlaceParser::IsHard(char c)
267
return mHard[(int)c] == ST_HARD;
270
char * InPlaceParser::AddHard(int &argc,const char **argv,char *foo)
272
while ( IsHard(*foo) )
274
const char *hard = &mHardString[*foo*2];
275
if ( argc < MAXARGS )
284
bool InPlaceParser::IsWhiteSpace(char c)
286
return mHard[(int)c] == ST_SOFT;
289
char * InPlaceParser::SkipSpaces(char *foo)
291
while ( !EOS(*foo) && IsWhiteSpace(*foo) ) foo++;
295
bool InPlaceParser::IsNonSeparator(char c)
297
if ( !IsHard(c) && !IsWhiteSpace(c) && c != 0 ) return true;
302
int InPlaceParser::ProcessLine(int lineno,char *line,InPlaceParserInterface *callback)
306
const char *argv[MAXARGS];
311
while ( !EOS(*foo) && argc < MAXARGS )
314
foo = SkipSpaces(foo); // skip any leading spaces
316
if ( EOS(*foo) ) break;
318
if ( *foo == mQuoteChar ) // if it is an open quote
321
if ( argc < MAXARGS )
325
while ( !EOS(*foo) && *foo != mQuoteChar ) foo++;
328
*foo = 0; // replace close quote with zero byte EOS
335
foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces
337
if ( IsNonSeparator(*foo) ) // add non-hard argument.
340
if ( *foo == mQuoteChar )
346
if ( argc < MAXARGS )
353
while (*foo && *foo != mQuoteChar ) foo++;
354
if ( *foo ) *foo = 32;
357
// continue..until we hit an eos ..
358
while ( !EOS(*foo) ) // until we hit EOS
360
if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit
366
else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument
368
const char *hard = &mHardString[*foo*2];
370
if ( argc < MAXARGS )
378
} // end of while loop...
385
ret = callback->ParseLine(lineno, argc, argv );
391
int InPlaceParser::Parse(InPlaceParserInterface *callback) // returns true if entire file was parsed, false if it aborted for some reason
394
if ( !mData ) return 0;
406
if ( *foo == 10 || *foo == 13 )
411
if ( *begin ) // if there is any data to parse at all...
413
int v = ProcessLine(lineno,begin,callback);
418
if ( *foo == 10 ) foo++; // skip line feed, if it is in the carraige-return line-feed format...
427
lineno++; // lasst line.
429
int v = ProcessLine(lineno,begin,callback);
435
void InPlaceParser::DefaultSymbols(void)
437
SetHardSeparator(',');
438
SetHardSeparator('(');
439
SetHardSeparator(')');
440
SetHardSeparator('=');
441
SetHardSeparator('[');
442
SetHardSeparator(']');
443
SetHardSeparator('{');
444
SetHardSeparator('}');
445
SetCommentSymbol('#');
449
const char ** InPlaceParser::GetArglist(char *line,int &count) // convert source string into an arg list, this is a destructive parse.
451
const char **ret = 0;
453
const char *argv[MAXARGS];
458
while ( !EOS(*foo) && argc < MAXARGS )
461
foo = SkipSpaces(foo); // skip any leading spaces
463
if ( EOS(*foo) ) break;
465
if ( *foo == mQuoteChar ) // if it is an open quote
468
if ( argc < MAXARGS )
472
while ( !EOS(*foo) && *foo != mQuoteChar ) foo++;
475
*foo = 0; // replace close quote with zero byte EOS
482
foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces
484
if ( IsNonSeparator(*foo) ) // add non-hard argument.
487
if ( *foo == mQuoteChar )
493
if ( argc < MAXARGS )
500
while (*foo && *foo != mQuoteChar ) foo++;
501
if ( *foo ) *foo = 32;
504
// continue..until we hit an eos ..
505
while ( !EOS(*foo) ) // until we hit EOS
507
if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit
513
else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument
515
const char *hard = &mHardString[*foo*2];
517
if ( argc < MAXARGS )
525
} // end of while loop...
539
/*******************************************************************/
540
/******************** Geometry.h ********************************/
541
/*******************************************************************/
552
class GeometryInterface
556
virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3) {}
558
virtual ~GeometryInterface () {}
562
/*******************************************************************/
563
/******************** Obj.h ********************************/
564
/*******************************************************************/
567
class OBJ : public InPlaceParserInterface
570
int LoadMesh(const char *fname,GeometryInterface *callback);
571
int ParseLine(int lineno,int argc,const char **argv); // return TRUE to continue parsing, return FALSE to abort parsing process
574
void getVertex(GeometryVertex &v,const char *face) const;
578
FloatVector mNormals;
580
GeometryInterface *mCallback;
584
/*******************************************************************/
585
/******************** Obj.cpp ********************************/
586
/*******************************************************************/
588
int OBJ::LoadMesh(const char *fname,GeometryInterface *iface)
598
InPlaceParser ipp(fname);
606
//static const char * GetArg(const char **argv,int i,int argc)
608
// const char * ret = 0;
609
// if ( i < argc ) ret = argv[i];
613
void OBJ::getVertex(GeometryVertex &v,const char *face) const
626
int index = atoi( face )-1;
628
const char *texel = strstr(face,"/");
632
int tindex = atoi( texel+1) - 1;
634
if ( tindex >=0 && tindex < (int)(mTexels.size()/2) )
636
const float *t = &mTexels[tindex*2];
643
const char *normal = strstr(texel+1,"/");
646
int nindex = atoi( normal+1 ) - 1;
648
if (nindex >= 0 && nindex < (int)(mNormals.size()/3) )
650
const float *n = &mNormals[nindex*3];
659
if ( index >= 0 && index < (int)(mVerts.size()/3) )
662
const float *p = &mVerts[index*3];
671
int OBJ::ParseLine(int lineno,int argc,const char **argv) // return TRUE to continue parsing, return FALSE to abort parsing process
677
const char *foo = argv[0];
680
if ( strcmp(argv[0],"v") == 0 && argc == 4 )
682
//if ( stricmp(argv[0],"v") == 0 && argc == 4 )
684
float vx = (float) atof( argv[1] );
685
float vy = (float) atof( argv[2] );
686
float vz = (float) atof( argv[3] );
687
mVerts.push_back(vx);
688
mVerts.push_back(vy);
689
mVerts.push_back(vz);
691
else if ( strcmp(argv[0],"vt") == 0 && argc == 3 )
693
// else if ( stricmp(argv[0],"vt") == 0 && argc == 3 )
695
float tx = (float) atof( argv[1] );
696
float ty = (float) atof( argv[2] );
697
mTexels.push_back(tx);
698
mTexels.push_back(ty);
700
// else if ( stricmp(argv[0],"vn") == 0 && argc == 4 )
702
else if ( strcmp(argv[0],"vn") == 0 && argc == 4 )
704
float normalx = (float) atof(argv[1]);
705
float normaly = (float) atof(argv[2]);
706
float normalz = (float) atof(argv[3]);
707
mNormals.push_back(normalx);
708
mNormals.push_back(normaly);
709
mNormals.push_back(normalz);
711
// else if ( stricmp(argv[0],"f") == 0 && argc >= 4 )
713
else if ( strcmp(argv[0],"f") == 0 && argc >= 4 )
715
GeometryVertex v[32];
719
for (int i=1; i<argc; i++)
721
getVertex(v[i-1],argv[i] );
724
// need to generate a normal!
725
#if 0 // not currently implemented
726
if ( mNormals.empty() )
728
Vector3d<float> p1( v[0].mPos );
729
Vector3d<float> p2( v[1].mPos );
730
Vector3d<float> p3( v[2].mPos );
733
n.ComputeNormal(p3,p2,p1);
735
for (int i=0; i<vcount; i++)
737
v[i].mNormal[0] = n.x;
738
v[i].mNormal[1] = n.y;
739
v[i].mNormal[2] = n.z;
745
mCallback->NodeTriangle(&v[0],&v[1],&v[2]);
747
if ( vcount >=3 ) // do the fan
749
for (int i=2; i<(vcount-1); i++)
751
mCallback->NodeTriangle(&v[0],&v[i],&v[i+1]);
765
class BuildMesh : public GeometryInterface
769
int getIndex(const float *p)
772
int vcount = mVertices.size()/3;
776
//New MS STL library checks indices in debug build, so zero causes an assert if it is empty.
777
const float *v = &mVertices[0];
779
for (int i=0; i<vcount; i++)
781
if ( v[0] == p[0] && v[1] == p[1] && v[2] == p[2] ) return i;
786
mVertices.push_back( p[0] );
787
mVertices.push_back( p[1] );
788
mVertices.push_back( p[2] );
793
virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3)
795
mIndices.push_back( getIndex(v1->mPos) );
796
mIndices.push_back( getIndex(v2->mPos) );
797
mIndices.push_back( getIndex(v3->mPos) );
800
const FloatVector& GetVertices(void) const { return mVertices; };
801
const IntVector& GetIndices(void) const { return mIndices; };
804
FloatVector mVertices;
809
WavefrontObj::WavefrontObj(void)
817
WavefrontObj::~WavefrontObj(void)
823
unsigned int WavefrontObj::loadObj(const char *fname) // load a wavefront obj returns number of triangles that were loaded. Data is persists until the class is destructed.
826
unsigned int ret = 0;
840
obj.LoadMesh(fname,&bm);
843
const FloatVector &vlist = bm.GetVertices();
844
const IntVector &indices = bm.GetIndices();
847
mVertexCount = vlist.size()/3;
848
mVertices = new float[mVertexCount*3];
849
memcpy( mVertices, &vlist[0], sizeof(float)*mVertexCount*3 );
850
mTriCount = indices.size()/3;
851
mIndices = new int[mTriCount*3*sizeof(int)];
852
memcpy(mIndices, &indices[0], sizeof(int)*mTriCount*3);