Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Shadow.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: Shadow.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Dynamic Stencil Shadow Volumes
13 */
14 
15 #include "MemDebug.h"
16 #include "Shadow.h"
17 #include "Light.h"
18 #include "Solid.h"
19 #include "Scene.h"
20 #include "Video.h"
21 
22 static bool visible_shadow_volumes = false;
23 
24 // +--------------------------------------------------------------------+
25 
27 : verts(0), nverts(0), max_verts(0), edges(0), num_edges(0), enabled(true)
28 {
29  solid = s;
30 
31  if (solid && solid->GetModel()) {
32  Model* model = solid->GetModel();
33  int npolys = model->NumPolys();
34 
35  max_verts = model->NumVerts() * 4;
36  verts = new(__FILE__,__LINE__) Vec3[max_verts];
37  edges = new(__FILE__,__LINE__) WORD[npolys * 6];
38  }
39 }
40 
41 // +--------------------------------------------------------------------+
42 
44 {
45  if (verts) delete [] verts;
46  if (edges) delete [] edges;
47 }
48 
49 // +--------------------------------------------------------------------+
50 
51 void
53 {
54  num_edges = 0;
55  nverts = 0;
56 }
57 
58 // +--------------------------------------------------------------------+
59 
60 void
62 {
63  if (enabled)
64  video->DrawShadow(solid, nverts, verts, visible_shadow_volumes);
65 }
66 
67 // +--------------------------------------------------------------------+
68 
69 void
71 {
72  Reset();
73 
74  if (!light || !solid || !solid->GetModel() || !edges) return;
75 
76  Vec3 lpos = light->Location();
77  bool directional = light->Type() == Light::LIGHT_DIRECTIONAL;
78  Model* model = solid->GetModel();
79 
80  ListIter<Surface> iter = model->GetSurfaces();
81  while (++iter) {
82  Surface* s = iter.value();
83 
84  // transform light location into surface object space
85  Matrix xform(solid->Orientation()); // XXX should be: (s->GetOrientation());
86 
87  Vec3 tmp = light->Location();
88 
89  if (!directional)
90  tmp -= (solid->Location() + s->GetOffset());
91 
92  lpos.x = tmp * Vec3(xform(0,0), xform(0,1), xform(0,2));
93  lpos.y = tmp * Vec3(xform(1,0), xform(1,1), xform(1,2));
94  lpos.z = tmp * Vec3(xform(2,0), xform(2,1), xform(2,2));
95 
96  // compute the silohuette for the mesh with respect to the light:
97 
98  for (int i = 0; i < s->NumPolys(); i++) {
99  Poly* p = s->GetPolys() + i;
100 
101  // skip polys with non-shadowing materials:
102  if (p->material && !p->material->shadow)
103  continue;
104 
105  // if this poly faces the light:
106  if (p->plane.normal * lpos > 0) {
107  for (int n = 0; n < p->nverts; n++) {
108  if (n < p->nverts-1)
109  AddEdge(p->vlocs[n], p->vlocs[n+1]);
110  else
111  AddEdge(p->vlocs[n], p->vlocs[0]);
112  }
113  }
114  }
115 
116  // extrude the silohuette away from the light source
117  // to create the shadow volume:
118 
119  Vec3 extent = lpos * -1;
120  extent.Normalize();
121  extent *= 50.0e3f; //solid->Radius() * 2.1f;
122 
123  for (int i = 0; i < (int) num_edges; i++) {
124  if (nverts+6 <= max_verts) {
125  Vec3 v1 = s->GetVLoc()[edges[2*i+0]];
126  Vec3 v2 = s->GetVLoc()[edges[2*i+1]];
127  Vec3 v3 = v1 + extent;
128  Vec3 v4 = v2 + extent;
129 
130  verts[nverts++] = v1;
131  verts[nverts++] = v2;
132  verts[nverts++] = v3;
133 
134  verts[nverts++] = v2;
135  verts[nverts++] = v4;
136  verts[nverts++] = v3;
137  }
138  }
139  }
140 }
141 
142 void
143 Shadow::AddEdge(WORD v1, WORD v2)
144 {
145  // Remove interior edges (which appear in the list twice)
146  for (DWORD i = 0; i < num_edges; i++) {
147  if ((edges[2*i+0] == v1 && edges[2*i+1] == v2) ||
148  (edges[2*i+0] == v2 && edges[2*i+1] == v1))
149  {
150  if (num_edges > 1) {
151  edges[2*i+0] = edges[2*(num_edges-1)+0];
152  edges[2*i+1] = edges[2*(num_edges-1)+1];
153  }
154 
155  num_edges--;
156  return;
157  }
158  }
159 
160  edges[2*num_edges+0] = v1;
161  edges[2*num_edges+1] = v2;
162 
163  num_edges++;
164 }
165 
166 bool
168 {
169  return visible_shadow_volumes;
170 }
171 
172 void
174 {
175  visible_shadow_volumes = vis;
176 }