Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
TerrainApron.cpp
Go to the documentation of this file.
1 /* Project Starshatter 4.5
2  Destroyer Studios LLC
3  Copyright © 1997-2005. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: TerrainApron.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12 */
13 
14 #include "MemDebug.h"
15 #include "Terrain.h"
16 #include "TerrainApron.h"
17 #include "TerrainRegion.h"
18 
19 #include "CameraView.h"
20 #include "Bitmap.h"
21 #include "DataLoader.h"
22 #include "Game.h"
23 #include "Light.h"
24 #include "Scene.h"
25 
26 // +====================================================================+
27 
28 const int PATCH_SIZE = 17;
29 const int HALF_PATCH_SIZE = 8;
31 const int NUM_INDICES_TRI = 3;
32 
33 // +--------------------------------------------------------------------+
34 
35 TerrainApron::TerrainApron(Terrain* terr,const Bitmap* patch, const Rect& r,
36 const Point& p1, const Point& p2)
37 : terrain(terr), rect(r)
38 {
39  size = fabs(p2.x - p1.x);
40  scale = size / (PATCH_SIZE-1);
41  mtnscale = 1.3 * (p2.y - p1.y);
42  base = p1.y;
43 
44  terrain_width = patch->Width();
45 
46  loc = (p1 + p2) * 0.5;
47  loc.y = base;
48 
49  radius = (float) (size * 0.75);
50  heights = new(__FILE__,__LINE__) float[MAX_VERTS];
51 
52  float* pHeight = heights;
53 
54  int i, j;
55 
56  for (i = 0; i < PATCH_SIZE; i++) {
57  int ty = rect.y + i;
58 
59  if (ty < 0)
60  ty = 0;
61 
62  if (ty > patch->Height()-1)
63  ty = patch->Height()-1;
64 
65  for (j = 0; j < PATCH_SIZE; j++) {
66  int tx = rect.x + (PATCH_SIZE-1 - j);
67 
68  if (tx < 0)
69  tx = 0;
70 
71  if (tx > patch->Width()-1)
72  tx = patch->Width()-1;
73 
74  *pHeight++ = (float) (patch->GetColor(tx,ty).Red() * mtnscale);
75  }
76  }
77 }
78 
79 // +--------------------------------------------------------------------+
80 
82 {
83  delete [] heights;
84 }
85 
86 // +--------------------------------------------------------------------+
87 
88 void
89 TerrainApron::SetScales(double s, double m, double b)
90 {
91  scale = s;
92  mtnscale = m;
93  base = b;
94 }
95 
96 // +--------------------------------------------------------------------+
97 
98 bool
100 {
101  int i, j;
102 
103  int detail_size = PATCH_SIZE-1;
104  int ds1 = PATCH_SIZE;
105  int nverts = MAX_VERTS;
106  int npolys = detail_size * detail_size * 2;
107 
108  model = new(__FILE__,__LINE__) Model;
109  model->SetLuminous(true);
110  model->SetDynamic(true);
111 
112  Material* mtl = new(__FILE__,__LINE__) Material;
113  mtl->Ka = ColorValue(0.5f, 0.5f, 0.5f);
114  mtl->Kd = ColorValue(0.3f, 0.6f, 0.2f);
115  mtl->Ks = Color::Black;
116 
117  mtl->tex_diffuse = terrain->ApronTexture();
118  strcpy_s(mtl->name, "Terrain Apron");
119 
120  model->GetMaterials().append(mtl);
121 
122  Surface* s = new(__FILE__,__LINE__) Surface;
123  VertexSet* vset = 0;
124 
125  if (s) {
126  s->SetName("default");
127  s->CreateVerts(nverts);
128  s->CreatePolys(npolys);
129  s->AddIndices(npolys*NUM_INDICES_TRI);
130 
131  vset = s->GetVertexSet();
132 
133  ZeroMemory(vset->loc, nverts * sizeof(Vec3));
134  ZeroMemory(vset->diffuse, nverts * sizeof(DWORD));
135  ZeroMemory(vset->specular, nverts * sizeof(DWORD));
136  ZeroMemory(vset->tu, nverts * sizeof(float));
137  ZeroMemory(vset->tv, nverts * sizeof(float));
138  ZeroMemory(vset->rw, nverts * sizeof(float));
139 
140 
141  // initialize vertices
142  Vec3* pVert = vset->loc;
143  float* pTu = vset->tu;
144  float* pTv = vset->tv;
145  double dt = (1.0/3.0) / (double) detail_size;
146  double tu0 = (double) rect.x / rect.w / 3.0 + (1.0/3.0);
147  double tv0 = (double) rect.y / rect.h / 3.0;
148 
149  for (i = 0; i < ds1; i++) {
150  for (j = 0; j < ds1; j++) {
151  *pVert++ = Vec3((float) (j* scale - (HALF_PATCH_SIZE*scale)),
152  (float) (heights[i*PATCH_SIZE + j]),
153  (float) (i* scale - (HALF_PATCH_SIZE*scale)));
154 
155  *pTu++ = (float) (tu0 - j*dt);
156  *pTv++ = (float) (tv0 + i*dt);
157  }
158  }
159 
160  // create the polys
161  for (i = 0; i < npolys; i++) {
162  Poly* p = s->GetPolys() + i;
163  p->nverts = 3;
164  p->vertex_set = vset;
165  p->material = mtl;
166  p->visible = 1;
167  p->sortval = 0;
168  }
169 
170  int index = 0;
171 
172  // build main patch polys:
173  for (i = 0; i < detail_size; i++) {
174  for (j = 0; j < detail_size; j++) {
175  // first triangle
176  Poly* p = s->GetPolys() + index++;
177  p->verts[0] = (ds1 * (i ) + (j ));
178  p->verts[1] = (ds1 * (i ) + (j+1));
179  p->verts[2] = (ds1 * (i+1) + (j+1));
180 
181  // second triangle
182  p = s->GetPolys() + index++;
183  p->verts[0] = (ds1 * (i ) + (j ));
184  p->verts[1] = (ds1 * (i+1) + (j+1));
185  p->verts[2] = (ds1 * (i+1) + (j ));
186  }
187  }
188 
189  // update the verts and colors of each poly:
190  for (i = 0; i < npolys; i++) {
191  Poly* p = s->GetPolys() + i;
192  Plane& plane = p->plane;
193  WORD* v = p->verts;
194 
195  plane = Plane(vset->loc[v[0]] + loc,
196  vset->loc[v[1]] + loc,
197  vset->loc[v[2]] + loc);
198  }
199 
200  // create continguous segments for each material:
201  s->Normalize();
202 
203  Segment* segment = new(__FILE__,__LINE__) Segment(npolys, s->GetPolys(), mtl, model);
204  s->GetSegments().append(segment);
205 
206  model->AddSurface(s);
207 
208 
209  // copy vertex normals:
210  Vec3 normal = Vec3(0, 1, 0);
211 
212  for (i = 0; i < ds1; i++) {
213  for (j = 0; j < ds1; j++) {
214  vset->nrm[i*ds1+j] = normal;
215  }
216  }
217  }
218 
219  return true;
220 }
221 
222 // +--------------------------------------------------------------------+
223 
224 int
226 {
227  return 0;
228 }
229 
230 // +--------------------------------------------------------------------+
231 
232 void
234 {
235 }
236 
237 // +--------------------------------------------------------------------+
238 
239 void
241 {
242  if (!model || model->NumVerts() < 1) return;
243  Surface* s = model->GetSurfaces().first();
244  if (!s) return;
245 
246  // clear the solid lights to ambient:
247  VertexSet* vset = s->GetVertexSet();
248  int nverts = vset->nverts;
249  DWORD aval = ambient.Value();
250 
251  for (int i = 0; i < nverts; i++) {
252  vset->diffuse[i] = aval;
253  }
254 
255  TerrainRegion* trgn = terrain->GetRegion();
256  bool eclipsed = false;
257 
258  // for each light:
259  ListIter<Light> iter = lights;
260  while (++iter) {
261  Light* light = iter.value();
262 
263  if (light->CastsShadow())
264  eclipsed = light->Location().y < -100;
265 
266  if (!light->CastsShadow() || !eclipsed) {
267  Vec3 vl = light->Location();
268  vl.Normalize();
269 
270  for (int i = 0; i < nverts; i++) {
271  Vec3& nrm = vset->nrm[i];
272  double val = 0;
273 
274  if (light->IsDirectional()) {
275  double gain = vl * nrm;
276 
277  if (gain > 0) {
278  val = light->Intensity() * (0.85 * gain);
279 
280  if (val > 1)
281  val = 1;
282  }
283  }
284 
285  if (val > 0.01)
286  vset->diffuse[i] = ((light->GetColor().dim(val)) + vset->diffuse[i]).Value();
287  }
288  }
289  }
290 
292 }
293 
294 // +--------------------------------------------------------------------+
295 
296 void
297 TerrainApron::Render(Video* video, DWORD flags)
298 {
299  if (!video || (flags & RENDER_ADDITIVE) || (flags & RENDER_ADD_LIGHT)) return;
300 
301  if (!model)
302  BuildApron();
303 
304  if (scene) {
306  }
307 
308  double visibility = terrain->GetRegion()->GetWeather().Visibility();
309  FLOAT fog_density = (FLOAT) (terrain->GetRegion()->FogDensity() * 2.5e-5 * 1/visibility);
310 
311  video->SetRenderState(Video::LIGHTING_ENABLE, false);
312  video->SetRenderState(Video::SPECULAR_ENABLE, false);
313  video->SetRenderState(Video::FOG_ENABLE, true);
315  video->SetRenderState(Video::FOG_DENSITY, *((DWORD*) &fog_density));
316 
317  Solid::Render(video, flags);
318 
321  video->SetRenderState(Video::FOG_ENABLE, false);
322 }
323 
324 // +--------------------------------------------------------------------+
325 
326 int
327 TerrainApron::CheckRayIntersection(Point Q, Point w, double len, Point& ipt, bool ttpas)
328 {
329  // compute leading edge of ray:
330  Point sun = Q + w*len;
331 
332  if (sun.y < loc.y)
333  return 1;
334 
335  return 0;
336 }