Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
CameraView.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: CameraView.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  3D Projection Camera View class
13  uses abstract PolyRender class to draw the triangles
14 */
15 
16 #include "MemDebug.h"
17 #include "CameraView.h"
18 #include "Color.h"
19 #include "Window.h"
20 #include "Scene.h"
21 #include "Light.h"
22 #include "Solid.h"
23 #include "Shadow.h"
24 #include "Sprite.h"
25 #include "Video.h"
26 #include "Bitmap.h"
27 #include "Screen.h"
28 #include "Game.h"
29 
30 // +--------------------------------------------------------------------+
31 
32 void Print(const char* fmt, ...);
33 
34 // +--------------------------------------------------------------------+
35 
36 static Camera emergency_cam;
37 static Scene emergency_scene;
38 
39 // +--------------------------------------------------------------------+
40 
42 : View(c), video(0), camera(cam), projector(c, cam), scene(s),
43 lens_flare_enable(0), halo_bitmap(0), infinite(0),
44 projection_type(Video::PROJECTION_PERSPECTIVE)
45 {
46  elem_bitmap[0] = 0;
47  elem_bitmap[1] = 0;
48  elem_bitmap[2] = 0;
49 
50  if (!camera)
51  camera = &emergency_cam;
52 
53  if (!scene)
54  scene = &emergency_scene;
55 
56  Rect r = window->GetRect();
57  width = r.w;
58  height = r.h;
59 }
60 
62 {
63 }
64 
65 // +--------------------------------------------------------------------+
66 
67 void
69 {
70  if (cam)
71  camera = cam;
72  else
73  camera = &emergency_cam;
74 
76 }
77 
78 void
80 {
81  if (s)
82  scene = s;
83  else
84  scene = &emergency_scene;
85 }
86 
87 void
89 {
91 }
92 
93 double
95 {
96  return projector.GetFieldOfView();
97 }
98 
99 void
101 {
103  projection_type = pt;
104 }
105 
106 DWORD
108 {
109  return projection_type;
110 }
111 
112 void
114 {
115  Rect r = window->GetRect();
117 
118  width = r.w;
119  height = r.h;
120 }
121 
122 
123 // +--------------------------------------------------------------------+
124 // Enable or disable lens flare effect, and provide bitmaps for rendering
125 // +--------------------------------------------------------------------+
126 
127 void
128 CameraView::LensFlare(int on, double dim)
129 {
130  lens_flare_enable = on;
131  lens_flare_dim = dim;
132 }
133 
134 void
136 {
137  if (halo)
138  halo_bitmap = halo;
139 
140  if (e1)
141  elem_bitmap[0] = e1;
142 
143  if (e2)
144  elem_bitmap[1] = e2;
145 
146  if (e3)
147  elem_bitmap[2] = e3;
148 }
149 
150 // +--------------------------------------------------------------------+
151 
152 int
154 {
155  int old = infinite;
156  infinite = i;
158  return old;
159 }
160 
161 // +--------------------------------------------------------------------+
162 // Compute the Depth of a Graphic
163 // +--------------------------------------------------------------------+
164 
165 void
167 {
168  if (infinite) {
169  g->SetDepth(1.0e20f);
170  return;
171  }
172 
173  // Translate into a viewpoint-relative coordinate
174  Vec3 loc = g->Location() - camera->Pos();
175 
176  // Rotate into the view orientation
177  float z = (float) (loc * camera->vpn());
178  g->SetDepth(z);
179 }
180 
181 // +--------------------------------------------------------------------+
182 
183 void
185 {
186  // disabled:
187  if (camera == &emergency_cam)
188  return;
189 
190  // prologue:
192  if (!video)
193  return;
194 
195  int cw = window->Width();
196  int ch = window->Height();
197 
198  cvrt = camera->vrt();
199  cvup = camera->vup();
200  cvpn = camera->vpn();
201 
202  TranslateScene();
204 
205  Rect old_rect;
206  video->GetWindowRect(old_rect);
207 
210  video->SetProjection((float) GetFieldOfView(), 1.0f, 1.0e6f, projection_type);
211 
212  // project and render:
214  RenderScene();
216  RenderSprites();
217  RenderLensFlare();
218 
220 
221  video->SetWindowRect(old_rect);
222 }
223 
224 // +--------------------------------------------------------------------+
225 // Translate all objects and lights to camera relative coordinates:
226 // +--------------------------------------------------------------------+
227 
228 void
230 {
231  camera_loc = camera->Pos();
232 
233  ListIter<Graphic> g_iter = scene->Graphics();
234  while (++g_iter) {
235  Graphic* graphic = g_iter.value();
236 
237  if (!graphic->IsInfinite())
238  graphic->TranslateBy(camera_loc);
239  }
240 
241  g_iter.attach(scene->Foreground());
242  while (++g_iter) {
243  Graphic* graphic = g_iter.value();
244  graphic->TranslateBy(camera_loc);
245  }
246 
247  g_iter.attach(scene->Sprites());
248  while (++g_iter) {
249  Graphic* graphic = g_iter.value();
250 
251  if (!graphic->IsInfinite())
252  graphic->TranslateBy(camera_loc);
253  }
254 
255  ListIter<Light> l_iter = scene->Lights();
256  while (++l_iter) {
257  Light* light = l_iter.value();
258  light->TranslateBy(camera_loc);
259  }
260 
261  camera->MoveTo(0,0,0);
262 }
263 
264 // +--------------------------------------------------------------------+
265 // Translate all objects and lights back to original positions:
266 // +--------------------------------------------------------------------+
267 
268 void
270 {
271  Point reloc = -camera_loc;
272 
273  ListIter<Graphic> g_iter = scene->Graphics();
274  while (++g_iter) {
275  Graphic* graphic = g_iter.value();
276 
277  if (!graphic->IsInfinite())
278  graphic->TranslateBy(reloc);
279  }
280 
281  g_iter.attach(scene->Foreground());
282  while (++g_iter) {
283  Graphic* graphic = g_iter.value();
284  graphic->TranslateBy(reloc);
285  }
286 
287  g_iter.attach(scene->Sprites());
288  while (++g_iter) {
289  Graphic* graphic = g_iter.value();
290 
291  if (!graphic->IsInfinite())
292  graphic->TranslateBy(reloc);
293  }
294 
295  ListIter<Light> l_iter = scene->Lights();
296  while (++l_iter) {
297  Light* light = l_iter.value();
298  light->TranslateBy(reloc);
299  }
300 
302 }
303 
304 // +--------------------------------------------------------------------+
305 // Mark visible objects
306 // +--------------------------------------------------------------------+
307 
308 void
310 {
312  graphics.clear();
313 
314  ListIter<Graphic> graphic_iter = scene->Graphics();
315  while (++graphic_iter) {
316  Graphic* graphic = graphic_iter.value();
317 
318  if (graphic->Hidden())
319  continue;
320 
321  if (graphic->CheckVisibility(projector)) {
322  graphic->Update();
323  graphics.append(graphic);
324  }
325  else {
326  graphic->ProjectScreenRect(0);
327  }
328  }
329 }
330 
331 void
333 {
334  if (flags < Graphic::RENDER_FIRST_LIGHT) {
336  }
337 
338  if (graphic->IsVisible()) {
339  Vec3 eye = camera->Pos();
340 
341  ListIter<Light> light_iter = scene->Lights();
342 
343  while (++light_iter) {
344  Light* light = light_iter.value();
345  bool bright_enough = light->Type() == Light::LIGHT_DIRECTIONAL ||
346  light->Intensity() >= 1e9;
347 
348  if (!bright_enough) {
349  Point test = graphic->Location() - light->Location();
350  if (test.length() < light->Intensity()*10)
351  bright_enough = true;
352  }
353 
354  // turn off lights that won't be used this pass:
355  if (light->CastsShadow()) {
356  if ((flags & Graphic::RENDER_ADD_LIGHT) == 0)
357  bright_enough = false;
358  }
359  else {
360  if ((flags & Graphic::RENDER_FIRST_LIGHT) == 0)
361  bright_enough = false;
362  }
363 
364  double obs_radius = graphic->Radius();
365  if (obs_radius < 100)
366  obs_radius = 100;
367 
368  light->SetActive(bright_enough);
369  }
370  }
371 }
372 
373 // +--------------------------------------------------------------------+
374 
375 void
377 {
378  if (scene->Background().isEmpty()) return;
379 
385 
386  // solid items:
388  while (++iter) {
389  Graphic* g = iter.value();
390 
391  if (!g->Hidden())
393  }
394 
395  // blended items:
396  iter.reset();
397  while (++iter) {
398  Graphic* g = iter.value();
399 
400  if (!g->Hidden())
402  }
403 
404  // glowing items:
405  iter.reset();
406  while (++iter) {
407  Graphic* g = iter.value();
408 
409  if (!g->Hidden())
411  }
412 }
413 
414 // +--------------------------------------------------------------------+
415 
416 void
418 {
419  bool foregroundVisible = false;
420 
422  while (++iter && !foregroundVisible) {
423  Graphic* g = iter.value();
424  if (g && !g->Hidden())
425  foregroundVisible = true;
426  }
427 
428  if (!foregroundVisible)
429  return;
430 
436  video->SetProjection((float) GetFieldOfView(), 1.0f, 1.0e6f, projection_type);
437 
439  // solid items, ambient and non-shadow lights:
440  iter.reset();
441  while (++iter) {
442  Graphic* g = iter.value();
444  }
445 
448 
449  // solid items, shadow lights:
450  iter.reset();
451  while (++iter) {
452  Graphic* g = iter.value();
454  }
455  }
456 
457  else {
458  // solid items:
459  iter.reset();
460  while (++iter) {
461  Graphic* g = iter.value();
463  }
464  }
465 
471 
472  // blended items:
473  iter.reset();
474  while (++iter) {
475  Graphic* g = iter.value();
478  }
479 
480  // glowing items:
481  iter.reset();
482  while (++iter) {
483  Graphic* g = iter.value();
486  }
487 }
488 
489 // +--------------------------------------------------------------------+
490 
491 void
493 {
494  if (scene->Sprites().isEmpty()) return;
495 
501 
502  // compute depth:
503  ListIter<Graphic> iter = scene->Sprites();
504  while (++iter) {
505  Graphic* g = iter.value();
506  if (g && g->IsVisible() && !g->Hidden()) {
507  FindDepth(g);
508  }
509  }
510 
511  // sort the list:
512  scene->Sprites().sort();
513 
514  // blended items:
515  iter.reset();
516  while (++iter) {
517  Graphic* g = iter.value();
519  }
520 
521  // glowing items:
522  iter.reset();
523  while (++iter) {
524  Graphic* g = iter.value();
526  }
527 }
528 
529 // +--------------------------------------------------------------------+
530 // Render the whole scene, sorted back to front
531 // +--------------------------------------------------------------------+
532 
533 void
535 {
536  if (graphics.isEmpty()) return;
537 
538  int i = 0;
539  int ngraphics = graphics.size();
540 
541  // compute depth:
543  while (++iter) {
544  Graphic* g = iter.value();
545  if (g && !g->Hidden()) {
546  FindDepth(g);
547 
548  if (g->IsSolid()) {
549  Solid* solid = (Solid*) g;
550 
551  solid->SelectDetail(&projector);
552 
553  if (video->IsShadowEnabled()) {
555  solid->UpdateShadows(scene->Lights());
556  }
557  }
558  }
559  }
560 
561  // sort the list:
562  graphics.sort();
563 
564  Graphic* g = graphics.last();
565  if (g->Depth() > 5e6) {
566  RenderSceneObjects(true);
568  }
569 
570  RenderSceneObjects(false);
571 }
572 
573 void
575 {
577 
583 
584  if (distant)
585  video->SetProjection((float) GetFieldOfView(), 5.0e6f, 1.0e12f, projection_type);
586  else
587  video->SetProjection((float) GetFieldOfView(), 1.0f, 1.0e6f, projection_type);
588 
590  // solid items, ambient and non-shadow lights:
591  iter.reset();
592  while (++iter) {
593  Graphic* g = iter.value();
594 
595  if (distant && g->Depth() > 5e6 || !distant && g->Depth() < 5e6) {
597  }
598  }
599 
600  // send shadows to stencil buffer:
601  if (video->IsShadowEnabled()) {
602  iter.reset();
603  while (++iter) {
604  Graphic* g = iter.value();
605  if (distant && g->Depth() > 5e6 || !distant && g->Depth() < 5e6) {
606  if (g->IsSolid()) {
607  Solid* solid = (Solid*) g;
608 
609  ListIter<Shadow> shadow_iter = solid->GetShadows();
610  while (++shadow_iter) {
611  Shadow* shadow = shadow_iter.value();
612  shadow->Render(video);
613  }
614  }
615  }
616  }
617  }
618 
622 
623  // solid items, shadow lights:
624  iter.reset();
625  while (++iter) {
626  Graphic* g = iter.value();
627 
628  if (distant && g->Depth() > 5e6 || !distant && g->Depth() < 5e6) {
630  }
631  }
632  }
633 
634  else {
635  // solid items:
636  iter.reset();
637  while (++iter) {
638  Graphic* g = iter.value();
639 
640  if (distant && g->Depth() > 5e6 || !distant && g->Depth() < 5e6) {
642  }
643  }
644  }
645 
651 
652  // blended items:
653  iter.reset();
654  while (++iter) {
655  Graphic* g = iter.value();
656 
657  if (distant && g->Depth() > 5e6 || !distant && g->Depth() < 5e6) {
660  }
661  }
662 
663  // glowing items:
664  iter.reset();
665  while (++iter) {
666  Graphic* g = iter.value();
667 
668  if (distant && g->Depth() > 5e6 || !distant && g->Depth() < 5e6) {
671  }
672  }
673 }
674 
675 void
676 CameraView::Render(Graphic* g, DWORD flags)
677 {
678  if (g && g->IsVisible() && !g->Hidden()) {
679  if (g->IsSolid()) {
680  MarkVisibleLights(g, flags);
682  }
683 
684  g->Render(video, flags);
685  }
686 }
687 
688 // +--------------------------------------------------------------------+
689 // Draw the lens flare effect, if enabled and light source visible
690 // +--------------------------------------------------------------------+
691 
692 void
694 {
695  if (!lens_flare_enable || lens_flare_dim < 0.01)
696  return;
697 
698  if (!halo_bitmap)
699  return;
700 
704 
705  Vec3 flare_pos;
706  Vec3 sun_pos;
707  Vec3 center((float)width/2.0f, (float)height/2.0f, 1.0f);
708  int flare_visible = 0;
709 
710  ListIter<Light> light_iter = scene->Lights();
711  while (++light_iter) {
712  Light* light = light_iter.value();
713 
714  if (!light->IsActive())
715  continue;
716 
717  if (light->Type() == Light::LIGHT_DIRECTIONAL && light->Intensity() < 1)
718  continue;
719 
720  double distance = (light->Location()-camera->Pos()).length();
721 
722  // only do lens flare for the sun:
723  if (distance > 1e9) {
724  if (projector.IsVisible(light->Location(), 1.0f)) {
725  // FOUND IT: TRANSFORM/PROJECT FLARE LOCATION
726  Point sun_pos = light->Location();
727 
728  if (light->CastsShadow() && scene->IsLightObscured(camera->Pos(), sun_pos, -1))
729  continue;
730 
731  projector.Transform(sun_pos);
732 
733  if (sun_pos.z < 100)
734  continue;
735 
736  projector.Project(sun_pos, false);
737 
738  int x = (int) (sun_pos.x);
739  int y = (int) (sun_pos.y);
740  int w = (int) (window->Width() / 4.0);
741  int h = w;
742 
743  // halo:
745 
746  // lens elements:
747  if (elem_bitmap[0]) {
748  Point vector = center - sun_pos;
749  float vlen = (float) vector.length();
750  vector.Normalize();
751 
752  static int nelem = 12;
753  static int elem_indx[] = { 0, 1, 1, 1, 0, 0, 0, 0, 2, 0, 0, 2 };
754  static float elem_dist[] = { -0.2f, 0.5f, 0.55f, 0.62f, 1.23f, 1.33f, 1.35f, 0.8f, 0.9f, 1.4f, 1.7f, 1.8f };
755  static float elem_size[] = { 0.3f, 0.2f, 0.4f, 0.3f, 0.4f, 0.2f, 0.6f, 0.1f, 0.1f, 1.6f, 1.0f, 0.2f };
756 
757  for (int elem = 0; elem < nelem; elem++) {
758  Bitmap* img = elem_bitmap[elem_indx[elem]];
759 
760  /***
761  if (elem == 10)
762  shade *= 0.5;
763  ***/
764 
765  if (img == 0)
766  img = elem_bitmap[0];
767 
768  flare_pos = sun_pos + (vector * elem_dist[elem] * vlen);
769  x = (int) (flare_pos.x);
770  y = (int) (flare_pos.y);
771  w = (int) (window->Width() / 8.0 * elem_size[elem]);
772  h = w;
773 
774  window->DrawBitmap(x-w,y-h,x+w,y+h, img, Video::BLEND_ADDITIVE);
775  }
776  }
777  }
778  }
779  }
780 }
781 
782 // +--------------------------------------------------------------------+
783 // Rotate and translate a plane in world space to view space.
784 // +--------------------------------------------------------------------+
785 
786 void
788 {
789  // Determine the distance from the viewpoint
790  Vec3 tnormal = plane.normal;
791 
792  if (!infinite)
793  plane.distance -= (float) (camera->Pos() * tnormal);
794 
795  // Rotate the normal into view orientation
796  plane.normal.x = tnormal * cvrt;
797  plane.normal.y = tnormal * cvup;
798  plane.normal.z = tnormal * cvpn;
799 }
800 
801 void
803 {
804  projector.SetDepthScale(scale);
805 }