wmesh.cpp
1 /********************************************************************************
2  * WorldSim -- library for robot simulations *
3  * Copyright (C) 2008-2011 Gianluca Massera <emmegian@yahoo.it> *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the Free Software *
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
18  ********************************************************************************/
19 // Thanks to Brett Porter and Mete Ciragan for help with this MS3D model loading code
20 // Thanks to Ronny A. Reierstad and Vadim Tikhanoff
21 // www.morrowland.com
22 // apron@morrowland.com
23 
24 #include "wmesh.h"
25 
26 //----------------------------------
27 //--- MS3D STRUCTURES --------------
28 // PACK_STRUCT : byte-align structures
29 #ifdef _MSC_VER
30  #pragma pack( push, packing )
31  #pragma pack( 1 )
32  #define PACK_STRUCT
33  #ifndef PATH_MAX
34  #define PATH_MAX _MAX_PATH
35  #endif
36 #elif defined( __GNUC__ )
37  #define PACK_STRUCT __attribute__((packed))
38  #include <limits.h>
39 #else
40  #error you must byte-align these structures with the appropriate compiler directives
41 #endif
42 
43 namespace farsa {
44 
45 typedef unsigned char byte;
46 typedef unsigned short word;
47 // File Header
48 struct MS3DHeader {
49  char m_ID[10];
50  int m_version;
51 } PACK_STRUCT;
52 // Vertex info
53 struct MS3DVertex {
54  byte m_flags;
55  float m_vertex[3];
56  char m_boneID;
57  byte m_refCount;
58 } PACK_STRUCT;
59 // Triangle info
60 struct MS3DTriangle {
61  word m_flags;
62  word m_vertexIndices[3];
63  float m_vertexNormals[3][3];
64  float m_s[3], m_t[3];
65  byte m_smoothingGroup;
66  byte m_groupIndex;
67 } PACK_STRUCT;
68 // Material info
69 struct MS3DMaterial {
70  static unsigned int Texture[15];
71  char m_name[32];
72  float m_ambient[4];
73  float m_diffuse[4];
74  float m_specular[4];
75  float m_emissive[4];
76  float m_shininess; // 0.0f - 128.0f
77  float m_transparency; // 0.0f - 1.0f
78  byte m_mode; // 0, 1, 2 (unused now)
79  char m_texture[128];
80  char m_alphamap[128];
81 } PACK_STRUCT;
82 // back to Default alignment
83 #ifdef _MSC_VER
84  #pragma pack( pop, packing )
85 #endif
86 #undef PACK_STRUCT
87 //--- MS3D STRUCTURES ENDS ---------
88 //----------------------------------
89 
90 } // end namespace farsa
91 
92 #include "string.h"
93 #include <QString>
94 #include <QFile>
95 #include <QImage>
96 
97 namespace farsa {
98 
99 WMesh::WMesh( World* world, QString name, const wMatrix& tm)
100  : WObject( world, name, tm, false ) {
101  m_numMeshes = 0;
102  m_pMeshes = NULL;
103  m_numMaterials = 0;
104  m_pMaterials = NULL;
105  m_numTriangles = 0;
106  m_pTriangles = NULL;
107  m_numVertices = 0;
108  m_pVertices = NULL;
109  attacho = NULL;
110  world->pushObject( this );
111 }
112 
114  int i;
115  for ( i = 0; i < m_numMeshes; i++ ) {
116  delete[] m_pMeshes[i].m_pTriangleIndices;
117  }
118  m_numMeshes = 0;
119  if ( m_pMeshes != NULL ) {
120  delete[] m_pMeshes;
121  m_pMeshes = NULL;
122  }
123  m_numMaterials = 0;
124  if ( m_pMaterials != NULL ) {
125  delete[] m_pMaterials;
126  m_pMaterials = NULL;
127  }
128  m_numTriangles = 0;
129  if ( m_pTriangles != NULL ) {
130  delete[] m_pTriangles;
131  m_pTriangles = NULL;
132  }
133  m_numVertices = 0;
134  if ( m_pVertices != NULL ) {
135  delete[] m_pVertices;
136  m_pVertices = NULL;
137  }
138 }
139 
140 void WMesh::attachTo( WObject* obj ) {
141  this->attacho = obj;
142 }
143 
144 bool WMesh::loadMS3DModel( QString filename ) {
145  QFile inputFile( filename );
146  if ( !inputFile.open( QIODevice::ReadOnly ) ) {
147  return false;
148  }
149  QByteArray bBuffer = inputFile.readAll();
150  const char *pPtr = bBuffer.data();
151  MS3DHeader *pHeader = ( MS3DHeader* )pPtr;
152  pPtr += sizeof( MS3DHeader );
153  if ( strncmp( pHeader->m_ID, "MS3D000000", 10 ) != 0 ) {
154  // "Not a valid Milkshape3D model file."
155  return false;
156  }
157  if ( pHeader->m_version < 3 ) {
158  // "Unhandled file version. Only Milkshape3D Version 1.3 and 1.4 is supported."
159  return false;
160  }
161  int nVertices = *( word* )pPtr;
162  m_numVertices = nVertices;
163  m_pVertices = new Vertex[nVertices];
164  pPtr += sizeof( word );
165  int i;
166  for ( i = 0; i < nVertices; i++ ) {
167  MS3DVertex *pVertex = ( MS3DVertex* )pPtr;
168  m_pVertices[i].m_boneID = pVertex->m_boneID;
169  memcpy( m_pVertices[i].m_location, pVertex->m_vertex, sizeof( float )*3 );
170  pPtr += sizeof( MS3DVertex );
171  }
172  int nTriangles = *( word* )pPtr;
173  m_numTriangles = nTriangles;
174  m_pTriangles = new Triangle[nTriangles];
175  pPtr += sizeof( word );
176  for ( i = 0; i < nTriangles; i++ ) {
177  MS3DTriangle *pTriangle = ( MS3DTriangle* )pPtr;
178  int vertexIndices[3] = { pTriangle->m_vertexIndices[0], pTriangle->m_vertexIndices[1], pTriangle->m_vertexIndices[2] };
179  float t[3] = { 1.0f-pTriangle->m_t[0], 1.0f-pTriangle->m_t[1], 1.0f-pTriangle->m_t[2] };
180  memcpy( m_pTriangles[i].m_vertexNormals, pTriangle->m_vertexNormals, sizeof( float )*3*3 );
181  memcpy( m_pTriangles[i].m_s, pTriangle->m_s, sizeof( float )*3 );
182  memcpy( m_pTriangles[i].m_t, t, sizeof( float )*3 );
183  memcpy( m_pTriangles[i].m_vertexIndices, vertexIndices, sizeof( int )*3 );
184  pPtr += sizeof( MS3DTriangle );
185  }
186  int nGroups = *( word* )pPtr;
187  m_numMeshes = nGroups;
188  m_pMeshes = new Mesh[nGroups];
189  pPtr += sizeof( word );
190  for ( i = 0; i < nGroups; i++ ) {
191  pPtr += sizeof( byte ); // flags
192  pPtr += 32; // name
193  word nTriangles = *( word* )pPtr;
194  pPtr += sizeof( word );
195  int *pTriangleIndices = new int[nTriangles];
196  for ( int j = 0; j < nTriangles; j++ ) {
197  pTriangleIndices[j] = *( word* )pPtr;
198  pPtr += sizeof( word );
199  }
200  char materialIndex = *( char* )pPtr;
201  pPtr += sizeof( char );
202  m_pMeshes[i].m_materialIndex = materialIndex;
203  m_pMeshes[i].m_numTriangles = nTriangles;
204  m_pMeshes[i].m_pTriangleIndices = pTriangleIndices;
205  }
206  int nMaterials = *( word* )pPtr;
207  m_numMaterials = nMaterials;
208  m_pMaterials = new Material[nMaterials];
209  pPtr += sizeof( word );
210  for ( i = 0; i < nMaterials; i++ ) {
211  MS3DMaterial *pMaterial = ( MS3DMaterial* )pPtr;
212  memcpy( m_pMaterials[i].m_ambient, pMaterial->m_ambient, sizeof( float )*4 );
213  memcpy( m_pMaterials[i].m_diffuse, pMaterial->m_diffuse, sizeof( float )*4 );
214  memcpy( m_pMaterials[i].m_specular, pMaterial->m_specular, sizeof( float )*4 );
215  memcpy( m_pMaterials[i].m_emissive, pMaterial->m_emissive, sizeof( float )*4 );
216  m_pMaterials[i].m_shininess = pMaterial->m_shininess;
217  m_pMaterials[i].m_pTextureFilename = QString( pMaterial->m_texture );
218  pPtr += sizeof( MS3DMaterial );
219  }
220  return true;
221 }
222 
223 } // end namespace farsa