Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
ModelFile3DS.cpp
Go to the documentation of this file.
1 /* Project Magic 2.0
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: Magic.exe
6  FILE: ModelFile3DS.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  File loader for 3DStudio MAX 3DS format models
13 */
14 
15 #include "stdafx.h"
16 #include "Magic.h"
17 #include "MagicDoc.h"
18 #include "ModelFile3DS.h"
19 
20 #include "Bitmap.h"
21 #include "Polygon.h"
22 #include "Text.h"
23 #include "List.h"
24 #include "l3ds.h"
25 
26 // +--------------------------------------------------------------------+
27 
28 ModelFile3DS::ModelFile3DS(const char* fname)
29  : ModelFile(fname)
30 {
31 }
32 
34 {
35 }
36 
37 // +--------------------------------------------------------------------+
38 
39 static int mcomp(const void* a, const void* b)
40 {
41  Poly* pa = (Poly*) a;
42  Poly* pb = (Poly*) b;
43 
44  if (pa->sortval == pb->sortval)
45  return 0;
46 
47  if (pa->sortval < pb->sortval)
48  return 1;
49 
50  return -1;
51 }
52 
53 bool
54 ModelFile3DS::Load(Model* model, double scale)
55 {
56  if (model && scale > 0 && strlen(filename) > 0) {
57  ModelFile::Load(model, scale);
58 
59  L3DS loader;
60 
61  if (!loader.LoadFile(filename)) {
62  ::MessageBox(0, "3DS Import Failed: Magic could not open the file for reading", "ERROR", MB_OK);
63  return false;
64  }
65 
66  int ntex = 0;
67  int nsurfs = 0;
68  int nverts = 0;
69  int npolys = 0;
70  int nmatls = 0;
71  int nmeshs = loader.GetMeshCount();
72 
73  int* mesh_verts = new int[nmeshs];
74 
75  for (int m = 0; m < nmeshs; m++) {
76  LMesh& mesh = loader.GetMesh(m);
77 
78  mesh_verts[m] = nverts;
79 
80  // count verts and polys:
81  nverts += mesh.GetVertexCount();
82  npolys += mesh.GetTriangleCount();
83  }
84 
85  if (nverts > Model::MAX_VERTS || npolys > Model::MAX_POLYS) {
86  ::MessageBox(0, "3DS Import Failed: model was too large (max 16000 polys)", "ERROR", MB_OK);
87  delete [] mesh_verts;
88  return FALSE;
89  }
90 
91  // get materials:
92  nmatls = loader.GetMaterialCount();
93 
94  for (int i = 0; i < nmatls; i++) {
95  LMaterial& matl = loader.GetMaterial(i);
96  LMap& tex_diff = matl.GetTextureMap1();
97  LMap& tex_spec = matl.GetSpecularMap();
98  LMap& tex_bump = matl.GetBumpMap();
99  LMap& tex_glow = matl.GetTextureMap2();
100 
101  Material* material = new Material;
102 
103  strncpy(material->name, matl.GetName().c_str(), Material::NAMELEN);
104 
105  material->Ka.Set( matl.GetAmbientColor().r,
106  matl.GetAmbientColor().g,
107  matl.GetAmbientColor().b );
108 
109  material->ambient_value = 1.0f;
110  material->ambient_color = material->Ka.ToColor();
111 
112  material->Kd.Set( matl.GetDiffuseColor().r,
113  matl.GetDiffuseColor().g,
114  matl.GetDiffuseColor().b );
115 
116  material->diffuse_value = 1.0f;
117  material->diffuse_color = material->Kd.ToColor();
118 
119  material->Ks.Set( matl.GetSpecularColor().r,
120  matl.GetSpecularColor().g,
121  matl.GetSpecularColor().b );
122 
123  material->specular_value = 1.0f;
124  material->specular_color = material->Ks.ToColor();
125 
126  material->power = matl.GetShininess() * 100;
127 
128  if (tex_diff.mapName[0])
129  LoadTexture(tex_diff.mapName, material->tex_diffuse);
130 
131  if (tex_spec.mapName[0])
132  LoadTexture(tex_spec.mapName, material->tex_specular);
133 
134  if (tex_bump.mapName[0])
135  LoadTexture(tex_bump.mapName, material->tex_bumpmap);
136 
137  if (tex_glow.mapName[0])
138  LoadTexture(tex_glow.mapName, material->tex_emissive);
139 
140  model->GetMaterials().append(material);
141  }
142 
143  Surface* surface = new Surface;
144  model->GetSurfaces().append(surface);
145 
146  surface->CreateVerts(nverts);
147  surface->CreatePolys(npolys);
148 
149  VertexSet* vset = surface->GetVertexSet();
150  Poly* polys = surface->GetPolys();
151  float radius = 0;
152  int v = 0;
153 
154  for (int m = 0; m < nmeshs && v < nverts; m++) {
155  LMesh& mesh = loader.GetMesh(m);
156 
157  // read vertex set:
158  for (int i = 0; i < mesh.GetVertexCount() && v < nverts; i++) {
159  vset->loc[v].x = mesh.GetVertex(i).x;
160  vset->loc[v].y = mesh.GetVertex(i).z;
161  vset->loc[v].z = mesh.GetVertex(i).y;
162 
163  vset->nrm[v].x = mesh.GetNormal(i).x;
164  vset->nrm[v].y = mesh.GetNormal(i).z;
165  vset->nrm[v].z = mesh.GetNormal(i).y;
166 
167  vset->tu[v] = mesh.GetUV(i).x;
168  vset->tv[v] = mesh.GetUV(i).y;
169 
170  float d = vset->loc[v].length();
171  if (d > radius)
172  radius = d;
173 
174  v++;
175  }
176  }
177 
178  if (radius < 16) {
179  model->ScaleBy(256.0f / radius);
180  radius = 256.0f;
181  }
182 
183  int n = 0;
184 
185  for (int m = 0; m < nmeshs && n < npolys; m++) {
186  LMesh& mesh = loader.GetMesh(m);
187 
188  // read polys:
189  int mesh_tris = mesh.GetTriangleCount();
190  for (int i = 0; i < mesh_tris && n < npolys; i++) {
191  Poly* p = surface->GetPolys() + n++;
192  const LTriangle& tri = mesh.GetTriangle(i);
193  LTriangle2 tri2 = mesh.GetTriangle2(i);
194 
195  p->nverts = 3;
196 
197  p->verts[0] = tri.a + mesh_verts[m];
198  p->verts[1] = tri.b + mesh_verts[m];
199  p->verts[2] = tri.c + mesh_verts[m];
200 
201  if (p->verts[0] > nverts || p->verts[1] > nverts || p->verts[2] > nverts) {
202  p->verts[0] = 0;
203  p->verts[1] = 1;
204  p->verts[2] = 2;
205  }
206 
207  if (tri2.vertexNormals[0] == tri2.vertexNormals[1] &&
208  tri2.vertexNormals[0] == tri2.vertexNormals[2])
209  p->flatness = 1.0f;
210  else
211  p->flatness = 0.0f;
212 
213  p->vertex_set = vset;
214  p->material = model->GetMaterials()[ tri2.materialId ];
215  p->sortval = tri2.materialId;
216 
217  p->plane = Plane(vset->loc[ p->verts[0] ],
218  vset->loc[ p->verts[2] ],
219  vset->loc[ p->verts[1] ]);
220 
221  surface->AddIndices(p->nverts);
222  }
223  }
224 
225  // sort the polys by material index:
226  qsort((void*) polys, npolys, sizeof(Poly), mcomp);
227 
228  // then assign them to cohesive segments:
229  Segment* segment = 0;
230 
231  for (int n = 0; n < npolys; n++) {
232  if (segment && segment->material == polys[n].material) {
233  segment->npolys++;
234  }
235  else {
236  segment = 0;
237  }
238 
239  if (!segment) {
240  segment = new Segment;
241 
242  segment->npolys = 1;
243  segment->polys = &polys[n];
244  segment->material = segment->polys->material;
245 
246  surface->GetSegments().append(segment);
247  }
248  }
249 
250  *pnverts = nverts;
251  *pnpolys = npolys;
252  *pradius = radius;
253 
254  model->Normalize();
255  return true;
256  }
257 
258  return false;
259 }
260 
261 // +--------------------------------------------------------------------+
262 
263 bool
265 {
266  if (m) {
267  ModelFile::Save(m);
268 
269  FILE* f = fopen(filename, "w");
270  if (!f) {
271  ::MessageBox(0, "3DS Export Failed: Magic could not open the file for writing", "ERROR", MB_OK);
272  return false;
273  }
274 
275  fclose(f);
276 
277  return true;
278  }
279 
280  return false;
281 }
282 
283 // +--------------------------------------------------------------------+