Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Polygon.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: Polygon.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Polygon and VertexSet structures for 3D rendering
13 */
14 
15 #include "MemDebug.h"
16 #include "Polygon.h"
17 #include "Bitmap.h"
18 
19 // +--------------------------------------------------------------------+
20 
22 : nverts(0), space(OBJECT_SPACE),
23 tu1(0), tv1(0), tangent(0), binormal(0)
24 {
25  Resize(m);
26 }
27 
28 // +--------------------------------------------------------------------+
29 
31 {
32  Delete();
33 }
34 
35 // +--------------------------------------------------------------------+
36 
37 void
38 VertexSet::Resize(int m, bool preserve)
39 {
40  // easy cases (no data will be preserved):
41  if (!m || !nverts || !preserve) {
42  bool additional_tex_coords = (tu1 != 0);
43 
44  Delete();
45 
46  nverts = m;
47 
48  if (nverts <= 0) {
49  ZeroMemory(this, sizeof(VertexSet));
50  }
51 
52  else {
53  loc = new(__FILE__,__LINE__) Vec3[nverts];
54  nrm = new(__FILE__,__LINE__) Vec3[nverts];
55  s_loc = new(__FILE__,__LINE__) Vec3[nverts];
56  tu = new(__FILE__,__LINE__) float[nverts];
57  tv = new(__FILE__,__LINE__) float[nverts];
58  rw = new(__FILE__,__LINE__) float[nverts];
59  diffuse = new(__FILE__,__LINE__) DWORD[nverts];
60  specular = new(__FILE__,__LINE__) DWORD[nverts];
61 
62  if (additional_tex_coords)
64 
65  if (!loc || !nrm || !s_loc || !rw || !tu || !tv || !diffuse || !specular) {
66  nverts = 0;
67 
68  delete [] loc;
69  delete [] nrm;
70  delete [] s_loc;
71  delete [] rw;
72  delete [] tu;
73  delete [] tv;
74  delete [] tu1;
75  delete [] tv1;
76  delete [] diffuse;
77  delete [] specular;
78 
79  ZeroMemory(this, sizeof(VertexSet));
80  }
81  }
82  }
83 
84  // actually need to copy data:
85  else {
86  int np = nverts;
87 
88  nverts = m;
89 
90  if (nverts < np)
91  np = nverts;
92 
93  Vec3* new_loc = new(__FILE__,__LINE__) Vec3[nverts];
94  Vec3* new_nrm = new(__FILE__,__LINE__) Vec3[nverts];
95  Vec3* new_s_loc = new(__FILE__,__LINE__) Vec3[nverts];
96  float* new_rw = new(__FILE__,__LINE__) float[nverts];
97  float* new_tu = new(__FILE__,__LINE__) float[nverts];
98  float* new_tv = new(__FILE__,__LINE__) float[nverts];
99  float* new_tu1 = 0;
100  float* new_tv1 = 0;
101  DWORD* new_diffuse = new(__FILE__,__LINE__) DWORD[nverts];
102  DWORD* new_specular = new(__FILE__,__LINE__) DWORD[nverts];
103 
104  if (tu1)
105  new_tu1 = new(__FILE__,__LINE__) float[nverts];
106 
107  if (tv1)
108  new_tv1 = new(__FILE__,__LINE__) float[nverts];
109 
110  if (new_loc) {
111  CopyMemory(new_loc, loc, np * sizeof(Vec3));
112  delete [] loc;
113  loc = new_loc;
114  }
115 
116  if (new_nrm) {
117  CopyMemory(new_nrm, nrm, np * sizeof(Vec3));
118  delete [] nrm;
119  nrm = new_nrm;
120  }
121 
122  if (new_s_loc) {
123  CopyMemory(new_s_loc, s_loc, np * sizeof(Vec3));
124  delete [] s_loc;
125  s_loc = new_s_loc;
126  }
127 
128  if (new_tu) {
129  CopyMemory(new_tu, tu, np * sizeof(float));
130  delete [] tu;
131  tu = new_tu;
132  }
133 
134  if (new_tv) {
135  CopyMemory(new_tv, tv, np * sizeof(float));
136  delete [] tv;
137  tv = new_tv;
138  }
139 
140  if (new_tu1) {
141  CopyMemory(new_tu1, tu1, np * sizeof(float));
142  delete [] tu1;
143  tu = new_tu1;
144  }
145 
146  if (new_tv1) {
147  CopyMemory(new_tv1, tv1, np * sizeof(float));
148  delete [] tv1;
149  tv = new_tv1;
150  }
151 
152  if (new_diffuse) {
153  CopyMemory(new_diffuse, diffuse, np * sizeof(DWORD));
154  delete [] diffuse;
155  diffuse = new_diffuse;
156  }
157 
158  if (new_specular) {
159  CopyMemory(new_specular, specular, np * sizeof(DWORD));
160  delete [] specular;
161  specular = new_specular;
162  }
163 
164  if (!loc || !nrm || !s_loc || !rw || !tu || !tv || !diffuse || !specular) {
165  Delete();
166  ZeroMemory(this, sizeof(VertexSet));
167  }
168  }
169 }
170 
171 // +--------------------------------------------------------------------+
172 
173 void
175 {
176  if (nverts) {
177  delete [] loc;
178  delete [] nrm;
179  delete [] s_loc;
180  delete [] rw;
181  delete [] tu;
182  delete [] tv;
183  delete [] tu1;
184  delete [] tv1;
185  delete [] diffuse;
186  delete [] specular;
187  delete [] tangent;
188  delete [] binormal;
189 
190  tangent = 0;
191  binormal = 0;
192  }
193 }
194 
195 // +--------------------------------------------------------------------+
196 
197 void
199 {
200  if (nverts) {
201  ZeroMemory(loc, sizeof(Vec3) * nverts);
202  ZeroMemory(nrm, sizeof(Vec3) * nverts);
203  ZeroMemory(s_loc, sizeof(Vec3) * nverts);
204  ZeroMemory(tu, sizeof(float) * nverts);
205  ZeroMemory(tv, sizeof(float) * nverts);
206  ZeroMemory(rw, sizeof(float) * nverts);
207  ZeroMemory(diffuse, sizeof(DWORD) * nverts);
208  ZeroMemory(specular, sizeof(DWORD) * nverts);
209 
210  if (tu1)
211  ZeroMemory(tu1, sizeof(float) * nverts);
212 
213  if (tv1)
214  ZeroMemory(tv1, sizeof(float) * nverts);
215 
216  if (tangent)
217  ZeroMemory(tangent, sizeof(Vec3) * nverts);
218 
219  if (binormal)
220  ZeroMemory(binormal, sizeof(Vec3) * nverts);
221  }
222 }
223 
224 // +--------------------------------------------------------------------+
225 
226 void
228 {
229  if (tangent) delete [] tangent;
230  if (binormal) delete [] binormal;
231 
232  tangent = 0;
233  binormal = 0;
234 
235  if (nverts) {
236  tangent = new(__FILE__,__LINE__) Vec3[nverts];
237  binormal = new(__FILE__,__LINE__) Vec3[nverts];
238  }
239 }
240 
241 // +--------------------------------------------------------------------+
242 
243 void
245 {
246  if (tu1) delete [] tu1;
247  if (tv1) delete [] tv1;
248 
249  tu1 = 0;
250  tv1 = 0;
251 
252  if (nverts) {
253  tu1 = new(__FILE__,__LINE__) float[nverts];
254  tv1 = new(__FILE__,__LINE__) float[nverts];
255  }
256 }
257 
258 // +--------------------------------------------------------------------+
259 
260 bool
261 VertexSet::CopyVertex(int dst, int src)
262 {
263  if (src >= 0 && src < nverts && dst >= 0 && dst < nverts) {
264  loc[dst] = loc[src];
265  nrm[dst] = nrm[src];
266  s_loc[dst] = s_loc[src];
267  tu[dst] = tu[src];
268  tv[dst] = tv[src];
269  diffuse[dst] = diffuse[src];
270  specular[dst] = specular[src];
271 
272  if (tu1)
273  tu1[dst] = tu1[src];
274 
275  if (tv1)
276  tv1[dst] = tv1[src];
277 
278  if (tangent)
279  tangent[dst] = tangent[src];
280 
281  if (binormal)
282  binormal[dst] = binormal[src];
283 
284  return true;
285  }
286 
287  return false;
288 }
289 
290 VertexSet*
292 {
293  VertexSet* result = new(__FILE__,__LINE__) VertexSet(nverts);
294 
295  CopyMemory(result->loc, loc, nverts * sizeof(Vec3));
296  CopyMemory(result->nrm, nrm, nverts * sizeof(Vec3));
297  CopyMemory(result->s_loc, s_loc, nverts * sizeof(Vec3));
298  CopyMemory(result->rw, rw, nverts * sizeof(float));
299  CopyMemory(result->tu, tu, nverts * sizeof(float));
300  CopyMemory(result->tv, tv, nverts * sizeof(float));
301  CopyMemory(result->diffuse, diffuse, nverts * sizeof(DWORD));
302  CopyMemory(result->specular, specular, nverts * sizeof(DWORD));
303 
304  if (tu1) {
305  if (!result->tu1)
306  result->tu1 = new(__FILE__,__LINE__) float[nverts];
307 
308  CopyMemory(result->tu1, tu1, nverts * sizeof(float));
309  }
310 
311  if (tv1) {
312  if (!result->tv1)
313  result->tv1 = new(__FILE__,__LINE__) float[nverts];
314 
315  CopyMemory(result->tv1, tv1, nverts * sizeof(float));
316  }
317 
318  if (tangent) {
319  if (!result->tangent)
320  result->tangent = new(__FILE__,__LINE__) Vec3[nverts];
321 
322  CopyMemory(result->tangent, tangent, nverts * sizeof(Vec3));
323  }
324 
325  if (binormal) {
326  if (!result->binormal)
327  result->binormal = new(__FILE__,__LINE__) Vec3[nverts];
328 
329  CopyMemory(result->binormal, binormal, nverts * sizeof(Vec3));
330  }
331 
332  return result;
333 }
334 
335 void
337 {
338  plus = Point(-1e6, -1e6, -1e6);
339  minus = Point( 1e6, 1e6, 1e6);
340 
341  for (int i = 0; i < nverts; i++) {
342  if (loc[i].x > plus.x) plus.x = loc[i].x;
343  if (loc[i].x < minus.x) minus.x = loc[i].x;
344  if (loc[i].y > plus.y) plus.y = loc[i].y;
345  if (loc[i].y < minus.y) minus.y = loc[i].y;
346  if (loc[i].z > plus.z) plus.z = loc[i].z;
347  if (loc[i].z < minus.z) minus.z = loc[i].z;
348  }
349 }
350 
351 // +--------------------------------------------------------------------+
352 // +--------------------------------------------------------------------+
353 // +--------------------------------------------------------------------+
354 
355 Poly::Poly(int init)
356 : nverts(0), visible(1), material(0), vertex_set(0), sortval(0), flatness(0)
357 { }
358 
359 // +--------------------------------------------------------------------+
360 // Check to see if a test point is within the bounds of the poly.
361 // The point is assumed to be coplanar with the poly. Return 1 if
362 // the point is inside, 0 if the point is outside.
363 
365 
366 static inline double extent3(double a, double b, double c)
367 {
368  double d1 = fabs(a-b);
369  double d2 = fabs(a-c);
370  double d3 = fabs(b-c);
371 
372  if (d1 > d2) {
373  if (d1 > d3)
374  return d1;
375  else
376  return d3;
377  }
378  else {
379  if (d2 > d3)
380  return d2;
381  else
382  return d3;
383  }
384 }
385 
386 int Poly::Contains(const Vec3& pt) const
387 {
388  // find largest 2d projection of this 3d Poly:
389  int projaxis;
390 
391  double pnx = fabs(plane.normal.x);
392  double pny = fabs(plane.normal.y);
393  double pnz = fabs(plane.normal.z);
394 
395  if (pnx > pny)
396  if (pnx > pnz)
397  if (plane.normal.x > 0)
398  projaxis = 1;
399  else
400  projaxis = -1;
401  else
402  if (plane.normal.z > 0)
403  projaxis = 3;
404  else
405  projaxis = -3;
406  else
407  if (pny > pnz)
408  if (plane.normal.y > 0)
409  projaxis = 2;
410  else
411  projaxis = -2;
412  else
413  if (plane.normal.z > 0)
414  projaxis = 3;
415  else
416  projaxis = -3;
417 
418  int i;
419 
420  for (i = 0; i < nverts; i++) {
421  Vec3 loc = vertex_set->loc[verts[i]];
422  switch (projaxis) {
423  case 1: projverts[i] = Vec2(loc.y, loc.z); break;
424  case -1: projverts[i] = Vec2(loc.z, loc.y); break;
425  case 2: projverts[i] = Vec2(loc.z, loc.x); break;
426  case -2: projverts[i] = Vec2(loc.x, loc.z); break;
427  case 3: projverts[i] = Vec2(loc.x, loc.y); break;
428  case -3: projverts[i] = Vec2(loc.y, loc.x); break;
429  }
430  }
431 
432  // now project the test point into the same plane:
433  Vec2 test;
434  switch (projaxis) {
435  case 1: test.x = pt.y; test.y = pt.z; break;
436  case -1: test.x = pt.z; test.y = pt.y; break;
437  case 2: test.x = pt.z; test.y = pt.x; break;
438  case -2: test.x = pt.x; test.y = pt.z; break;
439  case 3: test.x = pt.x; test.y = pt.y; break;
440  case -3: test.x = pt.y; test.y = pt.x; break;
441  }
442 
443  const float INSIDE_EPSILON = -0.01f;
444 
445  // if the test point is outside of any segment,
446  // it is outside the entire convex Poly.
447  for (i = 0; i < nverts-1; i++) {
448  if (verts[i] != verts[i+1]) {
449  Vec2 segment = projverts[i+1] - projverts[i];
450  Vec2 segnorm = segment.normal();
451  Vec2 tdelta = projverts[i] - test;
452  float inside = segnorm * tdelta;
453  if (inside < INSIDE_EPSILON)
454  return 0;
455  }
456  }
457 
458  // check last segment, too:
459  if (verts[0] != verts[nverts-1]) {
460  Vec2 segment = projverts[0] - projverts[nverts-1];
461  float inside = segment.normal() * (projverts[0] - test);
462  if (inside < INSIDE_EPSILON)
463  return 0;
464  }
465 
466  // still here? must be inside:
467  return 1;
468 }
469 
470 // +--------------------------------------------------------------------+
471 // +--------------------------------------------------------------------+
472 // +--------------------------------------------------------------------+
473 
475 : power(1.0f), brilliance(1.0f), bump(0.0f), blend(MTL_SOLID),
476 shadow(true), luminous(false),
477 tex_diffuse(0), tex_specular(0), tex_bumpmap(0), tex_emissive(0),
478 tex_alternate(0), tex_detail(0), thumbnail(0)
479 {
480  ZeroMemory(name, sizeof(name));
481  ZeroMemory(shader, sizeof(shader));
482 
483  ambient_value = 0.2f;
484  diffuse_value = 1.0f;
485  specular_value = 0.0f;
486  emissive_value = 0.0f;
487 }
488 
489 // +--------------------------------------------------------------------+
490 
492 {
493  // these objects are owned by the shared
494  // bitmap cache, so don't delete them now:
495  tex_diffuse = 0;
496  tex_specular = 0;
497  tex_bumpmap = 0;
498  tex_emissive = 0;
499  tex_alternate = 0;
500  tex_detail = 0;
501 
502  // the thumbnail is unique to the material,
503  // so it is never cached:
504  if (thumbnail)
505  delete thumbnail;
506 }
507 
508 // +--------------------------------------------------------------------+
509 
510 int
512 {
513  if (this == &m) return 1;
514 
515  if (Ka != m.Ka) return 0;
516  if (Kd != m.Kd) return 0;
517  if (Ks != m.Ks) return 0;
518  if (Ke != m.Ke) return 0;
519  if (power != m.power) return 0;
520  if (brilliance != m.brilliance) return 0;
521  if (bump != m.bump) return 0;
522  if (blend != m.blend) return 0;
523  if (shadow != m.shadow) return 0;
524  if (tex_diffuse != m.tex_diffuse) return 0;
525  if (tex_specular != m.tex_specular) return 0;
526  if (tex_bumpmap != m.tex_bumpmap) return 0;
527  if (tex_emissive != m.tex_emissive) return 0;
528  if (tex_alternate != m.tex_alternate) return 0;
529  if (tex_detail != m.tex_detail) return 0;
530 
531  return !strcmp(name, m.name);
532 }
533 
534 // +--------------------------------------------------------------------+
535 
536 void
538 {
539  Ka = ColorValue();
540  Kd = ColorValue();
541  Ks = ColorValue();
542  Ke = ColorValue();
543 
544  power = 1.0f;
545  bump = 0.0f;
546  blend = MTL_SOLID;
547  shadow = true;
548 
549  tex_diffuse = 0;
550  tex_specular = 0;
551  tex_bumpmap = 0;
552  tex_emissive = 0;
553  tex_alternate = 0;
554  tex_detail = 0;
555 }
556 
557 // +--------------------------------------------------------------------+
558 
559 static char shader_name[Material::NAMELEN];
560 
561 const char*
562 Material::GetShader(int pass) const
563 {
564  int level = 0;
565  if (pass > 1) pass--;
566 
567  for (int i = 0; i < NAMELEN; i++) {
568  if (shader[i] == '/') {
569  level++;
570 
571  if (level > pass)
572  return 0;
573  }
574 
575  else if (shader[i] != 0) {
576  if (level == pass) {
577  ZeroMemory(shader_name, NAMELEN);
578 
579  char* s = shader_name;
580  while (i < NAMELEN && shader[i] != 0 && shader[i] != '/') {
581  *s++ = shader[i++];
582  }
583 
584  return shader_name;
585  }
586  }
587 
588  else {
589  return 0;
590  }
591  }
592 
593  return 0;
594 }
595 
596 // +--------------------------------------------------------------------+
597 
598 void
600 {
601  if (!thumbnail) {
602  thumbnail = new(__FILE__,__LINE__) Bitmap(size, size);
603  }
604 
605  if (!thumbnail || thumbnail->Width() != thumbnail->Height())
606  return;
607 
608  size = thumbnail->Width();
609 
610  DWORD* image = new(__FILE__,__LINE__) DWORD[size*size];
611  DWORD* dst = image;
612 
613  for (int j = 0; j < size; j++) {
614  for (int i = 0; i < size; i++) {
615  *dst++ = GetThumbColor(i, j, size);
616  }
617  }
618 
619  thumbnail->CopyHighColorImage(size, size, image, Bitmap::BMP_SOLID);
620 }
621 
622 DWORD
623 Material::GetThumbColor(int i, int j, int size)
624 {
625  Color result = Color::LightGray;
626 
627  double x = i - size/2;
628  double y = j - size/2;
629  double r = 0.9 * size/2;
630  double d = sqrt(x*x + y*y);
631 
632  if (d <= r) {
633  double z = sqrt(r*r - x*x - y*y);
634 
635  Point loc(x,y,z);
636  Point nrm = loc; nrm.Normalize();
637  Point light(1,-1,1); light.Normalize();
638  Point eye(0,0,1);
639 
640  ColorValue c = Ka * ColorValue(0.25f, 0.25f, 0.25f); // ambient light
641  ColorValue white(1,1,1);
642 
643  double diffuse = nrm*light;
644  double v = 1 - (acos(nrm.y)/PI);
645  double u = asin(nrm.x / sin(acos(nrm.y))) / PI + 0.5;
646 
647  ColorValue cd = Kd;
648  ColorValue cs = Ks;
649  ColorValue ce = Ke;
650 
651  if (tex_diffuse) {
652  int tu = (int) (u * tex_diffuse->Width());
653  int tv = (int) (v * tex_diffuse->Height());
654  cd = Kd * tex_diffuse->GetColor(tu,tv);
655  }
656 
657  if (tex_emissive) {
658  int tu = (int) (u * tex_emissive->Width());
659  int tv = (int) (v * tex_emissive->Height());
660  ce = Ke * tex_emissive->GetColor(tu,tv);
661  }
662 
663  if (tex_bumpmap && bump != 0 && nrm.z > 0) {
664  // compute derivatives B(u,v)
665  int tu = (int) (u * tex_bumpmap->Width());
666  int tv = (int) (v * tex_bumpmap->Height());
667 
668  double du1 = tex_bumpmap->GetColor(tu,tv).Red() -
669  tex_bumpmap->GetColor(tu-1,tv).Red();
670  double du2 = tex_bumpmap->GetColor(tu+1,tv).Red() -
671  tex_bumpmap->GetColor(tu,tv).Red();
672 
673  double dv1 = tex_bumpmap->GetColor(tu,tv).Red() -
674  tex_bumpmap->GetColor(tu,tv-1).Red();
675  double dv2 = tex_bumpmap->GetColor(tu,tv+1).Red() -
676  tex_bumpmap->GetColor(tu,tv).Red();
677 
678  double du = (du1 + du2) / 512 * 1e-8;
679  double dv = (dv1 + dv2) / 512 * 1e-8;
680 
681  if (du || dv) {
682  Point Nu = nrm.cross(Point(0,-1,0)); Nu.Normalize();
683  Point Nv = nrm.cross(Point(1, 0,0)); Nv.Normalize();
684 
685  nrm += (Nu*du*bump);
686  nrm += (Nv*dv*bump);
687  nrm.Normalize();
688 
689  diffuse = nrm*light;
690  v = 1 - (acos(nrm.y)/PI);
691  u = asin(nrm.x / sin(acos(nrm.y))) / PI + 0.5;
692  }
693  }
694 
695  if (tex_specular) {
696  int tu = (int) (u * tex_specular->Width());
697  int tv = (int) (v * tex_specular->Height());
698  cs = Ks * tex_specular->GetColor(tu,tv);
699  }
700 
701  // anisotropic diffuse lighting
702  if (brilliance >= 0) {
703  diffuse = pow(diffuse, (double)brilliance);
704  }
705 
706  // forward lighting
707  if (diffuse > 0) {
708  // diffuse
709  c += cd * (white * diffuse);
710 
711  // specular
712  if (power > 0) {
713  double spec = ((nrm * 2*(nrm*light) - light) * eye);
714  if (spec > 0.01) {
715  spec = pow(spec, (double)power);
716  c += cs * (white * spec);
717  }
718  }
719  }
720 
721  // back lighting
722  else {
723  diffuse *= -0.5;
724  c += cd * (white * diffuse);
725 
726  // specular
727  if (power > 0) {
728  light *= -1;
729 
730  double spec = ((nrm * 2*(nrm*light) - light) * eye);
731  if (spec > 0.01) {
732  spec = pow(spec, (double)power);
733  c += cs * (white * spec) * 0.7;
734  }
735  }
736  }
737 
738  c += ce;
739 
740  result = c.ToColor();
741  }
742 
743  return result.Value();
744 }