Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
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