Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
l3ds.cpp
Go to the documentation of this file.
1 // copyright (c) 2001 Lev Povalahev
2 
3 
4 #include "stdafx.h"
5 
6 #include "l3ds.h"
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <math.h>
12 
13 //using namespace std;
14 
15 //-------------------------------------------------------
16 // generic stuff
17 //-------------------------------------------------------
18 
19 typedef unsigned long ulong;
20 
21 #define SEEK_START 1900
22 #define SEEK_CURSOR 1901
23 
24 // common chunks
25 // colors
26 #define COLOR_F 0x0010
27 #define COLOR_24 0x0011
28 #define LIN_COLOR_24 0x0012
29 #define LIN_COLOR_F 0x0013
30 // percentage
31 #define INT_PERCENTAGE 0x0030
32 #define FLOAT_PERCENTAGE 0x0031
33 // ambient light
34 #define AMBIENT_LIGHT 0x2100
35 
36 
37 #define MAIN3DS 0x4D4D
38 #define EDIT3DS 0x3D3D // this is the start of the editor config
39 
40 // keyframer chunk ids
41 #define KFDATA 0xB000 // the keyframer section
42 #define KFHDR 0xB00A
43 #define OBJECT_NODE_TAG 0xB002
44 #define NODE_HDR 0xB010
45 #define PIVOT 0xB013
46 #define POS_TRACK_TAG 0xB020
47 #define ROT_TRACK_TAG 0xB021
48 #define SCL_TRACK_TAG 0xB022
49 
50 // material entries
51 #define MAT_ENTRY 0xAFFF
52 #define MAT_NAME 0xA000
53 #define MAT_AMBIENT 0xA010
54 #define MAT_DIFFUSE 0xA020
55 #define MAT_SPECULAR 0xA030
56 #define MAT_SHININESS 0xA040
57 #define MAT_SHIN2PCT 0xA041
58 #define MAT_TRANSPARENCY 0xA050
59 #define MAT_SHADING 0xA100
60 #define MAT_TWO_SIDE 0xA081
61 #define MAT_ADDITIVE 0xA083
62 #define MAT_WIRE 0xA085
63 #define MAT_FACEMAP 0xA088
64 #define MAT_WIRESIZE 0xA087
65 #define MAT_DECAL 0xA082
66 #define MAT_TEXMAP 0xA200
67 #define MAT_MAPNAME 0xA300
68 #define MAT_MAP_TILING 0xA351
69 #define MAT_MAP_USCALE 0xA354
70 #define MAT_MAP_VSCALE 0xA356
71 #define MAT_MAP_UOFFSET 0xA358
72 #define MAT_MAP_VOFFSET 0xA35A
73 #define MAT_MAP_ANG 0xA35C
74 #define MAT_TEX2MAP 0xA33A
75 #define MAT_OPACMAP 0xA210
76 #define MAT_BUMPMAP 0xA230
77 #define MAT_SPECMAP 0xA204
78 #define MAT_SHINMAP 0xA33C
79 #define MAT_REFLMAP 0xA220
80 #define MAT_ACUBIC 0xA310
81 
82 #define EDIT_OBJECT 0x4000
83 #define OBJ_TRIMESH 0x4100
84 #define OBJ_LIGHT 0x4600
85 #define OBJ_CAMERA 0x4700
86 #define LIT_OFF 0x4620
87 #define LIT_SPOT 0x4610
88 #define TRI_VERTEXLIST 0x4110
89 #define TRI_VERTEXOPTIONS 0x4111
90 
91 #define TRI_FACELIST 0x4120
92  #define TRI_MAT_GROUP 0x4130
93  #define TRI_SMOOTH_GROUP 0x4150
94 
95 #define TRI_FACEMAPPING 0x4140
96 #define TRI_MATRIX 0x4160
97 
98 #define SPOTLIGHT 0x4610
99 
100 //----------------------------------
101 
102 #define MAX_SHARED_TRIS 100
103 
104 // the error reporting routine
105 
106 void ErrorMsg(const char *msg)
107 {
108 
109 }
110 
111 struct LChunk
112 {
113  unsigned short id;
116 };
117 
118 struct LTri
119 {
120  unsigned short a;
121  unsigned short b;
122  unsigned short c;
128 };
129 
130 // globals
131 
132 LColor3 black = {0, 0, 0};
133 
134 LVector3 zero3 = {0, 0, 0};
135 
136 LVector4 zero4 = {0, 0, 0, 0};
137 
138 LMap emptyMap = {0, "", 1, 1, 0, 0, 0};
139 
141 {
142  LVector3 t;
143  t.x = vec.x;
144  t.y = vec.y;
145  t.z = vec.z;
146  return t;
147 }
148 
150 {
151  LVector3 t;
152  t.x = a.x+b.x;
153  t.y = a.y+b.y;
154  t.z = a.z+b.z;
155  return t;
156 }
157 
159 {
160  LVector3 t;
161  t.x = a.x-b.x;
162  t.y = a.y-b.y;
163  t.z = a.z-b.z;
164  return t;
165 }
166 
167 float VectorLength(const LVector3 &vec)
168 {
169  return (float)sqrt(vec.x*vec.x + vec.y*vec.y+vec.z*vec.z);
170 }
171 
173 {
174  float a = VectorLength(vec);
175  if (a == 0)
176  return vec;
177  float b = 1/a;
178  LVector3 v;
179  v.x = vec.x*b;
180  v.y = vec.y*b;
181  v.z = vec.z*b;
182  return v;
183 }
184 
186 {
187  LVector3 v;
188  v.x = a.y*b.z - a.z*b.y;
189  v.y = a.z*b.x - a.x*b.z;
190  v.z = a.x*b.y - a.y*b.x;
191  return v;
192 }
193 
195 {
196  for (int i = 0; i < 4; i++)
197  for (int j = 0; j < 4; j++)
198  m.m[i][j] = (i==j) ? 1.0f : 0.0f;
199 }
200 
202 {
203  LVector4 res;
204 
205  res.x = m.m[0][0]*vec.x + m.m[1][0]*vec.y + m.m[2][0]*vec.z + m.m[3][0]*vec.w;
206  res.y = m.m[0][1]*vec.x + m.m[1][1]*vec.y + m.m[2][1]*vec.z + m.m[3][1]*vec.w;
207  res.z = m.m[0][2]*vec.x + m.m[1][2]*vec.y + m.m[2][2]*vec.z + m.m[3][2]*vec.w;
208  res.w = m.m[0][3]*vec.x + m.m[1][3]*vec.y + m.m[2][3]*vec.z + m.m[3][3]*vec.w;
209 
210  if (res.w != 0) {
211  float b = 1/res.w;
212  res.x *= b;
213  res.y *= b;
214  res.z *= b;
215  res.w = 1;
216  }
217  else {
218  res.w = 1;
219  }
220 
221  return res;
222 }
223 
224 void QuatToMatrix(const LVector4 &quat, LMatrix4 &m)
225 {
226 
227 }
228 
229 //-------------------------------------------------------
230 // LObject implementation
231 //-------------------------------------------------------
232 
234 {
235  m_name = "";//.clear();
236 }
237 
239 {
240  // nothing here
241 }
242 
243 void LObject::SetName(const std::string& value)
244 {
245  m_name = value;
246 }
247 
248 const std::string& LObject::GetName()
249 {
250  return m_name;
251 }
252 
253 bool LObject::IsObject(const std::string &name)
254 {
255  return (m_name == name);
256 }
257 
258 
259 //-------------------------------------------------------
260 // LMaterial implementation
261 //-------------------------------------------------------
262 
264 : LObject()
265 {
266  m_id = 0;
273  m_ambient = black;
274  m_diffuse = black;
275  m_specular = black;
277  m_shininess = 0;
278  m_transparency = 0;
279 }
280 
282 {
283 
284 }
285 
287 {
288  return m_id;
289 }
290 
292 {
293  return m_texMap1;
294 }
295 
297 {
298  return m_texMap2;
299 }
300 
302 {
303  return m_opacMap;
304 }
305 
307 {
308  return m_specMap;
309 }
310 
312 {
313  return m_bumpMap;
314 }
315 
317 {
318  return m_reflMap;
319 }
320 
322 {
323  return m_ambient;
324 }
325 
327 {
328  return m_diffuse;
329 }
330 
332 {
333  return m_specular;
334 }
335 
337 {
338  return m_shininess;
339 }
340 
342 {
343  return m_transparency;
344 }
345 
347 {
348  return m_shading;
349 }
350 
352 {
353  m_id = value;
354 }
355 
357 {
358  m_ambient = color;
359 }
360 
362 {
363  m_diffuse = color;
364 }
365 
367 {
368  m_specular = color;
369 }
370 
371 void LMaterial::SetShininess(float value)
372 {
373  m_shininess = value;
374  if (m_shininess < 0)
375  m_shininess = 0;
376  if (m_shininess > 1)
377  m_shininess = 1;
378 }
379 
380 void LMaterial::SetTransparency(float value)
381 {
382  m_transparency = value;
383  if (m_transparency < 0)
384  m_transparency = 0;
385  if (m_transparency > 1)
386  m_transparency = 1;
387 }
388 
390 {
391  m_shading = shading;
392 }
393 
394 //-------------------------------------------------------
395 // LMesh implementation
396 //-------------------------------------------------------
397 
399 : LObject()
400 {
401  Clear();
402 }
403 
405 {
406  Clear();
407 }
408 
410 {
411  m_vertices.clear();
412  m_normals.clear();
413  m_uv.clear();
414  m_tangents.clear();
415  m_binormals.clear();
416  m_triangles.clear();
417  m_tris.clear();
418  m_materials.clear();
420 }
421 
423 {
424  return m_vertices.size();
425 }
426 
428 {
429  m_vertices.resize(value);
430  m_normals.resize(value);
431  m_uv.resize(value);
432  m_tangents.resize(value);
433  m_binormals.resize(value);
434 }
435 
437 {
438  return m_triangles.size();
439 }
440 
442 {
443  m_triangles.resize(value);
444  m_tris.resize(value);
445 }
446 
448 {
449  return m_vertices[index];
450 }
451 
453 {
454  return m_normals[index];
455 }
456 
458 {
459  return m_uv[index];
460 }
461 
463 {
464  return m_tangents[index];
465 }
466 
468 {
469  return m_binormals[index];
470 }
471 
472 void LMesh::SetVertex(const LVector4 &vec, uint index)
473 {
474  if (index >= m_vertices.size())
475  return;
476  m_vertices[index] = vec;
477 }
478 
479 void LMesh::SetNormal(const LVector3 &vec, uint index)
480 {
481  if (index >= m_vertices.size())
482  return;
483  m_normals[index] = vec;
484 }
485 
486 void LMesh::SetUV(const LVector2 &vec, uint index)
487 {
488  if (index >= m_vertices.size())
489  return;
490  m_uv[index] = vec;
491 }
492 
493 void LMesh::SetTangent(const LVector3 &vec, uint index)
494 {
495  if (index >= m_vertices.size())
496  return;
497  m_tangents[index] = vec;
498 }
499 
500 void LMesh::SetBinormal(const LVector3 &vec, uint index)
501 {
502  if (index >= m_vertices.size())
503  return;
504  m_binormals[index] = vec;
505 }
506 
508 {
509  return m_triangles[index];
510 }
511 
513 {
514  LTriangle2 f;
515  LTriangle t = GetTriangle(index);
516  f.vertices[0] = GetVertex(t.a);
517  f.vertices[1] = GetVertex(t.b);
518  f.vertices[2] = GetVertex(t.c);
519 
520  f.vertexNormals[0] = GetNormal(t.a);
521  f.vertexNormals[1] = GetNormal(t.b);
522  f.vertexNormals[2] = GetNormal(t.c);
523 
524  f.textureCoords[0] = GetUV(t.a);
525  f.textureCoords[1] = GetUV(t.b);
526  f.textureCoords[2] = GetUV(t.c);
527 
528  LVector3 a, b;
529 
530  a = SubtractVectors(_4to3(f.vertices[1]), _4to3(f.vertices[0]));
531  b = SubtractVectors(_4to3(f.vertices[1]), _4to3(f.vertices[2]));
532 
533  f.faceNormal = CrossProduct(b, a);
534 
536 
537  f.materialId = m_tris[index].materialId;
538 
539  return f;
540 }
541 
543 {
544  return m_matrix;
545 }
546 
548 {
549  m_matrix = m;
550 }
551 
553 {
554  for (uint i=0; i<m_vertices.size(); i++)
556 
558 }
559 
560 void LMesh::CalcNormals(bool useSmoothingGroups)
561 {
562  uint i;
563  // first calculate the face normals
564  for (i=0; i<m_triangles.size(); i++)
565  {
566  LVector3 a, b;
569  m_tris[i].normal = NormalizeVector(CrossProduct(b, a));
570  }
571 
572  std::vector< std::vector<int> > array;
573  array.resize(m_vertices.size());
574  for (i=0; i<m_triangles.size(); i++)
575  {
576  uint k = m_tris[i].a;
577  array[k].push_back(i);
578 
579  k = m_tris[i].b;
580  array[k].push_back(i);
581 
582  k = m_tris[i].c;
583  array[k].push_back(i);
584  }
585 
586  LVector3 temp;
587 
588  if (!useSmoothingGroups)
589  {
590  // now calculate the normals without using smoothing groups
591  for (i=0; i<m_vertices.size(); i++)
592  {
593  temp = zero3;
594  int t = array[i].size();
595 
596  for (int k=0; k<t; k++)
597  {
598  temp.x += m_tris[array[i][k]].normal.x;
599  temp.y += m_tris[array[i][k]].normal.y;
600  temp.z += m_tris[array[i][k]].normal.z;
601  }
602  m_normals[i] = NormalizeVector(temp);
603  }
604  }
605  else
606  {
607  // now calculate the normals _USING_ smoothing groups
608  // I'm assuming a triangle can only belong to one smoothing group at a time!
609  std::vector<ulong> smGroups;
610  std::vector< std::vector <uint> > smList;
611 
612  uint loop_size = m_vertices.size();
613 
614  for (i=0; i<loop_size; i++)
615  {
616  int t = array[i].size();
617 
618  if (t == 0)
619  continue;
620 
621  smGroups.clear();
622  smList.clear();
623  smGroups.push_back(m_tris[array[i][0]].smoothingGroups);
624  smList.resize(smGroups.size());
625  smList[smGroups.size()-1].push_back(array[i][0]);
626 
627  // first build a list of smoothing groups for the vertex
628  for (int k=0; k<t; k++)
629  {
630  bool found = false;
631  for (uint j=0; j<smGroups.size(); j++)
632  {
633  if (m_tris[array[i][k]].smoothingGroups == smGroups[j])
634  {
635  smList[j].push_back(array[i][k]);
636  found = true;
637  }
638  }
639  if (!found)
640  {
641  smGroups.push_back(m_tris[array[i][k]].smoothingGroups);
642  smList.resize(smGroups.size());
643  smList[smGroups.size()-1].push_back(array[i][k]);
644  }
645  }
646  // now we have the list of faces for the vertex sorted by smoothing groups
647 
648 
649  // now duplicate the vertices so that there's only one smoothing group "per vertex"
650  if (smGroups.size() > 1)
651  for (uint j=1; j< smGroups.size(); j++)
652  {
653  m_vertices.push_back(m_vertices[i]);
654  m_normals.push_back(m_normals[i]);
655  m_uv.push_back(m_uv[i]);
656  m_tangents.push_back(m_tangents[i]);
657  m_binormals.push_back(m_binormals[i]);
658 
659  uint t = m_vertices.size()-1;
660  for (uint h=0; h<smList[j].size(); h++)
661  {
662  if (m_tris[smList[j][h]].a == i)
663  m_tris[smList[j][h]].a = t;
664  if (m_tris[smList[j][h]].b == i)
665  m_tris[smList[j][h]].b = t;
666  if (m_tris[smList[j][h]].c == i)
667  m_tris[smList[j][h]].c = t;
668  }
669  }
670  }
671 
672  // now rebuild a face list for each vertex, since the old one is invalidated
673  for (i=0; i<array.size(); i++)
674  array[i].clear();
675  array.clear();
676  array.resize(m_vertices.size());
677  for (i=0; i<m_triangles.size(); i++)
678  {
679  uint k = m_tris[i].a;
680  array[k].push_back(i);
681 
682  k = m_tris[i].b;
683  array[k].push_back(i);
684 
685  k = m_tris[i].c;
686  array[k].push_back(i);
687  }
688 
689  // now compute the normals
690  for (i=0; i<m_vertices.size(); i++)
691  {
692  temp = zero3;
693  int t = array[i].size();
694 
695  for (int k=0; k<t; k++)
696  {
697  temp.x += m_tris[array[i][k]].normal.x;
698  temp.y += m_tris[array[i][k]].normal.y;
699  temp.z += m_tris[array[i][k]].normal.z;
700  }
701  m_normals[i] = NormalizeVector(temp);
702  }
703 
704  }
705 
706  // copy m_tris to m_triangles
707  for (i=0; i<m_triangles.size(); i++)
708  {
709  m_triangles[i].a = m_tris[i].a;
710  m_triangles[i].b = m_tris[i].b;
711  m_triangles[i].c = m_tris[i].c;
712  }
713 
714 }
715 
717 {
718  // a understandable description of how to do that can be found here:
719  // http://members.rogers.com/deseric/tangentspace.htm
720  // first calculate the tangent for each triangle
721  LVector3 x_vec,
722  y_vec,
723  z_vec;
724  LVector3 v1, v2;
725  for (uint i=0; i<m_triangles.size(); i++)
726  {
727  v1.x = m_vertices[m_tris[i].b].x - m_vertices[m_tris[i].a].x;
728  v1.y = m_uv[m_tris[i].b].x - m_uv[m_tris[i].a].x;
729  v1.z = m_uv[m_tris[i].b].y - m_uv[m_tris[i].a].y;
730 
731  v2.x = m_vertices[m_tris[i].c].x - m_vertices[m_tris[i].a].x;
732  v2.y = m_uv[m_tris[i].c].x - m_uv[m_tris[i].a].x;
733  v2.z = m_uv[m_tris[i].c].y - m_uv[m_tris[i].a].y;
734 
735  x_vec = CrossProduct(v1, v2);
736 
737  v1.x = m_vertices[m_tris[i].b].y - m_vertices[m_tris[i].a].y;
738  v1.y = m_uv[m_tris[i].b].x - m_uv[m_tris[i].a].x;
739  v1.z = m_uv[m_tris[i].b].y - m_uv[m_tris[i].a].y;
740 
741  v2.x = m_vertices[m_tris[i].c].y - m_vertices[m_tris[i].a].y;
742  v2.y = m_uv[m_tris[i].c].x - m_uv[m_tris[i].a].x;
743  v2.z = m_uv[m_tris[i].c].y - m_uv[m_tris[i].a].y;
744 
745  y_vec = CrossProduct(v1, v2);
746 
747  v1.x = m_vertices[m_tris[i].b].z - m_vertices[m_tris[i].a].z;
748  v1.y = m_uv[m_tris[i].b].x - m_uv[m_tris[i].a].x;
749  v1.z = m_uv[m_tris[i].b].y - m_uv[m_tris[i].a].y;
750 
751  v2.x = m_vertices[m_tris[i].c].z - m_vertices[m_tris[i].a].z;
752  v2.y = m_uv[m_tris[i].c].x - m_uv[m_tris[i].a].x;
753  v2.z = m_uv[m_tris[i].c].y - m_uv[m_tris[i].a].y;
754 
755  z_vec = CrossProduct(v1, v2);
756 
757  m_tris[i].tangent.x = -(x_vec.y/x_vec.x);
758  m_tris[i].tangent.y = -(y_vec.y/y_vec.x);
759  m_tris[i].tangent.z = -(z_vec.y/z_vec.x);
760 
761  m_tris[i].binormal.x = -(x_vec.z/x_vec.x);
762  m_tris[i].binormal.y = -(y_vec.z/y_vec.x);
763  m_tris[i].binormal.z = -(z_vec.z/z_vec.x);
764 
765  }
766 
767  // now for each vertex build a list of face that share this vertex
768  std::vector< std::vector<int> > array;
769  array.resize(m_vertices.size());
770  for (int i=0; i<(int)m_triangles.size(); i++)
771  {
772  uint k = m_tris[i].a;
773  array[k].push_back(i);
774 
775  k = m_tris[i].b;
776  array[k].push_back(i);
777 
778  k = m_tris[i].c;
779  array[k].push_back(i);
780  }
781 
782  // now average the tangents and compute the binormals as (tangent X normal)
783  for (int i=0; i<(int)m_vertices.size(); i++)
784  {
785  v1 = zero3;
786  v2 = zero3;
787  int t = array[i].size();
788 
789  for (int k=0; k<t; k++)
790  {
791  v1.x += m_tris[array[i][k]].tangent.x;
792  v1.y += m_tris[array[i][k]].tangent.y;
793  v1.z += m_tris[array[i][k]].tangent.z;
794 
795  v2.x += m_tris[array[i][k]].binormal.x;
796  v2.y += m_tris[array[i][k]].binormal.y;
797  v2.z += m_tris[array[i][k]].binormal.z;
798  }
799  m_tangents[i] = NormalizeVector(v1);
800  //m_binormals[i] = NormalizeVector(v2);
801 
803  }
804 }
805 
807 {
808  switch (value)
809  {
810  case oNone:
812  break;
813  case oSimple:
815  CalcNormals(false);
816  break;
817  case oFull:
819  CalcNormals(true);
821  break;
822  }
823 }
824 
825 void LMesh::SetTri(const LTri &tri, uint index)
826 {
827  if (index >= m_triangles.size())
828  return;
829  m_tris[index] = tri;
830 }
831 
833 {
834  return m_tris[index];
835 }
836 
838 {
839  return m_materials[index];
840 }
841 
843 {
844  m_materials.push_back(id);
845  return m_materials.size()-1;
846 }
847 
849 {
850  return m_materials.size();
851 }
852 
853 //-------------------------------------------------------
854 // LLight implementation
855 //-------------------------------------------------------
856 
858 : LObject()
859 {
860  Clear();
861 }
862 
864 {
865 
866 }
867 
869 {
870  m_pos.x = m_pos.y = m_pos.z = 0.0f;
871  m_color.r = m_color.g = m_color.b = 0.0f;
872  m_spotlight = false;
873 }
874 
876 {
877  m_pos = vec;
878 }
879 
881 {
882  return m_pos;
883 }
884 
886 {
887  m_color = color;
888 }
889 
891 {
892  return m_color;
893 }
894 
895 void LLight::SetSpotlight(bool value)
896 {
897  m_spotlight = value;
898 }
899 
901 {
902  return m_spotlight;
903 }
904 
906 {
907  m_target = target;
908 }
909 
911 {
912  return m_target;
913 }
914 
915 void LLight::SetHotspot(float value)
916 {
917  m_hotspot = value;
918 }
919 
921 {
922  return m_hotspot;
923 }
924 
925 void LLight::SetFalloff(float value)
926 {
927  m_falloff = value;
928 }
929 
931 {
932  return m_falloff;
933 }
934 
935 //-------------------------------------------------------
936 // LImporter implementation
937 //-------------------------------------------------------
938 
940 {
941  Clear();
942 }
943 
945 {
946  Clear();
947 }
948 
950 {
951  return m_meshes.size();
952 }
953 
955 {
956  return m_lights.size();
957 }
958 
960 {
961  return m_materials.size();
962 }
963 
965 {
966  return m_meshes[index];
967 }
968 
970 {
971  return m_lights[index];
972 }
973 
975 {
976  return m_materials[index];
977 }
978 
979 LMaterial* LImporter::FindMaterial(const std::string& name)
980 {
981  for (uint i=0; i<m_materials.size(); i++)
982  if (m_materials[i].IsObject(name))
983  return &m_materials[i];
984  return 0;
985 }
986 
987 LMesh* LImporter::FindMesh(const std::string& name)
988 {
989  for (uint i=0; i<m_meshes.size(); i++)
990  if (m_meshes[i].IsObject(name))
991  return &m_meshes[i];
992  return 0;
993 }
994 
995 LLight* LImporter::FindLight(const std::string& name)
996 {
997  for (uint i=0; i<m_lights.size(); i++)
998  if (m_lights[i].IsObject(name))
999  return &m_lights[i];
1000  return 0;
1001 }
1002 
1004 {
1005  m_meshes.clear();
1006  m_lights.clear();
1007  m_materials.clear();
1008  m_optLevel = oFull;
1009 }
1010 
1012 {
1013  m_optLevel = value;
1014 }
1015 
1017 {
1018  return m_optLevel;
1019 }
1020 
1021 //-------------------------------------------------------
1022 // L3DS implementation
1023 //-------------------------------------------------------
1024 
1026 : LImporter()
1027 {
1028  m_buffer = 0;
1029  m_bufferSize = 0;
1030  m_pos = 0;
1031  m_eof = false;
1032 }
1033 
1034 L3DS::L3DS(const char *filename)
1035 : LImporter()
1036 {
1037  m_buffer = 0;
1038  m_bufferSize = 0;
1039  m_pos = 0;
1040  m_eof = false;
1041  LoadFile(filename);
1042 }
1043 
1045 {
1046  if (m_bufferSize > 0)
1047  free(m_buffer);
1048 }
1049 
1050 bool L3DS::LoadFile(const char *filename)
1051 {
1052  FILE *f;
1053  f = fopen(filename, "rb");
1054  if (f == 0)
1055  {
1056  ErrorMsg("L3DS::LoadFile - cannot open file");
1057  return false;
1058  }
1059  fseek(f, 0, SEEK_END);
1060  m_bufferSize = ftell(f);
1061  fseek(f, 0, SEEK_SET);
1062  m_buffer = (unsigned char*) calloc(m_bufferSize, 1);
1063  if (m_buffer == 0)
1064  {
1065  ErrorMsg("L3DS::LoadFile - not enough memory (malloc failed)");
1066  return false;
1067  }
1068  if (fread(m_buffer, m_bufferSize, 1, f) != 1)
1069  {
1070  fclose(f);
1071  free(m_buffer);
1072  m_bufferSize = 0;
1073  ErrorMsg("L3DS::LoadFile - error reading from file");
1074  return false;
1075  }
1076  fclose(f);
1077  Clear();
1078  bool res = Read3DS();
1079  free(m_buffer);
1080  m_buffer = 0;
1081  m_bufferSize = 0;
1082  return res;
1083 }
1084 
1086 {
1087  if ((m_buffer!=0) && (m_bufferSize != 0) && ((m_pos+2)<m_bufferSize))
1088  {
1089  short *w = (short*)(m_buffer+m_pos);
1090  short s = *w;//(short)*(m_buffer+m_pos);
1091  m_pos += 2;
1092  return s;
1093  }
1094  m_eof = true;
1095  return 0;
1096 }
1097 
1099 {
1100  if ((m_buffer!=0) && (m_bufferSize != 0) && ((m_pos+4)<m_bufferSize))
1101  {
1102  int *w = (int*)(m_buffer+m_pos);
1103  int s = *w;//(int)*(m_buffer+m_pos);
1104  m_pos += 4;
1105  return s;
1106  }
1107  m_eof = true;
1108  return 0;
1109 }
1110 
1112 {
1113  if ((m_buffer!=0) && (m_bufferSize != 0) && ((m_pos+1)<m_bufferSize))
1114  {
1115  char s = (char)*(m_buffer+m_pos);
1116  m_pos += 1;
1117  return s;
1118  }
1119  m_eof = true;
1120  return 0;
1121 }
1122 
1124 {
1125  if ((m_buffer!=0) && (m_bufferSize != 0) && ((m_pos+4)<m_bufferSize))
1126  {
1127  float *w = (float*)(m_buffer+m_pos);
1128  float s = *w;//(float)*(m_buffer+m_pos);
1129  m_pos += 4;
1130  return s;
1131  }
1132  m_eof = true;
1133  return 0.0;
1134 }
1135 
1137 {
1138  if ((m_buffer!=0) && (m_bufferSize != 0) && ((m_pos+1)<m_bufferSize))
1139  {
1140  byte s = (byte)*(m_buffer+m_pos);
1141  m_pos += 1;
1142  return s;
1143  }
1144  m_eof = true;
1145  return 0;
1146 }
1147 
1148 int L3DS::ReadASCIIZ(char *buf, int max_count)
1149 {
1150  int count;
1151  if ((m_buffer==0) || (m_bufferSize == 0) || (m_pos>=m_bufferSize))
1152  {
1153  count = 0;
1154  m_eof = true;
1155  return count;
1156  }
1157  count = 0;
1158  char c = ReadChar();
1159  while ((c!=0) && (count<max_count-1))
1160  {
1161  buf[count] = c;
1162  count ++;
1163  c = ReadChar();
1164  }
1165  buf[count] = 0;
1166  return count;
1167 }
1168 
1169 void L3DS::Seek(int offset, int origin)
1170 {
1171  if (origin == SEEK_START)
1172  m_pos = offset;
1173  if (origin == SEEK_CURSOR)
1174  m_pos += offset;
1175  if (m_pos < 0)
1176  m_pos = 0;
1177  if (m_pos >= m_bufferSize)
1178  m_pos = m_bufferSize-1;
1179  m_eof = false;
1180 }
1181 
1183 {
1184  return m_pos;
1185 }
1186 
1188 {
1189  LChunk chunk;
1190  chunk.id = ReadShort();
1191  int a = ReadInt();
1192  chunk.start = Pos();
1193  chunk.end = chunk.start+a-6;
1194  return chunk;
1195 }
1196 
1197 bool L3DS::FindChunk(LChunk &target, const LChunk &parent)
1198 {
1199  if (Pos() >= parent.end)
1200  return false;
1201  LChunk chunk;
1202  chunk = ReadChunk();
1203  while (( chunk.id != target.id) && (chunk.end <= parent.end))
1204  {
1205  SkipChunk(chunk);
1206  if (chunk.end >= parent.end)
1207  break;
1208  chunk = ReadChunk();
1209  }
1210  if (chunk.id == target.id)
1211  {
1212  target.start = chunk.start;
1213  target.end = chunk.end;
1214  return true;
1215  }
1216  return false;
1217 }
1218 
1219 void L3DS::SkipChunk(const LChunk &chunk)
1220 {
1221  Seek(chunk.end, SEEK_START);
1222 }
1223 
1224 void L3DS::GotoChunk(const LChunk &chunk)
1225 {
1226  Seek(chunk.start, SEEK_START);
1227 }
1228 
1230 {
1231  LColor3 col = black;
1232  GotoChunk(chunk);
1233  switch (chunk.id)
1234  {
1235  case COLOR_F:
1236  col.r = ReadFloat();
1237  col.g = ReadFloat();
1238  col.b = ReadFloat();
1239  break;
1240  case COLOR_24:
1241  col.r = ReadByte()/255.0f;
1242  col.g = ReadByte()/255.0f;
1243  col.b = ReadByte()/255.0f;
1244  break;
1245  case LIN_COLOR_F:
1246  col.r = ReadFloat();
1247  col.g = ReadFloat();
1248  col.b = ReadFloat();
1249  break;
1250  case LIN_COLOR_24:
1251  col.r = ReadByte()/255.0f;
1252  col.g = ReadByte()/255.0f;
1253  col.b = ReadByte()/255.0f;
1254  break;
1255  default:
1256  ErrorMsg("L3DS::ReadColor - error this is not a color chunk");
1257  }
1258  return col;
1259 }
1260 
1261 float L3DS::ReadPercentage(const LChunk &chunk)
1262 {
1263  GotoChunk(chunk);
1264  switch (chunk.id)
1265  {
1266  case INT_PERCENTAGE:
1267  return (ReadShort()/100.0f);
1268  case FLOAT_PERCENTAGE:
1269  return ReadFloat();
1270  }
1271  ErrorMsg("L3DS::ReadPercentage - error, the chunk is not a percentage chunk");
1272  return 0;
1273 }
1274 
1276 {
1277  LChunk mainchunk;
1278  LChunk edit;
1279  edit.id = EDIT3DS;
1280  mainchunk = ReadChunk();
1281  if (mainchunk.id != MAIN3DS)
1282  {
1283  ErrorMsg("L3DS::Read3DS - wrong file format");
1284  return false;
1285  }
1286  if (!FindChunk(edit, mainchunk))
1287  return false;
1288  LChunk obj;
1289  LChunk ml;
1290 
1291  GotoChunk(edit);
1292  obj.id = MAT_ENTRY;
1293  while (FindChunk(obj, edit))
1294  {
1295  ReadMaterial(obj);
1296  SkipChunk(obj);
1297  }
1298  GotoChunk(edit);
1299 
1300  obj.id = EDIT_OBJECT;
1301  {
1302  while (FindChunk(obj, edit))
1303  {
1304  ReadASCIIZ(m_objName, 99);
1305  ml = ReadChunk();
1306  if (ml.id == OBJ_TRIMESH)
1307  ReadMesh(ml);
1308  if (ml.id == OBJ_LIGHT)
1309  ReadLight(ml);
1310  SkipChunk(obj);
1311  }
1312  }
1313 
1314  // read the keyframer data here to find out correct object orientation
1315 
1316  LChunk keyframer;
1317  keyframer.id = KFDATA;
1318 
1319  LChunk objtrack;
1320  objtrack.id = OBJECT_NODE_TAG;
1321 
1322  GotoChunk(mainchunk);
1323  if (FindChunk(keyframer, mainchunk))
1324  { // keyframer chunk is present
1325  GotoChunk(keyframer);
1326  while (FindChunk(objtrack, keyframer))
1327  {
1328  ReadKeyframeData(objtrack);
1329  SkipChunk(objtrack);
1330  }
1331  }
1332 
1333  for (uint i=0; i<m_meshes.size(); i++) {
1334  m_meshes[i].Optimize(m_optLevel);
1335  }
1336 
1337  m_pos = 0;
1338  strcpy(m_objName, "");
1339  return true;
1340 }
1341 
1342 void L3DS::ReadLight(const LChunk &parent)
1343 {
1344  float t;
1345  LVector3 v;
1346  LLight light;
1347  light.SetName(m_objName);
1348  GotoChunk(parent);
1349  LChunk chunk = ReadChunk();
1350  if (chunk.id == OBJ_LIGHT)
1351  {
1352  v.x = ReadFloat();
1353  v.y = ReadFloat();
1354  v.z = ReadFloat();
1355  if (chunk.end < parent.end)
1356  chunk = ReadChunk();
1357  while (chunk.end <= parent.end)
1358  {
1359  switch (chunk.id)
1360  {
1361  case COLOR_24:
1362  case COLOR_F:
1363  case LIN_COLOR_F:
1364  case LIN_COLOR_24:
1365  light.SetColor(ReadColor(chunk));
1366  break;
1367  case SPOTLIGHT:
1368  v.x = ReadFloat();
1369  v.y = ReadFloat();
1370  v.z = ReadFloat();
1371  light.SetTarget(v);
1372  t = ReadFloat();
1373  light.SetHotspot(t);
1374  t = ReadFloat();
1375  light.SetFalloff(t);
1376  break;
1377  default:
1378  break;
1379  }
1380  SkipChunk(chunk);
1381  if (chunk.end >= parent.end)
1382  break;
1383  chunk = ReadChunk();
1384 
1385  }
1386  }
1387  m_lights.push_back(light);
1388 }
1389 
1390 void L3DS::ReadMesh(const LChunk &parent)
1391 {
1392  unsigned short count, i;
1393  LVector4 p;
1394  LMatrix4 m;
1395  LVector2 t;
1396  p.w = 1.0f;
1397  LMesh mesh;
1398  mesh.SetName(m_objName);
1399  GotoChunk(parent);
1400  LChunk chunk = ReadChunk();
1401  while (chunk.end <= parent.end)
1402  {
1403  switch (chunk.id)
1404  {
1405  case TRI_VERTEXLIST:
1406  count = ReadShort();
1407  mesh.SetVertexArraySize(count);
1408  for (i=0; i < count; i++)
1409  {
1410  p.x = ReadFloat();
1411  p.y = ReadFloat();
1412  p.z = ReadFloat();
1413  mesh.SetVertex(p, i);
1414  }
1415  break;
1416  case TRI_FACEMAPPING:
1417  count = ReadShort();
1418  if (mesh.GetVertexCount() == 0)
1419  mesh.SetVertexArraySize(count);
1420  for (i=0; i < count; i++)
1421  {
1422  t.x = ReadFloat();
1423  t.y = ReadFloat();
1424  mesh.SetUV(t, i);
1425  }
1426  break;
1427  case TRI_FACELIST:
1428  ReadFaceList(chunk, mesh);
1429  break;
1430  case TRI_MATRIX:
1431  {
1432  for (int i = 0; i < 4; i++)
1433  for (int j = 0; j < 3; j++)
1434  m.m[i][j] = ReadFloat();
1435 
1436  m.m[0][3] = 0.0f;
1437  m.m[1][3] = 0.0f;
1438  m.m[2][3] = 0.0f;
1439  m.m[3][3] = 1.0f;
1440 
1441  mesh.SetMatrix(m);
1442  }
1443  break;
1444  default:
1445  break;
1446  }
1447  SkipChunk(chunk);
1448  if (chunk.end >= parent.end)
1449  break;
1450  chunk = ReadChunk();
1451  }
1452  m_meshes.push_back(mesh);
1453 }
1454 
1455 void L3DS::ReadFaceList(const LChunk &chunk, LMesh &mesh)
1456 {
1457  // variables
1458  unsigned short count, t;
1459  uint i;
1460  LTri tri;
1461  LChunk ch;
1462  char str[20];
1463  //uint mat;
1464 
1465  // consistency checks
1466  if (chunk.id != TRI_FACELIST)
1467  {
1468  ErrorMsg("L3DS::ReadFaceList - internal error: wrong chunk passed as parameter");
1469  return;
1470  }
1471  GotoChunk(chunk);
1472  tri.smoothingGroups = 1;
1473  // read the number of faces
1474  count = ReadShort();
1475  mesh.SetTriangleArraySize(count);
1476  for (i=0; i<count; i++)
1477  {
1478  tri.a = ReadShort();
1479  tri.b = ReadShort();
1480  tri.c = ReadShort();
1481  ReadShort();
1482  mesh.SetTri(tri, i);
1483  }
1484  // now read the optional chunks
1485  ch = ReadChunk();
1486  while (ch.end <= chunk.end)
1487  {
1488  switch (ch.id)
1489  {
1490  case TRI_MAT_GROUP: {
1491  ReadASCIIZ(str, 20);
1492  int mat_id = FindMaterial(str)->GetID();
1493  mesh.AddMaterial(mat_id);
1494  count = ReadShort();
1495  for (i=0; i<count; i++) {
1496  t = ReadShort();
1497  mesh.GetTri(t).materialId = mat_id;
1498  }
1499  }
1500  break;
1501 
1502  case TRI_SMOOTH_GROUP:
1503  for (i=0; i<mesh.GetTriangleCount(); i++)
1504  mesh.GetTri(i).smoothingGroups = (ulong) ReadInt();
1505  break;
1506  }
1507  SkipChunk(ch);
1508  ch = ReadChunk();
1509  }
1510 }
1511 
1512 void L3DS::ReadMaterial(const LChunk &parent)
1513 {
1514  // variables
1515  LChunk chunk;
1516  LChunk child;
1517  char str[30];
1518  LMaterial mat;
1519  short sh;
1520 
1521  GotoChunk(parent);
1522 
1523  chunk = ReadChunk();
1524  while (chunk.end <= parent.end)
1525  {
1526  switch (chunk.id)
1527  {
1528  case MAT_NAME:
1529  ReadASCIIZ(str, 30);
1530  mat.SetName(str);
1531  break;
1532  case MAT_AMBIENT:
1533  child = ReadChunk();
1534  mat.SetAmbientColor(ReadColor(child));
1535  break;
1536  case MAT_DIFFUSE:
1537  child = ReadChunk();
1538  mat.SetDiffuseColor(ReadColor(child));
1539  break;
1540  case MAT_SPECULAR:
1541  child = ReadChunk();
1542  mat.SetSpecularColor(ReadColor(child));
1543  break;
1544  case MAT_SHININESS:
1545  child = ReadChunk();
1546  mat.SetShininess(ReadPercentage(child));
1547  break;
1548  case MAT_TRANSPARENCY:
1549  child = ReadChunk();
1550  mat.SetTransparency(ReadPercentage(child));
1551  break;
1552  case MAT_SHADING:
1553  sh = ReadShort();
1554  switch (sh)
1555  {
1556  case 0:
1558  break;
1559  case 1:
1560  mat.SetShadingType(sFlat);
1561  break;
1562  case 2:
1563  mat.SetShadingType(sGouraud);
1564  break;
1565  case 3:
1566  mat.SetShadingType(sPhong);
1567  break;
1568  case 4:
1569  mat.SetShadingType(sMetal);
1570  break;
1571  }
1572  break;
1573  case MAT_WIRE:
1575  break;
1576  case MAT_TEXMAP:
1577  ReadMap(chunk, mat.GetTextureMap1());
1578  break;
1579  case MAT_TEX2MAP:
1580  ReadMap(chunk, mat.GetTextureMap2());
1581  break;
1582  case MAT_OPACMAP:
1583  ReadMap(chunk, mat.GetOpacityMap());
1584  break;
1585  case MAT_BUMPMAP:
1586  ReadMap(chunk, mat.GetBumpMap());
1587  break;
1588  case MAT_SPECMAP:
1589  ReadMap(chunk, mat.GetSpecularMap());
1590  break;
1591  case MAT_REFLMAP:
1592  child = ReadChunk();
1593  mat.GetReflectionMap().strength = ReadPercentage(child);
1594  SkipChunk(child);
1595  child = ReadChunk();
1596  if (child.id != MAT_MAPNAME)
1597  {
1598  ErrorMsg("L3DS::ReadMaterial - error, expected chunk not found");
1599  return;
1600  }
1601  ReadASCIIZ(str, 30);
1602  if (strcmp(str, "") == 0)
1603  strcpy(mat.GetReflectionMap().mapName, "auto");
1604  break;
1605  }
1606 
1607  SkipChunk(chunk);
1608  chunk = ReadChunk();
1609  }
1610  m_materials.push_back(mat);
1611  m_materials[m_materials.size()-1].SetID(m_materials.size()-1);
1612 }
1613 
1614 void L3DS::ReadMap(const LChunk &chunk, LMap& map)
1615 {
1616  LChunk child;
1617  char str[20];
1618  GotoChunk(chunk);
1619  child = ReadChunk();
1620  while (child.end <= chunk.end)
1621  {
1622  switch (child.id)
1623  {
1624  case INT_PERCENTAGE:
1625  map.strength = ReadPercentage(child);
1626  break;
1627  case MAT_MAPNAME:
1628  ReadASCIIZ(str, 20);
1629  strcpy(map.mapName, str);
1630  break;
1631  case MAT_MAP_USCALE:
1632  map.uScale = ReadFloat();
1633  break;
1634  case MAT_MAP_VSCALE:
1635  map.vScale = ReadFloat();
1636  break;
1637  case MAT_MAP_UOFFSET:
1638  map.uOffset = ReadFloat();
1639  break;
1640  case MAT_MAP_VOFFSET:
1641  map.vOffset = ReadFloat();
1642  break;
1643  case MAT_MAP_ANG:
1644  map.angle = ReadFloat();
1645  break;
1646  }
1647  SkipChunk(child);
1648  child = ReadChunk();
1649  }
1650 }
1651 
1652 void L3DS::ReadKeyframeData(const LChunk &parent)
1653 {
1654  uint frames = 0;
1655 
1656  LChunk node_hdr;
1657  node_hdr.id = NODE_HDR;
1658 
1659  char str[20];
1660  LMesh *mesh;
1661 
1662  GotoChunk(parent);
1663  if (!FindChunk(node_hdr, parent))
1664  return;
1665  GotoChunk(node_hdr);
1666  ReadASCIIZ(str, 19);
1667  mesh = FindMesh(str);
1668  if (mesh == 0)
1669  return;
1670  GotoChunk(parent);
1671 
1672  // read the pivot
1673  LVector3 pivot = zero3;
1674 
1675  LChunk pivotchunk;
1676  pivotchunk.id = PIVOT;
1677  if (FindChunk(pivotchunk, parent))
1678  {
1679  GotoChunk(pivotchunk);
1680  pivot.x = ReadFloat();
1681  pivot.y = ReadFloat();
1682  pivot.z = ReadFloat();
1683  }
1684  GotoChunk(parent);
1685 
1686  // read frame 0 from the position track
1687  LVector3 pos = zero3;
1688 
1689  frames = 0;
1690 
1691  LChunk poschunk;
1692  poschunk.id = POS_TRACK_TAG;
1693  if (FindChunk(poschunk, parent))
1694  {
1695  GotoChunk(poschunk);
1696  // read the trackheader structure
1697  ReadShort();
1698  ReadInt();
1699  ReadInt();
1700  frames = ReadInt();
1701  if (frames > 0)
1702  {
1703  ReadKeyheader();
1704  pos.x = ReadFloat();
1705  pos.y = ReadFloat();
1706  pos.z = ReadFloat();
1707  }
1708  }
1709  GotoChunk(parent);
1710 
1711  // now read the rotation track
1712  LVector4 rot = zero4;
1713 
1714  LChunk rotchunk;
1715  rotchunk.id = ROT_TRACK_TAG;
1716 
1717  frames = 0;
1718  if (FindChunk(rotchunk, parent))
1719  {
1720  GotoChunk(rotchunk);
1721  // read the trackheader structure
1722  ReadShort();
1723  ReadInt();
1724  ReadInt();
1725  frames = ReadInt();
1726  if (frames > 0)
1727  {
1728  ReadKeyheader();
1729  rot.x = ReadFloat();
1730  rot.y = ReadFloat();
1731  rot.z = ReadFloat();
1732  rot.w = ReadFloat();
1733  }
1734  }
1735  GotoChunk(parent);
1736 
1737  // now read the scaling chunk
1738  LVector3 scale;
1739  scale.x = 1;
1740  scale.y = 1;
1741  scale.z = 1;
1742 
1743  LChunk scalechunk;
1744  scalechunk.id = SCL_TRACK_TAG;
1745 
1746  frames = 0;
1747 
1748  if (FindChunk(scalechunk, parent))
1749  {
1750  GotoChunk(scalechunk);
1751  // read the trackheader structure
1752  ReadShort();
1753  ReadInt();
1754  ReadInt();
1755  frames = ReadInt();
1756  if (frames > 0)
1757  {
1758  ReadKeyheader();
1759  scale.x = ReadFloat();
1760  scale.y = ReadFloat();
1761  scale.z = ReadFloat();
1762  }
1763  }
1764  GotoChunk(parent);
1765 
1766 
1767 }
1768 
1770 {
1771  long frame;
1772  frame = ReadInt();
1773  short opts = ReadShort();
1774  if (opts & 32768) // 32768 is 1000000000000000 binary
1775  { // tension is present
1776  ReadFloat();
1777  }
1778  if (opts & 16384) // 16384 is 0100000000000000 binary
1779  { // continuity is present
1780  ReadFloat();
1781  }
1782  if (opts & 8192)
1783  { // bias info present
1784  ReadFloat();
1785  }
1786  if (opts & 4096)
1787  { // "ease to" present
1788  ReadFloat();
1789  }
1790  if (opts & 2048)
1791  { // "ease from" present
1792  ReadFloat();
1793  }
1794  return frame;
1795 }