mElite  1.0
An Elite clone based on TextElite by Jan-Philipp Kappmeier and Melanie Schmidt.
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
ObjectLoader3ds.cpp
Go to the documentation of this file.
1 
8 #include<stdio.h>
9 #include<math.h>
10 #include<string.h>
11 #include"ObjectLoader3ds.h"
12 #include"3ds_chunks.h"
13 
14 ObjectLoader3ds::ObjectLoader3ds() : totalMeshes(0), totalMaterials(0) {
15  totalMeshes = 0;
16 }
17 
19  shutdown();
20 }
21 
22 bool ObjectLoader3ds::LoadModel(const char *fileName) {
23  FILE *fp = NULL;
24  stChunk primaryChunk;
25 
26  if(!fileName) return false;
27 
28  fopen_s(&fp, fileName, "rb");
29  if(!fp) return false;
30 
31  // The first chunk in the file is called the primary chunk.
32  ReadChunk(fp, &primaryChunk);
33 
34  // This test will tell us if this is a 3DS file.
35  if(primaryChunk.id != PRIMARY_ID) return false;
36 
37  // Recursively read the model file.
38  ReadSubChunk(fp, &primaryChunk);
39  fclose(fp);
40 
41  stVertex v1, v2;
42  stVertex n;
43 
44  // This is used to create triangle normals.If you want your
45  // 3DS loader to support bump mapping, adding s and t tangents
46  // below will do that for you.
47  for(int i = 0; i < totalMeshes; i++)
48  {
49  for(unsigned int f = 0; f < meshList[i].totalFaces; f++)
50  {
51  stMesh *pMesh = &meshList[i];
52  stFace *pFace = pMesh->pFaces;
53 
54  if(!pMesh || !pFace) continue;
55 
56  v1.x = pMesh->pVertices[pFace[f].indices[0]].x - pMesh->pVertices[pFace[f].indices[1]].x;
57  v1.y = pMesh->pVertices[pFace[f].indices[0]].y - pMesh->pVertices[pFace[f].indices[1]].y;
58  v1.z = pMesh->pVertices[pFace[f].indices[0]].z - pMesh->pVertices[pFace[f].indices[1]].z;
59 
60  v2.x = pMesh->pVertices[pFace[f].indices[1]].x - pMesh->pVertices[pFace[f].indices[2]].x;
61  v2.y = pMesh->pVertices[pFace[f].indices[1]].y - pMesh->pVertices[pFace[f].indices[2]].y;
62  v2.z = pMesh->pVertices[pFace[f].indices[1]].z - pMesh->pVertices[pFace[f].indices[2]].z;
63 
64  n.x = ((v1.y * v2.z) - (v1.z * v2.y));
65  n.y = ((v1.z * v2.x) - (v1.x * v2.z));
66  n.z = ((v1.x * v2.y) - (v1.y * v2.x));
67 
68  float len = 1 / (float)sqrt((n.x * n.x + n.y * n.y + n.z * n.z));
69  n.x *= len; n.y *= len; n.z *= len;
70 
71  pFace[f].normal.x = n.x;
72  pFace[f].normal.y = n.y;
73  pFace[f].normal.z = n.z;
74  }
75  }
76  return true;
77 }
78 
79 
80 void ObjectLoader3ds::ReadSubChunk(FILE *fp, stChunk *pChunk)
81 {
82  stMesh mesh;
83  stMesh *pMesh = NULL;
84  stMaterial *pMat = NULL;
85  stMaterial mat;
86  char name[256];
87 
88  // Keep reading until we have finished reading this chunk.
89  while(pChunk->bytesRead < pChunk->length)
90  {
91  // Read the next chunk.
92  stChunk chunk;
93  ReadChunk(fp, &chunk);
94 
95  // Depending on the chunk will depend on what
96  // is being loaded.
97  switch(chunk.id)
98  {
99  case EDIT3DS:
100  // Read the next chunk to get the actual data.
101  // sobald er das erste mal hier ist, ist das laden fertig. (für ball.3ds)
102  ReadSubChunk(fp, &chunk);
103  break;
104 
105  case NAMED_OBJECT:
106  // Add a new mesh object to the list.
107  meshList.push_back(mesh);
108  totalMeshes++;
109 
110  // Load mesh data.
111  chunk.bytesRead += GetNextString(fp, name);
112  pMesh = &(meshList[totalMeshes - 1]);
113  strcpy_s(pMesh->name, name);
114 
115  // bis hierher fehlerfrei
116  ReadSubChunk(fp, &chunk);
117  break;
118 
119  case OBJ_MESH:
120  // Read the next chunk to get the actual data.
121  // bis hierher ok
122  ReadSubChunk(fp, &chunk);
123  break;
124 
125  case MAT_ENTRY:
126  // Add a new material to the list then read it.
127  materialList.push_back(mat);
128  totalMaterials++;
129 
130  ReadSubChunk(fp, &chunk);
131  break;
132 
133  case MAT_NAME:
134  // Read materials name and save it.
135  chunk.bytesRead += GetNextString(fp, name);
136  pMat = &(materialList[totalMaterials - 1]);
137  strcpy_s(pMat->name, name);
138  break;
139 
140  case MAT_TEXFLNM:
141  // Read texture filename and save it.
142  chunk.bytesRead += GetNextString(fp, name);
143  pMat = &(materialList[totalMaterials - 1]);
144  strcpy_s(pMat->textureName, name);
145  break;
146 
147  case MAT_DIFFUSE:
148  // Read diffuse colors.
149  ReadDiffuse(fp, &chunk);
150  break;
151 
152  case MAT_AMBIENT:
153  // Read diffuse colors.
154  ReadAmbient(fp, &chunk);
155  break;
156 
157  case MAT_SPECULAR:
158  // Read diffuse colors.
159  ReadSpecular(fp, &chunk);
160  break;
161 
162  case MAT_TEXMAP:
163  // Read the next chunk to get the actual data.
164  // bis hier ist alles in ordnung, texturteil scheint auch ok zu sein
165  ReadSubChunk(fp, &chunk);
166  break;
167 
168  case MESH_FACES:
169  // Read triangles.
170  ReadFaces(fp, &chunk);
171  break;
172 
173  case MESH_VERTICES:
174  // Read vertex points.
175  // bis hierher alles korrekt
176  ReadVertices(fp, &chunk);
177  break;
178 
179  case MESH_TEX_VERT:
180  // Read texture coords.
181  ReadTexCoords(fp, &chunk);
182  break;
183 
184  case MESH_MATER:
185  // Read material indices.
186  ReadMeshMaterials(fp, &chunk);
187  break;
188 
189  default:
190  // Skip chunk cuz we don't support
191  // whatever is here.
192  MoveToNextChunk(fp, &chunk);
193  break;
194  }
195 
196  // Add to the total bytes loaded.
197  pChunk->bytesRead += chunk.length;
198  }
199 }
200 
201 
203 {
204  int buff[50000];
205  // Skip a chunks data.
206  fread(buff, 1, pChunk->length - pChunk->bytesRead, fp);
207 }
208 
209 
210 size_t ObjectLoader3ds::GetNextString(FILE *fp, char *str)
211 {
212  char buff[100] = { 0 };
213  int index = 0;
214 
215  // Read an entire string.
216  fread(buff, 1, 1, fp);
217  while(*(buff + index) != 0)
218  {
219  index++;
220  fread(buff + index, 1, 1, fp);
221  }
222 
223  // Save the string and return the size of the string.
224  strcpy(str, buff);
225  return strlen(buff) + 1;
226 }
227 
228 
229 void ObjectLoader3ds::ReadChunk(FILE *fp, stChunk *pChunk)
230 {
231  if(!pChunk) return;
232 
233  // Read chunk header.
234  pChunk->bytesRead = fread(&pChunk->id, 1, 2, fp); // lies 2 bytes = 16 bit = unsigned short
235  pChunk->bytesRead += fread(&pChunk->length, 1, 4, fp); // lies 4 bytes = 32 bit = unsigned int
236 }
237 
238 
239 // warning! in this function it's not checked if the color is _not_ 24 bit rgb-format! the 3ds format
240 // also allows float? colors.
241 // sometimes (normally?) two color values are saved: COLOR_24 and LIN_COLOR_24. sometimes (often?) the two
242 // colors are the same, but not always. in this case the second one is read. it was useful for the tie model ;)
243 void ObjectLoader3ds::ReadDiffuse(FILE *fp, stChunk *pChunk) {
244  stColor color;
245  unsigned char header[6];
246 
247  // Read a color value.
248  pChunk->bytesRead += fread(header, 1, 6, fp); // read header, it's ignored now
249  pChunk->bytesRead += fread(&color, 1, 3, fp); // read colorbytes
250 
251  // Save this color.
252  stMaterial *mat = &(materialList[totalMaterials - 1]);
253  mat->colorDiffuse.r = color.r;
254  mat->colorDiffuse.g = color.g;
255  mat->colorDiffuse.b = color.b;
256 
257  if(pChunk->length ==24) {
258  // if the space in this chunk is 24 read again. it has to be LIN_COLOR_24 as second color information
259  pChunk->bytesRead += fread(header, 1, 6, fp); // read header
260  pChunk->bytesRead += fread(&color, 1, 3, fp); // read colorbytes
261 
262  // Save this color.
263  stMaterial *mat = &(materialList[totalMaterials - 1]);
264  mat->colorDiffuse.r = color.r;
265  mat->colorDiffuse.g = color.g;
266  mat->colorDiffuse.b = color.b;
267  }
268 
269  // Skip the rest of the chunk, if there's any
270  MoveToNextChunk(fp, pChunk);
271 }
272 
273 // warning! in this function it's not checked if the color is _not_ 24 bit rgb-format! the 3ds format
274 // also allows float? colors.
275 // sometimes (normally?) two color values are saved: COLOR_24 and LIN_COLOR_24. sometimes (often?) the two
276 // colors are the same, but not always. in this case the second one is read. it was useful for the tie model ;)
277 void ObjectLoader3ds::ReadAmbient(FILE *fp, stChunk *pChunk) {
278  stColor color;
279  unsigned char header[6];
280 
281  // Read a color value.
282  pChunk->bytesRead += fread(header, 1, 6, fp); // read header, it's ignored now
283  pChunk->bytesRead += fread(&color, 1, 3, fp); // read colorbytes
284 
285  // Save this color.
286  stMaterial *mat = &(materialList[totalMaterials - 1]);
287  mat->colorAmbient.r = color.r;
288  mat->colorAmbient.g = color.g;
289  mat->colorAmbient.b = color.b;
290 
291  if(pChunk->length ==24) {
292  // if the space in this chunk is 24 read again. it has to be LIN_COLOR_24 as second color information
293  pChunk->bytesRead += fread(header, 1, 6, fp); // read header
294  pChunk->bytesRead += fread(&color, 1, 3, fp); // read colorbytes
295 
296  // Save this color.
297  stMaterial *mat = &(materialList[totalMaterials - 1]);
298  mat->colorAmbient.r = color.r;
299  mat->colorAmbient.g = color.g;
300  mat->colorAmbient.b = color.b;
301  }
302 
303  // Skip the rest of the chunk.
304  MoveToNextChunk(fp, pChunk);
305 }
306 
307 // warning! in this function it's not checked if the color is _not_ 24 bit rgb-format! the 3ds format
308 // also allows float? colors.
309 // sometimes (normally?) two color values are saved: COLOR_24 and LIN_COLOR_24. sometimes (often?) the two
310 // colors are the same, but not always. in this case the second one is read. it was useful for the tie model ;)
311 void ObjectLoader3ds::ReadSpecular(FILE *fp, stChunk *pChunk) {
312  stColor color;
313  unsigned char header[6];
314 
315  // Read a color value.
316  pChunk->bytesRead += fread(header, 1, 6, fp); // read header, it's ignored now
317  pChunk->bytesRead += fread(&color, 1, 3, fp); // read colorbytes
318 
319  // Save this color.
320  stMaterial *mat = &(materialList[totalMaterials - 1]);
321  mat->colorSpecular.r = color.r;
322  mat->colorSpecular.g = color.g;
323  mat->colorSpecular.b = color.b;
324 
325  if(pChunk->length ==24) {
326  // if the space in this chunk is 24 read again. it has to be LIN_COLOR_24 as second color information
327  pChunk->bytesRead += fread(header, 1, 6, fp); // read header
328  pChunk->bytesRead += fread(&color, 1, 3, fp); // read colorbytes
329 
330  // Save this color.
331  stMaterial *mat = &(materialList[totalMaterials - 1]);
332  mat->colorSpecular.r = color.r;
333  mat->colorSpecular.g = color.g;
334  mat->colorSpecular.b = color.b;
335  }
336 
337  // Skip the rest of the chunk.
338  MoveToNextChunk(fp, pChunk);
339 }
340 
341 
343 {
344  char name[256];
345  int matId = 0;
346  unsigned short totalMatIndices = 0;
347  unsigned short *pMatIndices = NULL;
348 
349  // Read material name and total.
350  pChunk->bytesRead += GetNextString(fp, name);
351  pChunk->bytesRead += fread(&totalMatIndices, 1, 2, fp);
352 
353  // Allocate the material indices.
354  pMatIndices = new unsigned short[totalMatIndices];
355 
356  // Read indices.
357  pChunk->bytesRead += fread(pMatIndices, 1, totalMatIndices *
358  sizeof(unsigned short), fp);
359 
360  // Look if this material already exist in the list.
361  for(int i = 0; i < totalMaterials; i++)
362  {
363  if(strcmp(name, materialList[i].name) == 0)
364  matId = i;
365  }
366 
367  // Get the current mesh.
368  stMesh *pMesh = &(meshList[totalMeshes - 1]);
369 
370  // Add the material id to all faces that uses it.
371  for(int i = 0; i < totalMatIndices; i++)
372  pMesh->pFaces[pMatIndices[i]].matId = matId;
373 }
374 
375 
376 void ObjectLoader3ds::ReadFaces(FILE *fp, stChunk *pChunk)
377 {
378  unsigned int totalFaces = 0;
379  // totalVertices is an integer, 4 bytes have to be loaded. therefore initialized to 0
380  stFileFace *pFaces;
381 
382  // Read number of faces.
383  pChunk->bytesRead += fread(&totalFaces, 1, 2, fp);
384 
385  // Read faces.
386  pFaces = new stFileFace[totalFaces];
387  pChunk->bytesRead += fread(pFaces, 1, totalFaces *
388  sizeof(stFileFace), fp);
389 
390  // Get current mesh and a pointer to its faces.
391  stMesh *pMesh = &(meshList[totalMeshes - 1]);
392  pMesh->pFaces = new stFace[totalFaces];
393  pMesh->totalFaces = totalFaces;
394 
395  // Loop through and copy the face data.
396  for(unsigned int i = 0; i < totalFaces; i++)
397  {
398  pMesh->pFaces[i].indices[0] = pFaces[i].indices[0];
399  pMesh->pFaces[i].indices[1] = pFaces[i].indices[1];
400  pMesh->pFaces[i].indices[2] = pFaces[i].indices[2];
401  }
402 
403  // Delete temp memory.
404  delete[] pFaces;
405 
406  // Read the next chunk.
407  ReadSubChunk(fp, pChunk);
408 }
409 
418 void ObjectLoader3ds::ReadVertices(FILE *fp, stChunk *pChunk)
419 {
420  unsigned int totalVertices = 0;
421  // totalVertices is an integer, 4 bytes have to be loaded. therefore initialized with 0
422  stVertex *pVertices;
423 
424  // Read number of vertices.
425 
426  pChunk->bytesRead += fread(&totalVertices, 1, 2, fp);
427 
428  // Load vertex points.
429  pVertices = new stVertex[totalVertices];
430  pChunk->bytesRead += fread(pVertices, 1, totalVertices *
431  sizeof(stVertex), fp);
432 
433  // Get the current mesh and save the data to it.
434  stMesh *pMesh = &(meshList[totalMeshes - 1]);
435  pMesh->pVertices = pVertices;
436  pMesh->totalVertices = totalVertices;
437 
438  // Skip any data left in this chunk.
439  MoveToNextChunk(fp, pChunk);
440 }
441 
450 {
451  unsigned int totalTexCoords = 0;
452  // totalTexCoords is an integer, 4 bytes have to be loaded. therefore initialized to 0
453  stTexCoord *pTexCoords;
454 
455  // read total.
456  pChunk->bytesRead += fread(&totalTexCoords, 1, 2, fp);
457 
458  // read all the tex coords.
459  pTexCoords = new stTexCoord[totalTexCoords];
460  pChunk->bytesRead += fread(pTexCoords, 1, totalTexCoords *
461  sizeof(stTexCoord), fp);
462 
463  // get the current mesh and save the data to it.
464  stMesh *pMesh = &(meshList[totalMeshes - 1]);
465  pMesh->pTexCoords = pTexCoords;
466 
467  // skip anything that is left.
468  MoveToNextChunk(fp, pChunk);
469 }
470 
476  // Loop through and make sure all data is released.
477  for(int i = 0; i < totalMeshes; i++)
478  {
479  if(meshList[i].pFaces)
480  {
481  delete[] meshList[i].pFaces;
482  meshList[i].pFaces = NULL;
483  }
484 
485  if(meshList[i].pVertices)
486  {
487  delete[] meshList[i].pVertices;
488  meshList[i].pVertices = NULL;
489  }
490 
491  if(meshList[i].pTexCoords)
492  {
493  delete[] meshList[i].pTexCoords;
494  meshList[i].pTexCoords = NULL;
495  }
496 
497  meshList[i].totalFaces = 0;
498  meshList[i].totalVertices = 0;
499  meshList[i].totalTexCoords = 0;
500  }
501 
502  meshList.erase( meshList.begin(), meshList.end());
503 
504  materialList.erase( materialList.begin(), materialList.end());
505 
506  totalMeshes = 0;
507  totalMaterials = 0;
508 }