From 8898ad9b25fca6afe2374d293a981db02a83d7e9 Mon Sep 17 00:00:00 2001 From: "FWoltermann@gmail.com" Date: Thu, 31 May 2012 14:46:27 +0000 Subject: Committing the documentation to svn to have it accessible online --- Doc/doxygen/html/_solid_8cpp_source.html | 2586 ++++++++++++++++++++++++++++++ 1 file changed, 2586 insertions(+) create mode 100644 Doc/doxygen/html/_solid_8cpp_source.html (limited to 'Doc/doxygen/html/_solid_8cpp_source.html') diff --git a/Doc/doxygen/html/_solid_8cpp_source.html b/Doc/doxygen/html/_solid_8cpp_source.html new file mode 100644 index 0000000..c1b637b --- /dev/null +++ b/Doc/doxygen/html/_solid_8cpp_source.html @@ -0,0 +1,2586 @@ + + + + + +Starshatter_Open: D:/SRC/StarshatterSVN/nGenEx/Solid.cpp Source File + + + + + + + + + + + + + +
+
+ + + + + + +
+
Starshatter_Open +
+
Open source Starshatter engine
+
+
+ + + + + +
+
+ +
+
+
+ +
+ + + + +
+ +
+ +
+
+
Solid.cpp
+
+
+Go to the documentation of this file.
1 /* Project nGenEx
+
2  Destroyer Studios LLC
+
3  Copyright © 1997-2004. All Rights Reserved.
+
4 
+
5  SUBSYSTEM: nGenEx.lib
+
6  FILE: Solid.cpp
+
7  AUTHOR: John DiCamillo
+
8 
+
9 
+
10  OVERVIEW
+
11  ========
+
12  Classes for rendering solid meshes of polygons
+
13 */
+
14 
+
15 #include "MemDebug.h"
+
16 #include "Solid.h"
+
17 #include "Scene.h"
+
18 #include "Bitmap.h"
+
19 #include "DataLoader.h"
+
20 #include "Light.h"
+
21 #include "Shadow.h"
+
22 #include "Projector.h"
+
23 #include "OPCODE.h"
+
24 
+
25 #ifdef for
+
26 #undef for
+
27 #endif
+
28 
+
29 void Print(const char* fmt, ...);
+
30 
+
31 // +--------------------------------------------------------------------+
+
32 
+
33 static bool use_collision_detection = true;
+
34 
+
35 bool Solid::IsCollisionEnabled() { return use_collision_detection; }
+
36 void Solid::EnableCollision(bool e) { use_collision_detection = e; }
+
37 
+
38 // +--------------------------------------------------------------------+
+
39 
+
40 Opcode::AABBTreeCollider opcode_collider;
+
41 
+ +
43 {
+
44 public:
+ +
46  bool status = false;
+
47 
+
48  if (s) {
+
49  using namespace Opcode;
+
50  opcode_collider.SetFirstContact(true);
+
51 
+
52  npolys = s->NumPolys();
+
53  nverts = s->NumVerts();
+
54  ntris = s->NumIndices() / 3;
+
55 
+
56  locs = new(__FILE__,__LINE__) IcePoint[nverts];
+
57  tris = new(__FILE__,__LINE__) IndexedTriangle[ntris];
+
58 
+
59  if (locs && tris) {
+
60  int i, n = 0;
+
61 
+
62  for (i = 0; i < nverts; i++) {
+
63  IcePoint* p = locs + i;
+
64  Vec3* v = s->GetVertexSet()->loc + i;
+
65 
+
66  p->Set(v->x, v->y, v->z);
+
67  }
+
68 
+
69  for (i = 0; i < npolys; i++) {
+
70  Poly* p = s->GetPolys() + i;
+
71 
+
72  if (p->nverts == 3) {
+
73  IndexedTriangle& t = tris[n++];
+
74 
+
75  t.mVRef[0] = p->verts[0];
+
76  t.mVRef[1] = p->verts[2];
+
77  t.mVRef[2] = p->verts[1];
+
78  }
+
79  else {
+
80  IndexedTriangle& t1 = tris[n++];
+
81  IndexedTriangle& t2 = tris[n++];
+
82 
+
83  t1.mVRef[0] = p->verts[0];
+
84  t1.mVRef[1] = p->verts[2];
+
85  t1.mVRef[2] = p->verts[1];
+
86 
+
87  t2.mVRef[0] = p->verts[0];
+
88  t2.mVRef[1] = p->verts[3];
+
89  t2.mVRef[2] = p->verts[2];
+
90  }
+
91  }
+
92 
+
93  mesh.SetNbVertices(nverts);
+
94  mesh.SetNbTriangles(ntris);
+
95  mesh.SetPointers(tris, locs);
+
96 
+
97  OPCODECREATE creator;
+
98  creator.mIMesh = &mesh;
+
99  status = model.Build(creator);
+
100  }
+
101  }
+
102  else {
+
103  tris = 0;
+
104  locs = 0;
+
105  npolys = 0;
+
106  nverts = 0;
+
107  ntris = 0;
+
108  }
+
109  }
+
110 
+ +
112  delete [] tris;
+
113  delete [] locs;
+
114  }
+
115 
+
116  Opcode::Model model;
+
117  Opcode::MeshInterface mesh;
+
118  IndexedTriangle* tris;
+
119  IcePoint* locs;
+
120  int npolys;
+
121  int nverts;
+
122  int ntris;
+
123 };
+
124 
+
125 // +--------------------------------------------------------------------+
+
126 // +--------------------------------------------------------------------+
+
127 // +--------------------------------------------------------------------+
+
128 
+ +
130 : model(0), own_model(1),
+
131 roll(0.0f), pitch(0.0f), yaw(0.0f), intersection_poly(0)
+
132 {
+
133  shadow = true;
+
134  sprintf_s(name, "Solid %d", id);
+
135 }
+
136 
+
137 // +--------------------------------------------------------------------+
+
138 
+ +
140 {
+
141  if (own_model)
+
142  delete model;
+
143 
+
144  shadows.destroy();
+
145 }
+
146 
+
147 // +--------------------------------------------------------------------+
+
148 
+
149 void
+ +
151 {
+
152 }
+
153 
+
154 // +--------------------------------------------------------------------+
+
155 
+
156 void
+ +
158 {
+
159  orientation = o;
+
160 }
+
161 
+
162 void
+ +
164 {
+
165  luminous = l;
+
166 
+
167  if (model && luminous) {
+
168  model->luminous = luminous;
+
169 
+ +
171 
+
172  while (++iter) {
+
173  Material* mtl = iter.value();
+
174 
+
175  mtl->Ka = Color::Black;
+
176  mtl->Kd = Color::Black;
+
177  mtl->Ks = Color::Black;
+
178  mtl->Ke = Color::White;
+
179 
+
180  if (mtl->tex_diffuse && !mtl->tex_emissive)
+
181  mtl->tex_emissive = mtl->tex_diffuse;
+
182  }
+
183 
+
184  ListIter<Surface> s_iter = model->GetSurfaces();
+
185  while (++s_iter) {
+
186  Surface* surface = s_iter.value();
+
187  VertexSet* vset = surface->GetVertexSet();
+
188 
+
189  for (int i = 0; i < vset->nverts; i++) {
+
190  vset->diffuse[i] = Color::White.Value();
+
191  vset->specular[i] = Color::Black.Value();
+
192  }
+
193  }
+
194  }
+
195 }
+
196 
+
197 // +--------------------------------------------------------------------+
+
198 
+
199 void
+ +
201 {
+
202  if (!model || infinite)
+
203  return;
+
204 
+
205  // copy the orientation matrix from the solid we are matching:
+
206  orientation = match.Orientation();
+
207 }
+
208 
+
209 // +--------------------------------------------------------------------+
+
210 
+
211 void
+
212 Solid::Render(Video* video, DWORD flags)
+
213 {
+
214  if (flags & RENDER_ADDITIVE)
+
215  return;
+
216 
+
217  if (video && model && model->NumPolys()) {
+
218  DWORD blend_modes = Video::BLEND_SOLID;
+
219 
+
220  if (flags == RENDER_ALPHA)
+ +
222 
+
223  video->DrawSolid(this, blend_modes);
+
224  }
+
225 }
+
226 
+
227 // +--------------------------------------------------------------------+
+
228 
+
229 void
+ +
231 {
+
232 }
+
233 
+
234 // +--------------------------------------------------------------------+
+
235 
+
236 void
+ +
238 {
+
239  if (model && p) {
+
240  Point tmp = loc;
+
241  p->Transform(tmp);
+
242 
+
243  if (tmp.z > 1) {
+
244  int l = 2000;
+
245  int r = -2000;
+
246  int t = 2000;
+
247  int b = -2000;
+
248 
+
249  for (int i = 0; i < 6; i++) {
+
250  Point extent;
+
251 
+
252  if (i < 2)
+
253  extent.x = model->extents[i];
+
254 
+
255  else if (i < 4)
+
256  extent.y = model->extents[i];
+
257 
+
258  else
+
259  extent.z = model->extents[i];
+
260 
+
261  extent = extent * orientation + loc;
+
262 
+
263  p->Transform(extent);
+
264  p->Project(extent);
+
265 
+
266  if (extent.x < l) l = (int) extent.x;
+
267  if (extent.x > r) r = (int) extent.x;
+
268  if (extent.y < t) t = (int) extent.y;
+
269  if (extent.y > b) b = (int) extent.y;
+
270  }
+
271 
+
272  screen_rect.x = l;
+
273  screen_rect.y = t;
+
274  screen_rect.w = r-l;
+
275  screen_rect.h = b-t;
+
276  return;
+
277  }
+
278  }
+
279 
+
280  screen_rect.x = 2000;
+
281  screen_rect.y = 2000;
+
282  screen_rect.w = 0;
+
283  screen_rect.h = 0;
+
284 }
+
285 
+
286 // +--------------------------------------------------------------------+
+
287 // Polygon Interference Detection:
+
288 
+
289 int
+ +
291 {
+
292  Vec3 delta_loc = Location() - o.Location();
+
293 
+
294  // bounding spheres test:
+
295  if (delta_loc.length() > Radius() + o.Radius())
+
296  return 0;
+
297 
+
298  // possible collision, but no further refinement can be done:
+
299  if (!o.IsSolid())
+
300  return 1;
+
301 
+
302  Solid& s = (Solid&) o;
+
303 
+
304  // use the OPCODE library to check for polygon interference:
+
305  if (model && s.model) {
+
306  using namespace Opcode;
+
307 
+
308  bool contact = false;
+
309 
+
310  // first, reverse the orientation matrices for OPCODE:
+
311  Matrix m1 = orientation;
+
312  Matrix m2 = s.orientation;
+
313 
+
314  Matrix4x4 world0;
+
315  Matrix4x4 world1;
+
316 
+
317  world0.m[0][0] = (float) m1.elem[0][0];
+
318  world0.m[0][1] = (float) m1.elem[0][1];
+
319  world0.m[0][2] = (float) m1.elem[0][2];
+
320  world0.m[0][3] = 0.0f;
+
321 
+
322  world0.m[1][0] = (float) m1.elem[1][0];
+
323  world0.m[1][1] = (float) m1.elem[1][1];
+
324  world0.m[1][2] = (float) m1.elem[1][2];
+
325  world0.m[1][3] = 0.0f;
+
326 
+
327  world0.m[2][0] = (float) m1.elem[2][0];
+
328  world0.m[2][1] = (float) m1.elem[2][1];
+
329  world0.m[2][2] = (float) m1.elem[2][2];
+
330  world0.m[2][3] = 0.0f;
+
331 
+
332  world0.m[3][0] = (float) Location().x;
+
333  world0.m[3][1] = (float) Location().y;
+
334  world0.m[3][2] = (float) Location().z;
+
335  world0.m[3][3] = 1.0f;
+
336 
+
337  world1.m[0][0] = (float) m2.elem[0][0];
+
338  world1.m[0][1] = (float) m2.elem[1][0];
+
339  world1.m[0][2] = (float) m2.elem[2][0];
+
340  world1.m[0][3] = 0.0f;
+
341 
+
342  world1.m[1][0] = (float) m2.elem[0][1];
+
343  world1.m[1][1] = (float) m2.elem[1][1];
+
344  world1.m[1][2] = (float) m2.elem[2][1];
+
345  world1.m[1][3] = 0.0f;
+
346 
+
347  world1.m[2][0] = (float) m2.elem[0][2];
+
348  world1.m[2][1] = (float) m2.elem[1][2];
+
349  world1.m[2][2] = (float) m2.elem[2][2];
+
350  world1.m[2][3] = 0.0f;
+
351 
+
352  world1.m[3][0] = (float) s.Location().x;
+
353  world1.m[3][1] = (float) s.Location().y;
+
354  world1.m[3][2] = (float) s.Location().z;
+
355  world1.m[3][3] = 1.0f;
+
356 
+
357  ListIter<Surface> s1_iter = model->surfaces;
+
358  while (++s1_iter && !contact) {
+
359  Surface* s1 = s1_iter.value();
+
360 
+
361  ListIter<Surface> s2_iter = s.model->surfaces;
+
362  while (++s2_iter && !contact) {
+
363  Surface* s2 = s2_iter.value();
+
364 
+
365  if (s1->opcode && s2->opcode) {
+
366  BVTCache bvt;
+
367  bvt.Model0 = &s1->opcode->model;
+
368  bvt.Model1 = &s2->opcode->model;
+
369 
+
370  if (opcode_collider.Collide(bvt, &world0, &world1))
+
371  if (opcode_collider.GetContactStatus() != 0)
+
372  contact = true;
+
373  }
+
374  }
+
375  }
+
376 
+
377  return contact;
+
378  }
+
379 
+
380 
+
381  return 1;
+
382 }
+
383 
+
384 // +--------------------------------------------------------------------+
+
385 // Find the intersection of the ray (Q + w*len) with the solid.
+
386 // If the ray intersects a polygon of the solid, place the intersection
+
387 // point in ipt, and return 1. Otherwise, return 0.
+
388 
+
389 int
+ +
391 bool treat_translucent_polys_as_solid)
+
392 {
+
393  int impact = 0;
+
394 
+
395  if (!model || model->npolys < 1)
+
396  return impact;
+
397 
+
398  // check right angle spherical distance:
+
399  Point d0 = loc - Q;
+
400  Point d1 = d0.cross(w);
+
401  double dlen = d1.length(); // distance of point from line
+
402 
+
403  if (dlen > radius) // clean miss
+
404  return 0; // (no impact)
+
405 
+
406  // possible collision course...
+
407 
+
408  /**********************************
+
409 
+
410 
+
411  /--- + leading_edge = Q + w * len
+
412  / / \
+
413  delta2 / delta 0
+
414  / / \
+
415  / *........x <- solid location
+
416  / /
+
417  / / delta1
+
418 /--- Q * = closest point
+
419 
+
420 
+
421 ************************************/
+
422 
+
423  // find the point on the ray that is closest
+
424  // to the solid's location:
+
425  Point closest = Q + w * (d0 * w);
+
426 
+
427  // find the leading edge, and it's distance from the location:
+
428  Point leading_edge = Q + w*len;
+
429  Point leading_delta = leading_edge - loc;
+
430  double leading_dist = leading_delta.length();
+
431 
+
432  // if the leading edge is not within the bounding sphere,
+
433  if (leading_dist > radius) {
+
434  // check to see if the closest point is between the
+
435  // ray's endpoints:
+
436  Point delta1 = closest - Q;
+
437  Point delta2 = leading_edge - Q; // this is w*len
+
438 
+
439  // if the closest point is not between the leading edge
+
440  // and the origin, this ray does not intersect:
+
441  if (delta1 * delta2 < 0 || delta1.length() > len) {
+
442  return 0;
+
443  }
+
444  }
+
445 
+
446  // probable hit at this point...
+
447 
+
448  // if not active, that's good enough:
+
449  if (GetScene() == 0) {
+
450  ipt = closest;
+
451  return 1;
+
452  }
+
453 
+
454  // transform ray into object space:
+
455  Matrix xform(Orientation());
+
456 
+
457  Vec3 tmp = w;
+
458 
+
459  w.x = tmp * Vec3(xform(0,0), xform(0,1), xform(0,2));
+
460  w.y = tmp * Vec3(xform(1,0), xform(1,1), xform(1,2));
+
461  w.z = tmp * Vec3(xform(2,0), xform(2,1), xform(2,2));
+
462 
+
463  tmp = Q-loc;
+
464 
+
465  Q.x = tmp * Vec3(xform(0,0), xform(0,1), xform(0,2));
+
466  Q.y = tmp * Vec3(xform(1,0), xform(1,1), xform(1,2));
+
467  Q.z = tmp * Vec3(xform(2,0), xform(2,1), xform(2,2));
+
468 
+
469  double min = len;
+
470  intersection_poly = 0;
+
471 
+
472  // check each polygon:
+
473  ListIter<Surface> iter = model->surfaces;
+
474  while (++iter) {
+
475  Surface* s = iter.value();
+
476  Poly* p = s->GetPolys();
+
477 
+
478  for (int i = 0; i < s->NumPolys(); i++) {
+
479  if (!treat_translucent_polys_as_solid && p->material && !p->material->IsSolid()) {
+
480  p++;
+
481  continue;
+
482  }
+
483 
+
484  Point v = p->plane.normal;
+
485  double d = p->plane.distance;
+
486 
+
487  double denom = w*v;
+
488 
+
489  if (denom < -1.0e-5) {
+
490  Point P = v * d;
+
491  double ilen = ((P-Q)*v)/denom;
+
492 
+
493  if (ilen > 0 && ilen < min) {
+
494  Point intersect = Q + w * ilen;
+
495 
+
496  if (p->Contains(intersect)) {
+
497  intersection_poly = p;
+
498  ipt = intersect;
+
499  min = ilen;
+
500  impact = 1;
+
501  }
+
502  }
+
503  }
+
504 
+
505  p++;
+
506  }
+
507  }
+
508 
+
509  // xform impact point back into world coordinates:
+
510 
+
511  if (impact) {
+
512  ipt = (ipt * Orientation()) + loc;
+
513  }
+
514 
+
515  return impact;
+
516 }
+
517 
+
518 // +--------------------------------------------------------------------+
+
519 
+
520 void
+ +
522 {
+
523  if (own_model && model) {
+
524  delete model;
+
525  model = 0;
+
526  }
+
527 
+
528  radius = 0.0f;
+
529 }
+
530 
+
531 // +--------------------------------------------------------------------+
+
532 
+
533 void
+ +
535 {
+
536  // get rid of the existing model:
+
537  ClearModel();
+
538 
+
539  // point to the new model:
+
540  own_model = 0;
+
541  model = m;
+
542  radius = m->radius;
+
543 }
+
544 
+
545 // +--------------------------------------------------------------------+
+
546 
+
547 bool
+
548 Solid::Load(const char* mag_file, double scale)
+
549 {
+
550  // get ready to load, delete existing model:
+
551  ClearModel();
+
552 
+
553  // loading our own copy, so we own the model:
+
554  model = new(__FILE__,__LINE__) Model;
+
555  own_model = 1;
+
556 
+
557  // now load the model:
+
558  if (model->Load(mag_file, scale)) {
+
559  radius = model->radius;
+
560  strncpy_s(name, model->name, sizeof(name));
+
561  return true;
+
562  }
+
563 
+
564  // load failed:
+
565  ClearModel();
+
566  return false;
+
567 }
+
568 
+
569 bool
+
570 Solid::Load(ModelFile* mod_file, double scale)
+
571 {
+
572  // get ready to load, delete existing model:
+
573  ClearModel();
+
574 
+
575  // loading our own copy, so we own the model:
+
576  model = new(__FILE__,__LINE__) Model;
+
577  own_model = 1;
+
578 
+
579  // now load the model:
+
580  if (model->Load(mod_file, scale)) {
+
581  radius = model->radius;
+
582  return true;
+
583  }
+
584 
+
585  // load failed:
+
586  ClearModel();
+
587  return false;
+
588 }
+
589 
+
590 bool
+
591 Solid::Rescale(double scale)
+
592 {
+
593  if (!own_model || !model)
+
594  return false;
+
595 
+
596  radius = 0;
+
597 
+ +
599  while (++iter) {
+
600  Surface* s = iter.value();
+
601 
+
602  for (int v = 0; v < s->NumVerts(); v++) {
+
603  s->vertex_set->loc[v] *= (float) scale;
+
604  s->vloc[v] *= (float) scale;
+
605 
+
606  float lvi = s->vloc[v].length();
+
607  if (lvi > radius)
+
608  radius = lvi;
+
609  }
+
610  }
+
611 
+
612  model->radius = radius;
+
613 
+ +
615 
+
616  return true;
+
617 }
+
618 
+
619 void
+ +
621 {
+
622  while (shadows.size() < nlights) {
+
623  shadows.append(new(__FILE__,__LINE__) Shadow(this));
+
624  }
+
625 }
+
626 
+
627 void
+ +
629 {
+
630  List<Light> active_lights;
+
631  ListIter<Light> iter = lights;
+
632 
+
633  while (++iter) {
+
634  Light* light = iter.value();
+
635 
+
636  if (light->IsActive() && light->CastsShadow()) {
+
637  double distance = Point(Location() - light->Location()).length();
+
638  double intensity = light->Intensity();
+
639 
+
640  if (light->Type() == Light::LIGHT_POINT) {
+
641  if (intensity / distance > 1)
+
642  active_lights.append(light);
+
643  }
+
644 
+
645  else if (light->Type() == Light::LIGHT_DIRECTIONAL) {
+
646  if (intensity > 0.65)
+
647  active_lights.insert(light);
+
648  }
+
649  }
+
650  }
+
651 
+
652  iter.attach(active_lights);
+
653 
+
654  while (++iter) {
+
655  Light* light = iter.value();
+
656  int index = iter.index();
+
657 
+
658  if (index < shadows.size()) {
+
659  shadows[index]->Update(light);
+
660  }
+
661  }
+
662 }
+
663 
+
664 // +--------------------------------------------------------------------+
+
665 
+
666 void
+ +
668 {
+
669  if (model)
+ +
671 }
+
672 
+
673 // +--------------------------------------------------------------------+
+
674 
+
675 void
+ +
677 {
+
678  if (!model)
+
679  return;
+
680 
+
681  bool invalidate = model->IsDynamic();
+
682 
+ +
684  while (++iter) {
+
685  Surface* s = iter.value();
+ +
687 
+
688  if (vpd) {
+
689  if (invalidate) {
+
690  vpd->Invalidate();
+
691  }
+
692  else {
+
693  delete vpd;
+
694  s->SetVideoPrivateData(0);
+
695  }
+
696  }
+
697  }
+
698 }
+
699 
+
700 void
+ +
702 {
+
703  if (!model)
+
704  return;
+
705 
+
706  bool invalidate = model->IsDynamic();
+
707 
+ +
709  while (++iter) {
+
710  Surface* s = iter.value();
+
711 
+
712  ListIter<Segment> seg_iter = s->GetSegments();
+
713  while (++seg_iter) {
+
714  Segment* segment = seg_iter.value();
+
715  VideoPrivateData* vpd = segment->GetVideoPrivateData();
+
716 
+
717  if (vpd) {
+
718  if (invalidate) {
+
719  vpd->Invalidate();
+
720  }
+
721  else {
+
722  delete vpd;
+
723  segment->SetVideoPrivateData(0);
+
724  }
+
725  }
+
726  }
+
727  }
+
728 }
+
729 
+
730 // +--------------------------------------------------------------------+
+
731 
+
732 bool
+ +
734 {
+
735  if (model)
+
736  return model->IsDynamic();
+
737 
+
738  return false;
+
739 }
+
740 
+
741 void
+ +
743 {
+
744  if (model && own_model)
+
745  model->SetDynamic(d);
+
746 }
+
747 
+
748 // +--------------------------------------------------------------------+
+
749 
+
750 void
+ +
752 {
+
753  if (model)
+
754  model->GetAllTextures(textures);
+
755 }
+
756 
+
757 void
+ +
759 {
+
760  ListIter<Material> m_iter = materials;
+
761  while (++m_iter) {
+
762  Material* m = m_iter.value();
+
763 
+
764  if (m->tex_diffuse && !textures.contains(m->tex_diffuse))
+
765  textures.append(m->tex_diffuse);
+
766 
+
767  if (m->tex_specular && !textures.contains(m->tex_specular))
+
768  textures.append(m->tex_specular);
+
769 
+
770  if (m->tex_emissive && !textures.contains(m->tex_emissive))
+
771  textures.append(m->tex_emissive);
+
772 
+
773  if (m->tex_bumpmap && !textures.contains(m->tex_bumpmap))
+
774  textures.append(m->tex_bumpmap);
+
775 
+
776  if (m->tex_detail && !textures.contains(m->tex_detail))
+
777  textures.append(m->tex_detail);
+
778  }
+
779 }
+
780 
+
781 // +--------------------------------------------------------------------+
+
782 // +--------------------------------------------------------------------+
+
783 // +--------------------------------------------------------------------+
+
784 
+ +
786 : nverts(0), npolys(0), radius(0), luminous(false), dynamic(false)
+
787 {
+
788  ZeroMemory(name, sizeof(name));
+
789 }
+
790 
+ +
792 : nverts(0), npolys(0), radius(0), luminous(false), dynamic(false)
+
793 {
+
794  operator=(m);
+
795 }
+
796 
+
797 // +--------------------------------------------------------------------+
+
798 
+ +
800 {
+
801  surfaces.destroy();
+
802  materials.destroy();
+
803 }
+
804 
+
805 Model&
+ +
807 {
+
808  if (this != &m) {
+
809  surfaces.destroy();
+
810  materials.destroy();
+
811 
+
812  CopyMemory(name, m.name, Solid::NAMELEN);
+
813 
+
814  nverts = m.nverts;
+
815  npolys = m.npolys;
+
816  radius = m.radius;
+
817  luminous = m.luminous;
+
818  dynamic = m.dynamic;
+
819 
+
820  Model* pmod = (Model*) &m;
+
821 
+
822  ListIter<Material> m_iter = pmod->materials;
+
823  while (++m_iter) {
+
824  Material* matl1 = m_iter.value();
+
825  Material* matl2 = new(__FILE__,__LINE__) Material;
+
826 
+
827  CopyMemory(matl2, matl1, sizeof(Material));
+
828  matl2->thumbnail = 0;
+
829 
+
830  materials.append(matl2);
+
831  }
+
832 
+
833  ListIter<Surface> s_iter = pmod->surfaces;
+
834  while (++s_iter) {
+
835  Surface* surf1 = s_iter.value();
+
836  Surface* surf2 = new(__FILE__,__LINE__) Surface;
+
837 
+
838  surf2->Copy(*surf1, this);
+
839  surfaces.append(surf2);
+
840  }
+
841  }
+
842 
+
843  return *this;
+
844 }
+
845 
+
846 // +--------------------------------------------------------------------+
+
847 
+
848 int
+ +
850 {
+
851  int nsegments = 0;
+
852 
+
853  for (int i = 0; i < surfaces.size(); i++) {
+
854  const Surface* s = surfaces[i];
+
855  nsegments += s->NumSegments();
+
856  }
+
857 
+
858  return nsegments;
+
859 }
+
860 
+
861 // +--------------------------------------------------------------------+
+
862 
+
863 inline bool Collinear(const double* a, const double* b, const double* c)
+
864 {
+
865  Point ab(b[0]-a[0], b[1]-a[1], b[2]-a[2]);
+
866  Point ac(c[0]-a[0], c[1]-a[1], c[2]-a[2]);
+
867  Point cross = ab.cross(ac);
+
868  return (cross.length() == 0);
+
869 }
+
870 
+
871 struct HomogenousPlane
+
872 {
+
873  double distance;
+
874  double normal_x;
+
875  double normal_y;
+
876  double normal_z;
+
877  double normal_w;
+
878 };
+
879 
+
880 static void LoadPlane(Plane& p, DataLoader* l, BYTE*& fp)
+
881 {
+
882  HomogenousPlane tmp;
+
883  l->fread(&tmp, sizeof(HomogenousPlane), 1, fp);
+
884 }
+
885 
+
886 static void LoadFlags(LPDWORD flags, DataLoader* l, BYTE*& fp)
+
887 {
+
888  DWORD magic_flags;
+
889  l->fread(&magic_flags, sizeof(DWORD), 1, fp);
+
890 
+
902  const DWORD magic_mask = 0x0fc3;
+
903 
+
904  *flags = magic_flags & magic_mask;
+
905 }
+
906 
+
907 // +--------------------------------------------------------------------+
+
908 
+
909 bool
+
910 Model::Load(const char* mag_file, double scale)
+
911 {
+
912  BYTE* block;
+
913  DataLoader* loader = DataLoader::GetLoader();
+
914  bool result = false;
+
915 
+
916  radius = 0.0f;
+
917  extents[0] = 0.0f;
+
918  extents[1] = 0.0f;
+
919  extents[2] = 0.0f;
+
920  extents[3] = 0.0f;
+
921  extents[4] = 0.0f;
+
922  extents[5] = 0.0f;
+
923 
+
924  if (!loader) {
+
925  Print("MAG Open Failed: no data loader for file '%s'\n", mag_file);
+
926  return result;
+
927  }
+
928 
+
929  int size = loader->LoadBuffer(mag_file, block);
+
930  BYTE* fp = block;
+
931 
+
932  // check MAG file:
+
933  if (!size) {
+
934  Print("MAG Open Failed: could not open file '%s'\n", mag_file);
+
935  return result;
+
936  }
+
937 
+
938  strncpy_s(name, mag_file, 31);
+
939  name[31] = 0;
+
940 
+
941  char file_id[5];
+
942  CopyMemory(file_id, block, 4);
+
943  file_id[4] = '\0';
+
944  int version = 1;
+
945 
+
946  if (!strcmp(file_id, "MAG6")) {
+
947  version = 6;
+
948  }
+
949  else if (!strcmp(file_id, "MAG5")) {
+
950  version = 5;
+
951  }
+
952  else if (!strcmp(file_id, "MAG4")) {
+
953  version = 4;
+
954  }
+
955  else {
+
956  Print("MAG Open Failed: File '%s' Invalid file type '%s'\n", mag_file, file_id);
+
957  loader->ReleaseBuffer(block);
+
958  return result;
+
959  }
+
960 
+
961  // get ready to load, delete existing model:
+
962  surfaces.destroy();
+
963  materials.destroy();
+
964  nverts = 0;
+
965  npolys = 0;
+
966 
+
967  // now load the model:
+
968  switch (version) {
+
969  case 4:
+
970  case 5:
+
971  result = LoadMag5(block, size, scale);
+
972  break;
+
973 
+
974  case 6:
+
975  result = LoadMag6(block, size, scale);
+
976  break;
+
977 
+
978  default:
+
979  break;
+
980  }
+
981 
+
982  loader->ReleaseBuffer(block);
+
983  return result;
+
984 }
+
985 
+
986 // +--------------------------------------------------------------------+
+
987 
+
988 bool
+
989 Model::Load(ModelFile* mod_file, double scale)
+
990 {
+
991  if (mod_file) {
+
992  return mod_file->Load(this, scale);
+
993  }
+
994 
+
995  return false;
+
996 }
+
997 
+
998 // +--------------------------------------------------------------------+
+
999 
+
1000 static int mcomp(const void* a, const void* b)
+
1001 {
+
1002  Poly* pa = (Poly*) a;
+
1003  Poly* pb = (Poly*) b;
+
1004 
+
1005  if (pa->sortval == pb->sortval)
+
1006  return 0;
+
1007 
+
1008  if (pa->sortval < pb->sortval)
+
1009  return 1;
+
1010 
+
1011  return -1;
+
1012 }
+
1013 
+
1014 bool
+
1015 Model::LoadMag5(BYTE* block, int len, double scale)
+
1016 {
+
1017  bool result = false;
+
1018 
+
1019  DataLoader* loader = DataLoader::GetLoader();
+
1020  BYTE* fp = block + 4;
+
1021  int ntex = 0;
+
1022  int nsurfs = 0;
+
1023 
+
1024  loader->fread(&ntex, sizeof(ntex), 1, fp);
+
1025  loader->fread(&nsurfs, sizeof(nsurfs), 1, fp);
+
1026 
+
1027  // create a default gray material:
+
1028  Material* mtl = new Material;
+
1029 
+
1030  if (mtl) {
+
1031  mtl->Ka = Color::LightGray;
+
1032  mtl->Kd = Color::LightGray;
+
1033  mtl->Ks = ColorValue(0.2f,0.2f,0.2f);
+
1034  mtl->power = 20.0f;
+
1035 
+
1036  mtl->ambient_value = 1.0f;
+ +
1038  mtl->diffuse_value = 1.0f;
+ +
1040  mtl->specular_value = 0.2f;
+ +
1042  strcpy_s(mtl->name, "(default)");
+
1043 
+
1044  materials.append(mtl);
+
1045  }
+
1046 
+
1047  // read texture list:
+
1048  for (int i = 0; i < ntex; i++) {
+
1049  mtl = new(__FILE__,__LINE__) Material;
+
1050  char tname[32];
+
1051 
+
1052  if (mtl) {
+
1053  mtl->Ka = ColorValue(0.5f,0.5f,0.5f);
+
1054  mtl->Kd = ColorValue(1.0f,1.0f,1.0f);
+
1055  mtl->Ks = ColorValue(0.2f,0.2f,0.2f);
+
1056  mtl->power = 20.0f;
+
1057 
+
1058  mtl->ambient_value = 1.0f;
+
1059  mtl->ambient_color = Color::Gray;
+
1060  mtl->diffuse_value = 1.0f;
+
1061  mtl->diffuse_color = Color::White;
+
1062  mtl->specular_value = 0.2f;
+ +
1064 
+
1065  loader->fread(tname, 32, 1, fp);
+
1066  loader->LoadTexture(tname, mtl->tex_diffuse, Bitmap::BMP_SOLID, true);
+
1067  strcpy_s(mtl->name, tname);
+
1068 
+
1069  char* dot = strrchr(mtl->name, '.');
+
1070  if (dot)
+
1071  *dot = 0;
+
1072 
+
1073  char* plus = strrchr(mtl->name, '+');
+
1074  if (plus)
+
1075  *plus = 0;
+
1076 
+
1077  materials.append(mtl);
+
1078  }
+
1079  }
+
1080 
+
1081 
+
1082  loader->fread(&nverts, 4, 1, fp);
+
1083  loader->fread(&npolys, 4, 1, fp);
+
1084 
+
1085  // plan on creating four verts per poly:
+
1086  int mag_nverts = nverts;
+
1087  int next_vert = nverts;
+
1088 
+
1089  nverts = npolys * 4;
+
1090 
+
1091  Surface* s = new(__FILE__,__LINE__) Surface;
+
1092  VertexSet* vset = 0;
+
1093 
+
1094  if (s) {
+
1095  strcpy_s(s->name, "default");
+
1096 
+
1097  s->model = this;
+
1098  s->vertex_set = new(__FILE__,__LINE__) VertexSet(nverts);
+
1099  s->vloc = new(__FILE__,__LINE__) Vec3[nverts];
+
1100 
+
1101  ZeroMemory(s->vertex_set->loc, nverts * sizeof(Vec3));
+
1102  ZeroMemory(s->vertex_set->diffuse, nverts * sizeof(DWORD));
+
1103  ZeroMemory(s->vertex_set->specular, nverts * sizeof(DWORD));
+
1104  ZeroMemory(s->vertex_set->tu, nverts * sizeof(float));
+
1105  ZeroMemory(s->vertex_set->tv, nverts * sizeof(float));
+
1106  ZeroMemory(s->vertex_set->rw, nverts * sizeof(float));
+
1107  ZeroMemory(s->vloc, nverts * sizeof(Vec3));
+
1108 
+
1109  s->npolys = npolys;
+
1110  s->polys = new(__FILE__,__LINE__) Poly[npolys];
+
1111 
+
1112  ZeroMemory(s->polys, sizeof(Poly) * npolys);
+
1113  surfaces.append(s);
+
1114 
+
1115  vset = s->vertex_set;
+
1116 
+
1117  int v;
+
1118  // read vertex set:
+
1119  for (v = 0; v < mag_nverts; v++) {
+
1120  Vec3 vert, norm;
+
1121  DWORD vstate;
+
1122 
+
1123  loader->fread(&vert, sizeof(Vec3), 1, fp);
+
1124  loader->fread(&norm, sizeof(Vec3), 1, fp);
+
1125  loader->fread(&vstate, sizeof(DWORD), 1, fp);
+
1126 
+
1127  vert.SwapYZ();
+
1128  vert *= (float) scale;
+
1129 
+
1130  vset->loc[v] = vert;
+
1131  vset->nrm[v] = norm;
+
1132 
+
1133  double d = vert.length();
+
1134  if (d > radius)
+
1135  radius = (float) d;
+
1136 
+
1137  if (vert.x > extents[0]) extents[0] = vert.x;
+
1138  if (vert.x < extents[1]) extents[1] = vert.x;
+
1139  if (vert.y > extents[2]) extents[2] = vert.y;
+
1140  if (vert.y < extents[3]) extents[3] = vert.y;
+
1141  if (vert.z > extents[4]) extents[4] = vert.z;
+
1142  if (vert.z < extents[5]) extents[5] = vert.z;
+
1143  }
+
1144 
+
1145  while (v < nverts)
+
1146  vset->nrm[v++] = Vec3(1,0,0);
+
1147 
+
1148  // read polys:
+
1149  Vec3 dummy_center;
+
1150  DWORD dummy_flags;
+
1151  DWORD dummy_color;
+
1152  Plane dummy_plane;
+
1153  int texture_num;
+
1154  int poly_nverts;
+
1155  int vert_index_buffer[32];
+
1156  float texture_index_buffer[32];
+
1157 
+
1158  for (int n = 0; n < npolys; n++) {
+
1159  Poly& poly = s->polys[n];
+
1160  poly.vertex_set = vset;
+
1161 
+
1162  loader->fread(&dummy_flags, sizeof(DWORD), 1, fp);
+
1163  loader->fread(&dummy_center, sizeof(Vec3), 1, fp);
+
1164 
+
1165  LoadPlane(dummy_plane, loader, fp);
+
1166 
+
1167  loader->fread(&dummy_color, sizeof(DWORD), 1, fp);
+
1168  loader->fread(&texture_num, sizeof(int), 1, fp);
+
1169 
+
1170  if (texture_num >= 0 && texture_num < ntex) {
+
1171  int mtl_num = texture_num + 1;
+
1172  poly.material = materials[mtl_num];
+
1173  poly.sortval = texture_num;
+
1174 
+
1175  bool flag_translucent = (dummy_flags & 0x04) ? true : false;
+
1176  bool flag_transparent = (dummy_flags & 0x08) ? true : false;
+
1177 
+
1178  // luminous
+
1179  if (dummy_flags & 2) {
+
1180  mtl = materials[mtl_num];
+
1181 
+
1182  mtl->Ka = ColorValue(0,0,0,0);
+
1183  mtl->Kd = ColorValue(0,0,0,0);
+
1184  mtl->Ks = ColorValue(0,0,0,0);
+
1185  mtl->Ke = ColorValue(1,1,1,1);
+
1186 
+
1187  mtl->tex_emissive = mtl->tex_diffuse;
+
1188  }
+
1189 
+
1190  // glowing (additive)
+
1191  if (flag_translucent && flag_transparent)
+
1192  materials[mtl_num]->blend = Material::MTL_ADDITIVE;
+
1193 
+
1194  // translucent (alpha)
+
1195  else if (flag_translucent)
+
1196  materials[mtl_num]->blend = Material::MTL_TRANSLUCENT;
+
1197 
+
1198  // transparent (just use alpha for this)
+
1199  else if (flag_transparent)
+
1200  materials[mtl_num]->blend = Material::MTL_TRANSLUCENT;
+
1201  }
+
1202  else {
+
1203  poly.material = materials.first();
+
1204  poly.sortval = 1000;
+
1205  }
+
1206 
+
1207  // hack: store flat shaded flag in unused visible byte
+
1208  poly.visible = (BYTE) (dummy_flags & 1);
+
1209 
+
1210  loader->fread(&poly_nverts, sizeof(int), 1, fp);
+
1211  loader->fread(vert_index_buffer, sizeof(int), poly_nverts, fp);
+
1212 
+
1213  if (poly_nverts == 3)
+
1214  s->nindices += 3;
+
1215 
+
1216  else if (poly_nverts == 4)
+
1217  s->nindices += 6;
+
1218 
+
1219  poly.nverts = poly_nverts;
+
1220  for (int vi = 0; vi < poly_nverts; vi++) {
+
1221  v = vert_index_buffer[vi];
+
1222 
+
1223  if (vset->rw[v] > 0) {
+
1224  vset->CopyVertex(next_vert, v);
+
1225  v = next_vert++;
+
1226  }
+
1227 
+
1228  vset->rw[v] = 1;
+
1229  poly.verts[vi] = v;
+
1230  }
+
1231 
+
1232  loader->fread(texture_index_buffer, sizeof(float), poly_nverts, fp); // tu's
+
1233  for (int vi = 0; vi < poly_nverts; vi++) {
+
1234  v = poly.verts[vi];
+
1235  vset->tu[v] = texture_index_buffer[vi];
+
1236  }
+
1237 
+
1238  loader->fread(texture_index_buffer, sizeof(float), poly_nverts, fp); // tv's
+
1239  for (int vi = 0; vi < poly_nverts; vi++) {
+
1240  v = poly.verts[vi];
+
1241  vset->tv[v] = texture_index_buffer[vi];
+
1242  }
+
1243 
+
1244  fp += 16;
+
1245  }
+
1246 
+
1247  // pass 2 (adjust vertex normals for flat polys):
+
1248  for (int n = 0; n < npolys; n++) {
+
1249  Poly& poly = s->polys[n];
+
1250  poly.plane = Plane(vset->loc[poly.verts[0]],
+
1251  vset->loc[poly.verts[2]],
+
1252  vset->loc[poly.verts[1]]);
+
1253 
+
1254  // hack: retrieve flat shaded flag from unused visible byte
+
1255  if (poly.visible) {
+
1256  poly_nverts = poly.nverts;
+
1257 
+
1258  for (int vi = 0; vi < poly_nverts; vi++) {
+
1259  v = poly.verts[vi];
+
1260  vset->nrm[v] = poly.plane.normal;
+
1261  }
+
1262  }
+
1263  }
+
1264 
+
1265  // sort the polys by material index:
+
1266  qsort((void*) s->polys, s->npolys, sizeof(Poly), mcomp);
+
1267 
+
1268  // then assign them to cohesive segments:
+
1269  Segment* segment = 0;
+
1270 
+
1271  for (int n = 0; n < npolys; n++) {
+
1272  if (segment && segment->material == s->polys[n].material) {
+
1273  segment->npolys++;
+
1274  }
+
1275  else {
+
1276  segment = 0;
+
1277  }
+
1278 
+
1279  if (!segment) {
+
1280  segment = new(__FILE__,__LINE__) Segment;
+
1281 
+
1282  segment->npolys = 1;
+
1283  segment->polys = &s->polys[n];
+
1284  segment->material = segment->polys->material;
+
1285  segment->model = this;
+
1286 
+
1287  s->segments.append(segment);
+
1288  }
+
1289  }
+
1290 
+
1291  s->BuildHull();
+
1292 
+
1293  result = nverts && npolys;
+
1294  }
+
1295 
+
1296  return result;
+
1297 }
+
1298 
+
1299 // +--------------------------------------------------------------------+
+
1300 
+
1301 struct MaterialMag6 {
+
1302  char name[Material::NAMELEN];
+
1303  char shader[Material::NAMELEN];
+
1304  float power; // highlight sharpness (big=shiny)
+
1305  float brilliance; // diffuse power function
+
1306  float bump; // bump level (0=none)
+
1307  DWORD blend; // alpha blend type
+
1308  bool shadow; // material casts shadow
+
1309  bool luminous; // verts have their own lighting
+
1310 
+ + + + +
1315 
+
1316  float ambient_value;
+
1317  float diffuse_value;
+
1318  float specular_value;
+
1319  float emissive_value;
+
1320 
+
1321  BYTE tex_diffuse;
+
1322  BYTE tex_specular;
+
1323  BYTE tex_bumpmap;
+
1324  BYTE tex_emissive;
+
1325 };
+
1326 
+
1327 // +--------------------------------------------------------------------+
+
1328 
+
1329 bool
+
1330 Model::LoadMag6(BYTE* block, int len, double scale)
+
1331 {
+
1332  bool result = false;
+
1333 
+
1334  DataLoader* loader = DataLoader::GetLoader();
+
1335  BYTE* fp = block + 4;
+
1336  int ntex = 0;
+
1337  int nmtls = 0;
+
1338  int nsurfs = 0;
+
1339  List<Bitmap> textures;
+
1340 
+
1341  loader->fread(&ntex, sizeof(ntex), 1, fp); // size of texture block
+
1342  loader->fread(&nmtls, sizeof(nmtls), 1, fp); // number of materials
+
1343  loader->fread(&nsurfs, sizeof(nsurfs), 1, fp); // number of surfaces
+
1344 
+
1345  // read texture list:
+
1346  if (ntex) {
+
1347  char* buffer = new(__FILE__,__LINE__) char[ntex];
+
1348  char* p = buffer;
+
1349  Bitmap* bmp = 0;
+
1350 
+
1351  loader->fread(buffer, ntex, 1, fp);
+
1352 
+
1353  while (p < buffer + ntex) {
+
1354  loader->LoadTexture(p, bmp, Bitmap::BMP_SOLID, true);
+
1355  textures.append(bmp);
+
1356 
+
1357  p += strlen(p) + 1;
+
1358  }
+
1359 
+
1360  delete [] buffer;
+
1361  }
+
1362 
+
1363  for (int i = 0; i < nmtls; i++) {
+
1364  MaterialMag6 m6;
+
1365  Material* mtl = new(__FILE__,__LINE__) Material;
+
1366 
+
1367  loader->fread(&m6, sizeof(m6), 1, fp);
+
1368 
+
1369  if (mtl) {
+
1370  CopyMemory(mtl->name, m6.name, Material::NAMELEN);
+
1371  CopyMemory(mtl->shader, m6.shader, Material::NAMELEN);
+
1372 
+
1373  mtl->ambient_value = m6.ambient_value;
+
1374  mtl->ambient_color = m6.ambient_color;
+
1375  mtl->diffuse_value = m6.diffuse_value;
+
1376  mtl->diffuse_color = m6.diffuse_color;
+
1377  mtl->specular_value = m6.specular_value;
+
1378  mtl->specular_color = m6.specular_color;
+
1379  mtl->emissive_value = m6.emissive_value;
+
1380  mtl->emissive_color = m6.emissive_color;
+
1381 
+
1382  mtl->Ka = ColorValue(mtl->ambient_color) * mtl->ambient_value;
+
1383  mtl->Kd = ColorValue(mtl->diffuse_color) * mtl->diffuse_value;
+
1384  mtl->Ks = ColorValue(mtl->specular_color) * mtl->specular_value;
+
1385  mtl->Ke = ColorValue(mtl->emissive_color) * mtl->emissive_value;
+
1386 
+
1387  mtl->power = m6.power;
+
1388  mtl->brilliance = m6.brilliance;
+
1389  mtl->bump = m6.bump;
+
1390  mtl->blend = m6.blend;
+
1391  mtl->shadow = m6.shadow;
+
1392  mtl->luminous = m6.luminous;
+
1393 
+
1394  if (m6.tex_diffuse && m6.tex_diffuse <= textures.size())
+
1395  mtl->tex_diffuse = textures[m6.tex_diffuse - 1];
+
1396 
+
1397  if (m6.tex_specular && m6.tex_specular <= textures.size())
+
1398  mtl->tex_specular = textures[m6.tex_specular - 1];
+
1399 
+
1400  if (m6.tex_emissive && m6.tex_emissive <= textures.size())
+
1401  mtl->tex_emissive = textures[m6.tex_emissive - 1];
+
1402 
+
1403  if (m6.tex_bumpmap && m6.tex_bumpmap <= textures.size())
+
1404  mtl->tex_bumpmap = textures[m6.tex_bumpmap - 1];
+
1405 
+
1406  materials.append(mtl);
+
1407  }
+
1408  }
+
1409 
+
1410  for (int i = 0; i < nsurfs; i++) {
+
1411  int nverts = 0;
+
1412  int npolys = 0;
+
1413  BYTE namelen = 0;
+
1414  char name[128];
+
1415 
+
1416  loader->fread(&nverts, 4, 1, fp);
+
1417  loader->fread(&npolys, 4, 1, fp);
+
1418  loader->fread(&namelen, 1, 1, fp);
+
1419  loader->fread(name, 1, namelen, fp);
+
1420 
+
1421  Surface* surface = new(__FILE__,__LINE__) Surface;
+
1422  surface->model = this;
+
1423  surface->SetName(name);
+
1424  surface->CreateVerts(nverts);
+
1425  surface->CreatePolys(npolys);
+
1426 
+
1427  VertexSet* vset = surface->GetVertexSet();
+
1428  Poly* polys = surface->GetPolys();
+
1429 
+
1430  ZeroMemory(polys, sizeof(Poly) * npolys);
+
1431 
+
1432  // read vertex set:
+
1433  for (int v = 0; v < nverts; v++) {
+
1434  loader->fread(&vset->loc[v], sizeof(float), 3, fp);
+
1435  loader->fread(&vset->nrm[v], sizeof(float), 3, fp);
+
1436  loader->fread(&vset->tu[v], sizeof(float), 1, fp);
+
1437  loader->fread(&vset->tv[v], sizeof(float), 1, fp);
+
1438 
+
1439  vset->loc[v] *= (float) scale;
+
1440 
+
1441  Vec3 vert = vset->loc[v];
+
1442 
+
1443  double d = vert.length();
+
1444  if (d > radius)
+
1445  radius = (float) d;
+
1446 
+
1447  if (vert.x > extents[0]) extents[0] = vert.x;
+
1448  if (vert.x < extents[1]) extents[1] = vert.x;
+
1449  if (vert.y > extents[2]) extents[2] = vert.y;
+
1450  if (vert.y < extents[3]) extents[3] = vert.y;
+
1451  if (vert.z > extents[4]) extents[4] = vert.z;
+
1452  if (vert.z < extents[5]) extents[5] = vert.z;
+
1453  }
+
1454 
+
1455  // read polys:
+
1456  for (int n = 0; n < npolys; n++) {
+
1457  Poly& poly = polys[n];
+
1458  BYTE poly_nverts = 0;
+
1459  BYTE material_index = 0;
+
1460  WORD poly_verts[8];
+
1461 
+
1462  loader->fread(&poly_nverts, sizeof(BYTE), 1, fp);
+
1463  loader->fread(&material_index, sizeof(BYTE), 1, fp);
+
1464  loader->fread(&poly_verts[0], sizeof(WORD), poly_nverts, fp);
+
1465 
+
1466  if (poly_nverts >= 3) {
+
1467  poly.nverts = poly_nverts;
+
1468 
+
1469  for (int i = 0; i < poly_nverts; i++) {
+
1470  poly.verts[i] = poly_verts[i];
+
1471  }
+
1472  }
+
1473  else {
+
1474  poly.sortval = 666;
+
1475  }
+
1476 
+
1477  if (material_index > 0) {
+
1478  poly.material = materials[material_index-1];
+
1479  poly.sortval = material_index;
+
1480  }
+
1481  else if (materials.size()) {
+
1482  poly.material = materials.first();
+
1483  poly.sortval = 1;
+
1484  }
+
1485  else {
+
1486  poly.sortval = 1000;
+
1487  }
+
1488 
+
1489  if (poly.nverts == 3)
+
1490  surface->AddIndices(3);
+
1491 
+
1492  else if (poly.nverts == 4)
+
1493  surface->AddIndices(6);
+
1494 
+
1495  poly.vertex_set = vset;
+
1496  poly.plane = Plane(vset->loc[poly.verts[0]],
+
1497  vset->loc[poly.verts[2]],
+
1498  vset->loc[poly.verts[1]]);
+
1499  }
+
1500 
+
1501  // sort the polys by material index:
+
1502  qsort((void*) polys, npolys, sizeof(Poly), mcomp);
+
1503 
+
1504  // then assign them to cohesive segments:
+
1505  Segment* segment = 0;
+
1506 
+
1507  for (int n = 0; n < npolys; n++) {
+
1508  if (segment && segment->material == polys[n].material) {
+
1509  segment->npolys++;
+
1510  }
+
1511  else {
+
1512  segment = 0;
+
1513  }
+
1514 
+
1515  if (!segment) {
+
1516  segment = new(__FILE__,__LINE__) Segment;
+
1517 
+
1518  segment->npolys = 1;
+
1519  segment->polys = &polys[n];
+
1520  segment->material = segment->polys->material;
+
1521  segment->model = this;
+
1522 
+
1523  surface->GetSegments().append(segment);
+
1524  }
+
1525  }
+
1526 
+
1527  surface->BuildHull();
+
1528  surfaces.append(surface);
+
1529 
+
1530  this->nverts += nverts;
+
1531  this->npolys += npolys;
+
1532  }
+
1533 
+
1534 
+
1535  result = nverts && npolys;
+
1536  return result;
+
1537 }
+
1538 
+
1539 void
+ +
1541 {
+
1542  if (surface) {
+
1543  surface->model = this;
+
1544 
+
1545  ListIter<Segment> iter = surface->segments;
+
1546  while (++iter) {
+
1547  Segment* segment = iter.value();
+
1548  segment->model = this;
+
1549  }
+
1550 
+
1551  surface->BuildHull();
+
1552  surfaces.append(surface);
+
1553 
+
1554  nverts += surface->NumVerts();
+
1555  npolys += surface->NumPolys();
+
1556  }
+
1557 }
+
1558 
+
1559 
+
1560 // +--------------------------------------------------------------------+
+
1561 
+
1562 const Material*
+
1563 Model::FindMaterial(const char* mtl_name) const
+
1564 {
+
1565  if (mtl_name && *mtl_name) {
+
1566  Model* pThis = (Model*) this;
+
1567 
+
1568  ListIter<Material> iter = pThis->materials;
+
1569  while (++iter) {
+
1570  Material* mtl = iter.value();
+
1571 
+
1572  if (!strcmp(mtl->name, mtl_name))
+
1573  return mtl;
+
1574  }
+
1575  }
+
1576 
+
1577  return 0;
+
1578 }
+
1579 
+
1580 const Material*
+ +
1582 {
+
1583  const Material* mtl_orig = 0;
+
1584 
+
1585  if (mtl) {
+
1586  mtl_orig = FindMaterial(mtl->name);
+
1587 
+
1588  if (mtl_orig) {
+
1589  int n = materials.index(mtl_orig);
+
1590  materials[n] = (Material*) mtl;
+
1591 
+
1592  ListIter<Surface> surf_iter = surfaces;
+
1593  while (++surf_iter) {
+
1594  Surface* surf = surf_iter.value();
+
1595 
+
1596  ListIter<Segment> seg_iter = surf->GetSegments();
+
1597  while (++seg_iter) {
+
1598  Segment* segment = seg_iter.value();
+
1599 
+
1600  if (segment->material == mtl_orig)
+
1601  segment->material = (Material*) mtl;
+
1602  }
+
1603  }
+
1604  }
+
1605  }
+
1606 
+
1607  return mtl_orig;
+
1608 }
+
1609 
+
1610 // +--------------------------------------------------------------------+
+
1611 
+
1612 Poly*
+
1613 Model::AddPolys(int nsurf, int np, int nv)
+
1614 {
+
1615  if (nsurf >= 0 && nsurf < surfaces.size())
+
1616  return surfaces[nsurf]->AddPolys(np, nv);
+
1617 
+
1618  ::Print("WARNING: AddPolys(%d,%d,%d) invalid surface\n", nsurf, np, nv);
+
1619  return 0;
+
1620 }
+
1621 
+
1622 // +--------------------------------------------------------------------+
+
1623 
+
1624 void
+ +
1626 {
+
1627  ListIter<Surface> iter = surfaces;
+
1628 
+
1629  int nv = 0;
+
1630  int np = 0;
+
1631 
+
1632  while (++iter) {
+
1633  Surface* s = iter.value();
+
1634  s->ExplodeMesh();
+
1635 
+
1636  nv += s->NumVerts();
+
1637  np += s->NumPolys();
+
1638  }
+
1639 
+
1640  nverts = nv;
+
1641  npolys = np;
+
1642 }
+
1643 
+
1644 // +--------------------------------------------------------------------+
+
1645 
+
1646 void
+ +
1648 {
+
1649  ListIter<Surface> iter = surfaces;
+
1650 
+
1651  int nv = 0;
+
1652  int np = 0;
+
1653 
+
1654  while (++iter) {
+
1655  Surface* s = iter.value();
+
1656  s->OptimizeMesh();
+
1657 
+
1658  nv += s->NumVerts();
+
1659  np += s->NumPolys();
+
1660  }
+
1661 
+
1662  nverts = nv;
+
1663  npolys = np;
+
1664 }
+
1665 
+
1666 // +--------------------------------------------------------------------+
+
1667 
+
1668 void
+ +
1670 {
+
1671  for (int i = 0; i < materials.size(); i++) {
+
1672  Material* m1 = materials[i];
+
1673 
+
1674  for (int n = i; n < materials.size(); n++) {
+
1675  Material* m2 = materials[n];
+
1676 
+
1677  // if they match, merge them:
+
1678  if (*m1 == *m2) {
+
1679  List<Poly> polys;
+
1680  SelectPolys(polys, m2);
+
1681 
+
1682  ListIter<Poly> iter = polys;
+
1683  while (++iter) {
+
1684  Poly* p = iter.value();
+
1685  p->material = m1;
+
1686  }
+
1687 
+
1688  // and discard the duplicate:
+
1689  materials.remove(m2);
+
1690  delete m2;
+
1691  }
+
1692  }
+
1693  }
+
1694 }
+
1695 
+
1696 void
+
1697 Model::ScaleBy(double factor)
+
1698 {
+
1699  ListIter<Surface> iter = surfaces;
+
1700 
+
1701  while (++iter) {
+
1702  Surface* s = iter.value();
+
1703  s->ScaleBy(factor);
+
1704  }
+
1705 }
+
1706 
+
1707 // +--------------------------------------------------------------------+
+
1708 
+
1709 void
+ +
1711 {
+
1712  ListIter<Surface> iter = surfaces;
+
1713 
+
1714  while (++iter) {
+
1715  Surface* s = iter.value();
+
1716  s->Normalize();
+
1717  }
+
1718 }
+
1719 
+
1720 void
+ +
1722 {
+
1723  ListIter<Surface> iter = surfaces;
+
1724 
+
1725  while (++iter) {
+
1726  Surface* s = iter.value();
+
1727  s->SelectPolys(polys, loc);
+
1728  }
+
1729 }
+
1730 
+
1731 void
+ +
1733 {
+
1734  ListIter<Surface> iter = surfaces;
+
1735 
+
1736  while (++iter) {
+
1737  Surface* s = iter.value();
+
1738  s->SelectPolys(polys, m);
+
1739  }
+
1740 }
+
1741 
+
1742 void
+ +
1744 {
+
1745  ListIter<Surface> iter = surfaces;
+
1746 
+
1747  while (++iter) {
+
1748  Surface* s = iter.value();
+
1749  s->ComputeTangents();
+
1750  }
+
1751 }
+
1752 
+
1753 // +--------------------------------------------------------------------+
+
1754 
+
1755 void
+ +
1757 {
+
1758  ListIter<Surface> iter = surfaces;
+
1759  while (++iter) {
+
1760  Surface* s = iter.value();
+ +
1762 
+
1763  if (vpd) {
+
1764  delete vpd;
+
1765  s->SetVideoPrivateData(0);
+
1766  }
+
1767 
+
1768  ListIter<Segment> seg_iter = s->GetSegments();
+
1769  while (++seg_iter) {
+
1770  Segment* segment = seg_iter.value();
+
1771  VideoPrivateData* vpdp = segment->video_data;
+
1772 
+
1773  if (vpdp) {
+
1774  delete vpdp;
+
1775  segment->video_data = 0;
+
1776  }
+
1777  }
+
1778  }
+
1779 }
+
1780 
+
1781 // +--------------------------------------------------------------------+
+
1782 // +--------------------------------------------------------------------+
+
1783 // +--------------------------------------------------------------------+
+
1784 
+ +
1786 : model(0), vertex_set(0), vloc(0), nhull(0), npolys(0), nindices(0),
+
1787 polys(0), state(0), video_data(0), opcode(0)
+
1788 {
+
1789  ZeroMemory(name, sizeof(name));
+
1790 }
+
1791 
+ +
1793 {
+
1794  segments.destroy();
+
1795 
+
1796  delete opcode;
+
1797  delete vertex_set;
+
1798  delete [] vloc;
+
1799  delete [] polys;
+
1800  delete video_data;
+
1801 
+
1802  model = 0;
+
1803 }
+
1804 
+
1805 // +--------------------------------------------------------------------+
+
1806 
+
1807 void
+ +
1809 {
+
1810  segments.destroy();
+
1811 
+
1812  delete opcode;
+
1813  delete vertex_set;
+
1814  delete [] vloc;
+
1815  delete [] polys;
+
1816  delete video_data;
+
1817 
+
1818  CopyMemory(name, s.name, Solid::NAMELEN);
+
1819 
+
1820  model = m;
+
1821  radius = s.radius;
+
1822  nhull = s.nhull;
+
1823  npolys = s.npolys;
+
1824  nindices = s.nindices;
+
1825  state = s.state;
+
1826  offset = s.offset;
+
1827  orientation = s.orientation;
+
1828  opcode = 0;
+
1829  video_data = 0;
+
1830 
+
1831  vertex_set = s.vertex_set->Clone();
+
1832 
+
1833  if (nhull > 0) {
+
1834  vloc = new(__FILE__,__LINE__) Vec3[nhull];
+
1835  CopyMemory(vloc, s.vloc, nhull * sizeof(Vec3));
+
1836  }
+
1837  else {
+
1838  vloc = 0;
+
1839  }
+
1840 
+
1841  polys = new(__FILE__,__LINE__) Poly[npolys];
+
1842  CopyMemory(polys, s.polys, npolys * sizeof(Poly));
+
1843 
+
1844  for (int i = 0; i < npolys; i++) {
+
1845  polys[i].vertex_set = vertex_set;
+
1846 
+
1847  if (s.polys[i].material)
+
1848  polys[i].material = (Material*) model->FindMaterial(s.polys[i].material->name);
+
1849  }
+
1850 
+
1851  ListIter<Segment> iter = s.segments;
+
1852  while (++iter) {
+
1853  Segment* seg1 = iter.value();
+
1854  Segment* seg2 = new(__FILE__,__LINE__) Segment;
+
1855 
+
1856  seg2->npolys = seg1->npolys;
+
1857  seg2->polys = polys + (seg1->polys - s.polys);
+
1858 
+
1859  if (seg2->polys[0].material)
+
1860  seg2->material = seg2->polys[0].material;
+
1861 
+
1862  seg2->model = model;
+
1863  seg2->video_data = 0;
+
1864 
+
1865  segments.append(seg2);
+
1866  }
+
1867 }
+
1868 
+
1869 // +--------------------------------------------------------------------+
+
1870 
+
1871 void
+
1872 Surface::SetName(const char* n)
+
1873 {
+
1874  int len = sizeof(name);
+
1875 
+
1876  ZeroMemory(name, len);
+
1877  strncpy_s(name, n, len-1);
+
1878 }
+
1879 
+
1880 void
+ +
1882 {
+
1883  if (b)
+
1884  state = state | HIDDEN;
+
1885 
+
1886  else
+
1887  state = state & ~HIDDEN;
+
1888 }
+
1889 
+
1890 void
+ +
1892 {
+
1893  if (b)
+
1894  state = state | LOCKED;
+
1895 
+
1896  else
+
1897  state = state & ~LOCKED;
+
1898 }
+
1899 
+
1900 void
+ +
1902 {
+
1903  if (b)
+
1904  state = state | SIMPLE;
+
1905 
+
1906  else
+
1907  state = state & ~SIMPLE;
+
1908 }
+
1909 
+
1910 void
+ +
1912 {
+
1913  if (!vertex_set && !vloc) {
+
1914  vertex_set = new(__FILE__,__LINE__) VertexSet(nverts);
+
1915  vloc = new(__FILE__,__LINE__) Vec3[nverts];
+
1916  }
+
1917 }
+
1918 
+
1919 void
+ +
1921 {
+
1922  if (!polys && !npolys) {
+
1923  npolys = np;
+
1924  polys = new(__FILE__,__LINE__) Poly[npolys];
+
1925 
+
1926  ZeroMemory(polys, npolys * sizeof(Poly));
+
1927  }
+
1928 }
+
1929 
+
1930 // +--------------------------------------------------------------------+
+
1931 
+
1932 Poly*
+
1933 Surface::AddPolys(int np, int nv)
+
1934 {
+
1935  if ( polys && vertex_set &&
+
1936  np > 0 && np + npolys < MAX_POLYS &&
+
1937  nv > 0 && nv + vertex_set->nverts < MAX_VERTS)
+
1938  {
+
1939  int newverts = nv + vertex_set->nverts;
+
1940  int newpolys = np + npolys;
+
1941 
+
1942  vertex_set->Resize(newverts, true);
+
1943 
+
1944  Poly* pset = new(__FILE__,__LINE__) Poly[newpolys];
+
1945  Poly* pnew = pset + npolys;
+
1946 
+
1947  CopyMemory(pset, polys, npolys * sizeof(Poly));
+
1948  ZeroMemory(pnew, np * sizeof(Poly));
+
1949 
+
1950  if (segments.size() > 0) {
+
1951  Segment* seg = segments.last();
+
1952  Material* mtl = seg->material;
+
1953 
+
1954  for (int i = 0; i < np; i++) {
+
1955  Poly* p = pnew + i;
+
1956  p->material = mtl;
+
1957  }
+
1958 
+
1959  seg->npolys += np;
+
1960  }
+
1961  }
+
1962 
+
1963  return 0;
+
1964 }
+
1965 
+
1966 // +--------------------------------------------------------------------+
+
1967 
+
1968 void
+ +
1970 {
+
1971  if (!vertex_set || vertex_set->nverts < 3)
+
1972  return;
+
1973 
+
1974  int i, j, v;
+
1975  int nverts = 0;
+
1976 
+
1977  // count max verts:
+
1978  for (i = 0; i < npolys; i++) {
+
1979  Poly* p = polys + i;
+
1980  nverts += p->nverts;
+
1981  }
+
1982 
+
1983  // create target vertex set:
+
1984  VertexSet* vset = new(__FILE__,__LINE__) VertexSet(nverts);
+
1985  v = 0;
+
1986 
+
1987  // explode verts:
+
1988  for (i = 0; i < npolys; i++) {
+
1989  Poly* p = polys + i;
+
1990  p->vertex_set = vset;
+
1991 
+
1992  for (j = 0; j < p->nverts; j++) {
+
1993  int vsrc = p->verts[j];
+
1994 
+
1995  vset->loc[v] = vertex_set->loc[vsrc];
+
1996  vset->nrm[v] = vertex_set->nrm[vsrc];
+
1997  vset->tu[v] = vertex_set->tu[vsrc];
+
1998  vset->tv[v] = vertex_set->tv[vsrc];
+
1999  vset->rw[v] = vertex_set->rw[vsrc];
+
2000  vset->diffuse[v] = vertex_set->diffuse[vsrc];
+
2001  vset->specular[v] = vertex_set->specular[vsrc];
+
2002 
+
2003  p->verts[j] = v++;
+
2004  }
+
2005  }
+
2006 
+
2007  // finalize:
+
2008  if (vset) {
+
2009  delete vertex_set;
+
2010  vertex_set = vset;
+
2011  }
+
2012 
+
2013  if (vloc)
+
2014  delete [] vloc;
+
2015 
+
2016  vloc = new(__FILE__,__LINE__) Vec3[nverts];
+
2017 
+
2018  ComputeTangents();
+
2019  BuildHull();
+
2020 }
+
2021 
+
2022 // +--------------------------------------------------------------------+
+
2023 
+
2024 const double SELECT_EPSILON = 0.05;
+
2025 const double SELECT_TEXTURE = 0.0001;
+
2026 
+
2027 static bool MatchVerts(VertexSet* vset, int i, int j)
+
2028 {
+
2029  double d = 0;
+
2030  const Vec3& vl1 = vset->loc[i];
+
2031  const Vec3& vn1 = vset->nrm[i];
+
2032  float tu1 = vset->tu[i];
+
2033  float tv1 = vset->tv[i];
+
2034  const Vec3& vl2 = vset->loc[j];
+
2035  const Vec3& vn2 = vset->nrm[j];
+
2036  float tu2 = vset->tu[j];
+
2037  float tv2 = vset->tv[j];
+
2038 
+
2039  d = fabs(vl1.x - vl2.x);
+
2040  if (d > SELECT_EPSILON)
+
2041  return false;
+
2042 
+
2043  d = fabs(vl1.y - vl2.y);
+
2044  if (d > SELECT_EPSILON)
+
2045  return false;
+
2046 
+
2047  d = fabs(vl1.z - vl2.z);
+
2048  if (d > SELECT_EPSILON)
+
2049  return false;
+
2050 
+
2051  d = fabs(vn1.x - vn2.x);
+
2052  if (d > SELECT_EPSILON)
+
2053  return false;
+
2054 
+
2055  d = fabs(vn1.y - vn2.y);
+
2056  if (d > SELECT_EPSILON)
+
2057  return false;
+
2058 
+
2059  d = fabs(vn1.z - vn2.z);
+
2060  if (d > SELECT_EPSILON)
+
2061  return false;
+
2062 
+
2063  d = fabs(tu1 - tu2);
+
2064  if (d > SELECT_TEXTURE)
+
2065  return false;
+
2066 
+
2067  d = fabs(tv1 - tv2);
+
2068  if (d > SELECT_TEXTURE)
+
2069  return false;
+
2070 
+
2071  return true;
+
2072 }
+
2073 
+
2074 void
+ +
2076 {
+
2077  if (!vertex_set || vertex_set->nverts < 3)
+
2078  return;
+
2079 
+
2080  int nverts = vertex_set->nverts;
+
2081  int used = 0;
+
2082  int final = 0;
+
2083  int nmatch = 0;
+
2084 
+
2085  // create vertex maps:
+
2086  BYTE* vert_map = new BYTE[nverts];
+
2087  WORD* vert_dst = new WORD[nverts];
+
2088  ZeroMemory(vert_map, nverts * sizeof(BYTE));
+
2089  ZeroMemory(vert_dst, nverts * sizeof(WORD));
+
2090 
+
2091  // count used verts:
+
2092  for (int i = 0; i < npolys; i++) {
+
2093  Poly* p = polys + i;
+
2094 
+
2095  for (int j = 0; j < p->nverts; j++) {
+
2096  WORD vert = p->verts[j];
+
2097 
+
2098  if (vert < nverts) {
+
2099  vert_map[vert]++;
+
2100  used++;
+
2101  }
+
2102  }
+
2103  }
+
2104 
+
2105  // create target vertex set:
+
2106  VertexSet* vset = new(__FILE__,__LINE__) VertexSet(used);
+
2107  int v = 0;
+
2108 
+
2109  // compress verts:
+
2110  for (int i = 0; i < nverts; i++) {
+
2111  if (vert_map[i] == 0) continue;
+
2112 
+
2113  vert_dst[i] = v;
+
2114  vset->loc[v] = vertex_set->loc[i];
+
2115  vset->nrm[v] = vertex_set->nrm[i];
+
2116  vset->tu[v] = vertex_set->tu[i];
+
2117  vset->tv[v] = vertex_set->tv[i];
+
2118  vset->rw[v] = vertex_set->rw[i];
+
2119  vset->diffuse[v] = vertex_set->diffuse[i];
+
2120  vset->specular[v] = vertex_set->specular[i];
+
2121 
+
2122  for (int j = i+1; j < nverts; j++) {
+
2123  if (vert_map[j] == 0) continue;
+
2124 
+
2125  if (MatchVerts(vertex_set, i, j)) {
+
2126  vert_map[j] = 0;
+
2127  vert_dst[j] = v;
+
2128  nmatch++;
+
2129  }
+
2130  }
+
2131 
+
2132  v++;
+
2133  }
+
2134 
+
2135  final = v;
+
2136 
+
2137  // remap polys:
+
2138  for (int n = 0; n < npolys; n++) {
+
2139  Poly* p = polys + n;
+
2140  p->vertex_set = vset;
+
2141  for (int v = 0; v < p->nverts; v++) {
+
2142  p->verts[v] = vert_dst[ p->verts[v] ];
+
2143  }
+
2144  }
+
2145 
+
2146  // finalize:
+
2147  if (vset && final < nverts) {
+
2148  delete vertex_set;
+
2149  vertex_set = vset;
+
2150  vset->Resize(final, true);
+
2151  nverts = final;
+
2152  }
+
2153 
+
2154  // clean up and rebuild hull:
+
2155  delete [] vert_map;
+
2156 
+
2157  if (vloc)
+
2158  delete [] vloc;
+
2159 
+
2160  vloc = new(__FILE__,__LINE__) Vec3[nverts];
+
2161 
+
2162  ComputeTangents();
+
2163  BuildHull();
+
2164 }
+
2165 
+
2166 // +--------------------------------------------------------------------+
+
2167 
+
2168 void
+
2169 Surface::ScaleBy(double factor)
+
2170 {
+
2171  offset *= factor;
+
2172 
+
2173  if (vertex_set && vertex_set->nverts) {
+
2174  for (int i = 0; i < vertex_set->nverts; i++) {
+
2175  vertex_set->loc[i] *= (float) factor;
+
2176  }
+
2177  }
+
2178 }
+
2179 
+
2180 // +--------------------------------------------------------------------+
+
2181 
+
2182 void
+ +
2184 {
+
2185  if (npolys < 1 || !vertex_set || vertex_set->nverts < 1)
+
2186  return;
+
2187 
+
2188  nhull = 0;
+
2189 
+
2190  for (int i = 0; i < npolys; i++) {
+
2191  Poly* p = polys + i;
+
2192 
+
2193  for (int n = 0; n < p->nverts; n++) {
+
2194  WORD v = p->verts[n];
+
2195  WORD h;
+
2196 
+
2197  for (h = 0; h < nhull; h++) {
+
2198  Vec3& vl = vertex_set->loc[v];
+
2199  Vec3& loc = vloc[h];
+
2200 
+
2201  double d = vl.x - loc.x;
+
2202 
+
2203  if (d < -SELECT_EPSILON || d > SELECT_EPSILON)
+
2204  continue;
+
2205 
+
2206  d = vl.y - loc.y;
+
2207 
+
2208  if (d < -SELECT_EPSILON || d > SELECT_EPSILON)
+
2209  continue;
+
2210 
+
2211  d = vl.z - loc.z;
+
2212 
+
2213  if (d < -SELECT_EPSILON || d > SELECT_EPSILON)
+
2214  continue;
+
2215 
+
2216  // found a match:
+
2217  break;
+
2218  }
+
2219 
+
2220  // didn't find a match:
+
2221  if (h >= nhull) {
+
2222  vloc[h] = vertex_set->loc[v];
+
2223  nhull = h+1;
+
2224  }
+
2225 
+
2226  p->vlocs[n] = h;
+
2227  }
+
2228  }
+
2229 
+
2230  if (use_collision_detection)
+ +
2232 }
+
2233 
+
2234 // +--------------------------------------------------------------------+
+
2235 
+
2236 void
+ +
2238 {
+
2239  if (npolys < 1 || !vertex_set || vertex_set->nverts < 1)
+
2240  return;
+
2241 
+
2242  // STEP ONE: initialize poly planes
+
2243 
+
2244  for (int i = 0; i < npolys; i++) {
+
2245  Poly* p = polys + i;
+
2246 
+
2247  p->plane = Plane( vertex_set->loc[ p->verts[0] ],
+
2248  vertex_set->loc[ p->verts[2] ],
+
2249  vertex_set->loc[ p->verts[1] ] );
+
2250  }
+
2251 
+
2252  // STEP TWO: compute vertex normals by averaging adjecent poly planes
+
2253 
+
2254  List<Poly> faces;
+
2255  for (int v = 0; v < vertex_set->nverts; v++) {
+
2256  faces.clear();
+
2257  SelectPolys(faces, vertex_set->loc[v]);
+
2258 
+
2259  if (faces.size()) {
+
2260  vertex_set->nrm[v] = Vec3(0.0f, 0.0f, 0.0f);
+
2261 
+
2262  for (int i = 0; i < faces.size(); i++) {
+
2263  vertex_set->nrm[v] += faces[i]->plane.normal;
+
2264  }
+
2265 
+
2266  vertex_set->nrm[v].Normalize();
+
2267  }
+
2268 
+
2269  else if (vertex_set->loc[v].length() > 0) {
+
2270  vertex_set->nrm[v] = vertex_set->loc[v];
+
2271  vertex_set->nrm[v].Normalize();
+
2272  }
+
2273 
+
2274  else {
+
2275  vertex_set->nrm[v] = Vec3(0.0f, 1.0f, 0.0f);
+
2276  }
+
2277  }
+
2278 
+
2279  // STEP THREE: adjust vertex normals for poly flatness
+
2280 
+
2281  for (int i = 0; i < npolys; i++) {
+
2282  Poly* p = polys + i;
+
2283 
+
2284  for (int n = 0; n < p->nverts; n++) {
+
2285  int v = p->verts[n];
+
2286 
+
2287  vertex_set->nrm[v] = vertex_set->nrm[v] * (1.0f - p->flatness) +
+
2288  p->plane.normal * ( p->flatness);
+
2289  }
+
2290  }
+
2291 }
+
2292 
+
2293 void
+ +
2295 {
+
2296  const double SELECT_EPSILON = 0.05;
+
2297 
+
2298  for (int i = 0; i < npolys; i++) {
+
2299  Poly* p = polys + i;
+
2300 
+
2301  for (int n = 0; n < p->nverts; n++) {
+
2302  int v = p->verts[n];
+
2303  Vec3& vl = vertex_set->loc[v];
+
2304  double d = vl.x - loc.x;
+
2305 
+
2306  if (d < -SELECT_EPSILON || d > SELECT_EPSILON)
+
2307  continue;
+
2308 
+
2309  d = vl.y - loc.y;
+
2310 
+
2311  if (d < -SELECT_EPSILON || d > SELECT_EPSILON)
+
2312  continue;
+
2313 
+
2314  d = vl.z - loc.z;
+
2315 
+
2316  if (d < -SELECT_EPSILON || d > SELECT_EPSILON)
+
2317  continue;
+
2318 
+
2319  selection.append(p);
+
2320  break;
+
2321  }
+
2322  }
+
2323 }
+
2324 
+
2325 void
+ +
2327 {
+
2328  for (int i = 0; i < npolys; i++) {
+
2329  Poly* p = polys + i;
+
2330 
+
2331  if (p->material == m)
+
2332  selection.append(p);
+
2333  }
+
2334 }
+
2335 
+
2336 // +--------------------------------------------------------------------+
+
2337 
+
2338 void
+ +
2340 {
+
2341  Vec3 tangent;
+
2342  Vec3 binormal;
+
2343 
+
2344  if (!vertex_set || !vertex_set->nverts)
+
2345  return;
+
2346 
+
2347  if (vertex_set->tangent)
+
2348  return;
+
2349 
+
2350  vertex_set->CreateTangents();
+
2351 
+
2352  for (int i = 0; i < npolys; i++) {
+
2353  Poly* p = polys + i;
+
2354 
+
2355  CalcGradients(*p, tangent, binormal);
+
2356 
+
2357  for (int n = 0; n < p->nverts; n++) {
+
2358  vertex_set->tangent[p->verts[n]] = tangent;
+
2359  vertex_set->binormal[p->verts[n]] = binormal;
+
2360  }
+
2361  }
+
2362 }
+
2363 
+
2364 void
+
2365 Surface::CalcGradients(Poly& p, Vec3& tangent, Vec3& binormal)
+
2366 {
+
2367  // using Eric Lengyel's approach with a few modifications
+
2368  // from Mathematics for 3D Game Programmming and Computer Graphics
+
2369  // want to be able to trasform a vector in Object Space to Tangent Space
+
2370  // such that the x-axis cooresponds to the 's' direction and the
+
2371  // y-axis corresponds to the 't' direction, and the z-axis corresponds
+
2372  // to <0,0,1>, straight up out of the texture map
+
2373 
+
2374  VertexSet* vset = p.vertex_set;
+
2375 
+
2376  Vec3 P = vset->loc[p.verts[1]] - vset->loc[p.verts[0]];
+
2377  Vec3 Q = vset->loc[p.verts[2]] - vset->loc[p.verts[0]];
+
2378 
+
2379  float s1 = vset->tu[p.verts[1]] - vset->tu[p.verts[0]];
+
2380  float t1 = vset->tv[p.verts[1]] - vset->tv[p.verts[0]];
+
2381  float s2 = vset->tu[p.verts[2]] - vset->tu[p.verts[0]];
+
2382  float t2 = vset->tv[p.verts[2]] - vset->tv[p.verts[0]];
+
2383 
+
2384  float tmp = 1.0f;
+
2385  float denom = s1*t2 - s2*t1;
+
2386 
+
2387  if (fabsf(denom) > 0.0001f)
+
2388  tmp = 1.0f/(denom);
+
2389 
+
2390  tangent.x = (t2*P.x - t1*Q.x) * tmp;
+
2391  tangent.y = (t2*P.y - t1*Q.y) * tmp;
+
2392  tangent.z = (t2*P.z - t1*Q.z) * tmp;
+
2393 
+
2394  tangent.Normalize();
+
2395 
+
2396  binormal.x = (s1*Q.x - s2*P.x) * tmp;
+
2397  binormal.y = (s1*Q.y - s2*P.y) * tmp;
+
2398  binormal.z = (s1*Q.z - s2*P.z) * tmp;
+
2399 
+
2400  binormal.Normalize();
+
2401 }
+
2402 
+
2403 void
+ +
2405 {
+
2406  opcode = new(__FILE__,__LINE__) OPCODE_data(this);
+
2407 }
+
2408 
+
2409 // +--------------------------------------------------------------------+
+
2410 // +--------------------------------------------------------------------+
+
2411 // +--------------------------------------------------------------------+
+
2412 
+ +
2414 {
+
2415  ZeroMemory(this, sizeof(Segment));
+
2416 }
+
2417 
+
2418 Segment::Segment(int n, Poly* p, Material* mtl, Model* mod)
+
2419 : npolys(n), polys(p), material(mtl), model(mod), video_data(0)
+
2420 {
+
2421 }
+
2422 
+ +
2424 {
+
2425  delete video_data;
+
2426 
+
2427  ZeroMemory(this, sizeof(Segment));
+
2428 }
+
2429 
+
2430 // +--------------------------------------------------------------------+
+
2431 // +--------------------------------------------------------------------+
+
2432 // +--------------------------------------------------------------------+
+
2433 
+
2434 ModelFile::ModelFile(const char* fname)
+
2435 : model(0), pname(0), pnverts(0), pnpolys(0), pradius(0)
+
2436 {
+
2437  int len = sizeof(filename);
+
2438  ZeroMemory(filename, len);
+
2439  strncpy_s(filename, fname, len);
+
2440  filename[len-1] = 0;
+
2441 }
+
2442 
+ +
2444 {
+
2445 }
+
2446 
+
2447 bool
+
2448 ModelFile::Load(Model* m, double scale)
+
2449 {
+
2450  model = m;
+
2451 
+
2452  // expose model innards for child classes:
+
2453 
+
2454  if (model) {
+
2455  pname = model->name;
+
2456  pnverts = &model->nverts;
+
2457  pnpolys = &model->npolys;
+
2458  pradius = &model->radius;
+
2459  }
+
2460 
+
2461  return false;
+
2462 }
+
2463 
+
2464 bool
+ +
2466 {
+
2467  model = m;
+
2468 
+
2469  // expose model innards for child classes:
+
2470 
+
2471  if (model) {
+
2472  pname = model->name;
+
2473  pnverts = &model->nverts;
+
2474  pnpolys = &model->npolys;
+
2475  pradius = &model->radius;
+
2476  }
+
2477 
+
2478  return false;
+
2479 }
+
2480 
+
+
+ + + + -- cgit v1.1