Browse Source

rewrite cameras to use new lens interface

David Rose 24 years ago
parent
commit
b6d41dd8c8
76 changed files with 2924 additions and 1766 deletions
  1. 2 2
      direct/src/directtools/DirectSelection.py
  2. 19 20
      direct/src/directtools/DirectSession.py
  3. 2 2
      direct/src/leveleditor/LevelEditor.py
  4. 29 20
      direct/src/showbase/ShowBase.py
  5. 5 5
      direct/src/showbase/showBase.cxx
  6. 2 2
      direct/src/tkpanels/DirectSessionPanel.py
  7. 8 6
      panda/src/chancfg/chancfg.cxx
  8. 2 2
      panda/src/collide/collide_headers.h
  9. 6 6
      panda/src/collide/collisionRay.I
  10. 13 8
      panda/src/collide/collisionRay.cxx
  11. 3 3
      panda/src/collide/collisionRay.h
  12. 6 6
      panda/src/collide/collisionSegment.I
  13. 10 15
      panda/src/collide/collisionSegment.cxx
  14. 3 3
      panda/src/collide/collisionSegment.h
  15. 1 1
      panda/src/cull/cullTraverser.cxx
  16. 4 4
      panda/src/display/displayRegion.I
  17. 3 3
      panda/src/display/displayRegion.h
  18. 9 7
      panda/src/display/graphicsStateGuardian.I
  19. 4 4
      panda/src/display/graphicsStateGuardian.h
  20. 27 25
      panda/src/dxgsg/dxGraphicsStateGuardian.cxx
  21. 2 2
      panda/src/dxgsg/dxGraphicsStateGuardian.h
  22. 5 6
      panda/src/effects/lensFlareNode.cxx
  23. 4 5
      panda/src/framework/framework.cxx
  24. 32 78
      panda/src/glgsg/glGraphicsStateGuardian.cxx
  25. 2 2
      panda/src/glgsg/glGraphicsStateGuardian.h
  26. 9 8
      panda/src/gobj/Sources.pp
  27. 6 6
      panda/src/gobj/config_gobj.cxx
  28. 3 3
      panda/src/gobj/gobj_composite2.cxx
  29. 367 0
      panda/src/gobj/lens.I
  30. 1291 0
      panda/src/gobj/lens.cxx
  31. 242 0
      panda/src/gobj/lens.h
  32. 0 41
      panda/src/gobj/orthoProjection.I
  33. 0 142
      panda/src/gobj/orthoProjection.cxx
  34. 12 24
      panda/src/gobj/orthographicLens.I
  35. 114 0
      panda/src/gobj/orthographicLens.cxx
  36. 75 0
      panda/src/gobj/orthographicLens.h
  37. 16 14
      panda/src/gobj/perspectiveLens.I
  38. 146 0
      panda/src/gobj/perspectiveLens.cxx
  39. 24 27
      panda/src/gobj/perspectiveLens.h
  40. 0 219
      panda/src/gobj/perspectiveProjection.cxx
  41. 0 79
      panda/src/gobj/perspectiveProjection.h
  42. 0 81
      panda/src/gobj/projection.cxx
  43. 0 72
      panda/src/gobj/projection.h
  44. 2 2
      panda/src/gsgbase/graphicsStateGuardianBase.h
  45. 0 1
      panda/src/light/directionalLight.cxx
  46. 7 8
      panda/src/light/spotlight.cxx
  47. 4 4
      panda/src/light/spotlight.h
  48. 16 0
      panda/src/linmath/cmath.I
  49. 4 0
      panda/src/linmath/cmath.h
  50. 19 0
      panda/src/mathutil/boundingHexahedron.cxx
  51. 4 0
      panda/src/mathutil/boundingHexahedron.h
  52. 3 3
      panda/src/sgattrib/billboardTransition.cxx
  53. 4 4
      panda/src/sgraph/Sources.pp
  54. 6 104
      panda/src/sgraph/camera.cxx
  55. 6 22
      panda/src/sgraph/camera.h
  56. 2 2
      panda/src/sgraph/config_sgraph.cxx
  57. 1 1
      panda/src/sgraph/geomTransformer.cxx
  58. 88 0
      panda/src/sgraph/lensNode.I
  59. 85 0
      panda/src/sgraph/lensNode.cxx
  60. 80 0
      panda/src/sgraph/lensNode.h
  61. 0 367
      panda/src/sgraph/projectionNode.cxx
  62. 0 97
      panda/src/sgraph/projectionNode.h
  63. 1 1
      panda/src/sgraph/sgraph_composite2.cxx
  64. 3 3
      panda/src/sgraphutil/directRenderTraverser.cxx
  65. 21 20
      panda/src/sgraphutil/frustumCullTraverser.I
  66. 3 3
      panda/src/shader/shader.I
  67. 5 5
      panda/src/shader/shader.h
  68. 1 1
      panda/src/shader/spheretexHighlighter.cxx
  69. 11 10
      panda/src/shader/spheretexReflector.cxx
  70. 3 3
      panda/src/switchnode/LODNode.cxx
  71. 0 117
      panda/src/testbed/demo.cxx
  72. 4 4
      panda/src/testbed/herc.cxx
  73. 5 5
      panda/src/testbed/min_herc.cxx
  74. 12 11
      panda/src/testbed/min_shader.cxx
  75. 10 9
      panda/src/testbed/panda.cxx
  76. 6 6
      panda/src/testbed/shader_test.cxx

+ 2 - 2
direct/src/directtools/DirectSelection.py

@@ -487,8 +487,8 @@ class SelectionRay:
 
     def pick(self, targetNodePath, mouseX, mouseY):
         # Determine ray direction based upon the mouse coordinates
-        # Note! This has to be a cam object (of type ProjectionNode)
-        self.ray.setProjection( base.cam.node(), mouseX, mouseY )
+        # Note! This has to be a cam object (of type LensNode)
+        self.ray.setFromLens( base.camNode, mouseX, mouseY )
         self.ct.traverse( targetNodePath.node() )
         self.numEntries = self.cq.getNumEntries()
         self.cq.sortEntries()

+ 19 - 20
direct/src/directtools/DirectSession.py

@@ -782,15 +782,15 @@ class DisplayRegionList(PandaObject):
 
     def setNearFar(self, near, far):
         for dr in self.displayRegionList:
-            dr.camNode.setNearFar(near, far)
+            dr.camLens.setNearFar(near, far)
     
     def setNear(self, near):
         for dr in self.displayRegionList:
-            dr.camNode.setNear(near)
+            dr.camLens.setNear(near)
     
     def setFar(self, far):
         for dr in self.displayRegionList:
-            dr.camNode.setFar(far)
+            dr.camLens.setFar(far)
 
     def setFov(self, hfov, vfov):
         for dr in self.displayRegionList:
@@ -850,7 +850,8 @@ class DisplayRegionContext:
     def __init__(self, win, cam, group):
         self.win = win
         self.cam = cam
-        self.camNode = self.cam.getNode(0)
+        self.camNode = self.cam.node()
+        self.camLens = self.camNode.getLens()
         self.group = group
         self.iRay = SelectionRay(self.cam)
         self.nearVec = Vec3(0)
@@ -889,44 +890,42 @@ class DisplayRegionContext:
     # The following take into consideration sideways displays
     def getHfov(self):
         if self.isSideways:
-            return self.camNode.getVfov()
+            return self.camLens.getVfov()
         else:
-            return self.camNode.getHfov()
+            return self.camLens.getHfov()
 
     def getVfov(self):
         if self.isSideways:
-            return self.camNode.getHfov()
+            return self.camLens.getHfov()
         else:
-            return self.camNode.getVfov()
+            return self.camLens.getVfov()
 
     def setHfov(self,hfov):
         if self.isSideways:
-            self.camNode.setVfov(hfov)
+            self.camLens.setFov(self.camLens.getHfov(), hfov)
         else:
-            self.camNode.setHfov(hfov)
+            self.camLens.setFov(hfov, self.camLens.getVfov())
 
     def setVfov(self,vfov):
         if self.isSideways:
-            self.camNode.setHfov(vfov)
+            self.camLens.setFov(vfov, self.camLens.getVfov())
         else:
-            self.camNode.setVfov(vfov)
+            self.camLens.setFov(self.camLens.getHfov(), vfov)
 
     def setFov(self,hfov,vfov):
         if self.isSideways:
-            self.camNode.setVfov(hfov)
-            self.camNode.setHfov(vfov)
+            self.camLens.setFov(vfov, hfov)
         else:
-            self.camNode.setHfov(hfov)
-            self.camNode.setVfov(vfov)
+            self.camLens.setFov(hfov, vfov)
             
     def camUpdate(self):
         # Window Data
         self.width = self.win.getWidth()
         self.height = self.win.getHeight()
-        self.near = self.camNode.getNear()
-        self.far = self.camNode.getFar()
-        self.fovH = self.camNode.getHfov()
-        self.fovV = self.camNode.getVfov()
+        self.near = self.camLens.getNear()
+        self.far = self.camLens.getFar()
+        self.fovH = self.camLens.getHfov()
+        self.fovV = self.camLens.getVfov()
         self.nearWidth = math.tan(deg2Rad(self.fovH * 0.5)) * self.near * 2.0
         self.nearHeight = math.tan(deg2Rad(self.fovV * 0.5)) * self.near * 2.0
         self.left = -self.nearWidth * 0.5

+ 2 - 2
direct/src/leveleditor/LevelEditor.py

@@ -514,8 +514,8 @@ class LevelEditor(NodePath, PandaObject):
                                            'y-ring', 'y-disc',
                                            'z-post'])
         # Initialize camera
-        base.cam.node().setNear(1.0)
-        base.cam.node().setFar(3000)
+        base.camLens.setNear(1.0)
+        base.camLens.setFar(3000)
         direct.camera.setPos(0,-10,10)
         # Initialize drive mode
         self.configureDriveModeCollisionData()

+ 29 - 20
direct/src/showbase/ShowBase.py

@@ -112,9 +112,14 @@ class ShowBase:
             self.camList.append( camera.find('**/+Camera') )
         # Set the default camera
         self.cam = self.camera.find('**/+Camera')
-        # If you need to use the camera node, use camNode instead
-        # of calling cam.node() to save the FFI overhead
+
+        # If you need to get a handle to the camera node itself, use
+        # self.camNode.
         self.camNode = self.cam.node()
+        # If you need to adjust camera parameters, like fov or
+        # near/far clipping planes, use self.camLens
+        self.camLens = self.camNode.getLens()
+
         # Set up a 2-d layer for drawing things behind Gui labels.
         self.render2d = NodePath(setupPanda2d(self.win, "render2d"))
 
@@ -131,9 +136,7 @@ class ShowBase:
         self.aspect2d.setScale(1.0 / self.aspectRatio, 1.0, 1.0)
 
         # And let's enforce that aspect ratio on the camera.
-        hfov = self.camNode.getHfov()
-        vfov = hfov / self.aspectRatio
-        self.camNode.setFov(hfov, vfov)
+        self.camLens.setAspectRatio(self.aspectRatio)
 
         # It's important to know the bounds of the aspect2d screen.
         self.a2dTop = 1.0
@@ -141,17 +144,6 @@ class ShowBase:
         self.a2dLeft = -self.aspectRatio
         self.a2dRight = self.aspectRatio
 
-        # Set up an auxiliary 3-d layer for rendering floating heads
-        # or other 3-d objects on top of text or widgets in the 2-d
-        # layer.  We set it up with a camera that specifically shares
-        # the projection with the default camera, so that when we
-        # change the default camera's parameters, it changes this one
-        # too.
-        self.renderAux = NodePath(NamedNode('renderAux'))
-        self.camAux = self.renderAux.attachNewNode(Camera('camAux'))
-        self.camAux.node().shareProjection(self.cam.node().getProjection())
-        addRenderLayer(self.win, self.renderAux.node(), self.camAux.node())
-
         # We create both a MouseAndKeyboard object and a MouseWatcher object
         # for the window.  The MouseAndKeyboard generates mouse events and
         # mouse button/keyboard events; the MouseWatcher passes them through
@@ -543,6 +535,10 @@ class ShowBase:
 
             self.oobeCamera = self.hidden.attachNewNode('oobeCamera')
             self.oobeCameraTrackball = self.oobeCamera.attachNewNode('oobeCameraTrackball')
+            self.oobeLens = PerspectiveLens()
+            self.oobeLens.setAspectRatio(self.aspectRatio)
+            self.oobeLens.setNearFar(0.1, 10000.0)
+            self.oobeLens.setFov(52.0)
             self.oobeControl = DataValve.Control()
             self.mouseValve.node().setControl(1, self.oobeControl)
             self.oobeTrackball = self.mouseValve.attachNewNode(Trackball('oobeTrackball'), 1)
@@ -555,6 +551,7 @@ class ShowBase:
             if self.oobeVis:
                 self.oobeVis.arc().setFinal(1)
             self.oobeCullFrustum = None
+            self.oobeCullFrustumVis = None
 
             # Make sure the MouseValve is monitoring the Control key.
             mods = ModifierButtons(self.mouseValve.node().getModifierButtons())
@@ -573,6 +570,7 @@ class ShowBase:
             if self.oobeVis:
                 self.oobeVis.reparentTo(self.hidden)
             self.cam.reparentTo(self.camera)
+            self.camNode.setLens(self.camLens)
             self.oobeCamera.reparentTo(self.hidden)
             self.oobeMode = 0            
         else:
@@ -592,8 +590,7 @@ class ShowBase:
             self.mouseValve.node().setFineControl(0, self.oobeButtonEventsType, self.onControl)
 
             # Make oobeCamera be a sibling of wherever camera is now.
-            cameraParent = NodePath(self.camera)
-            cameraParent.shorten(1)
+            cameraParent = self.camera.getParent()
             self.oobeCamera.reparentTo(cameraParent)
             self.oobeCamera.clearMat()
 
@@ -603,6 +600,7 @@ class ShowBase:
             self.oobeTrackball.node().setMat(mat)
 
             self.cam.reparentTo(self.oobeCameraTrackball)
+            self.camNode.setLens(self.oobeLens)
             if self.oobeVis:
                 self.oobeVis.reparentTo(self.camera)
             self.oobeMode = 1
@@ -623,10 +621,17 @@ class ShowBase:
 
         if self.oobeCullFrustum == None:
             # Enable OOBE culling.
-            pnode = ProjectionNode('oobeCull')
-            pnode.setProjection(self.camNode.getProjection())
+            pnode = LensNode('oobeCull')
+            pnode.setLens(self.camLens)
             self.oobeCullFrustum = self.camera.attachNewNode(pnode)
 
+            # Create a visible representation of the frustum.
+            geom = self.camLens.makeGeometry()
+            if geom != None:
+                gn = GeomNode('frustum')
+                gn.addGeom(geom)
+                self.oobeCullFrustumVis = self.oobeVis.attachNewNode(gn)
+
             # Assign each DisplayRegion shared by the camera to use
             # this cull frustum.
             numDrs = self.camNode.getNumDrs()
@@ -646,6 +651,10 @@ class ShowBase:
             self.oobeCullFrustum.removeNode()
             self.oobeCullFrustum = None
 
+            if self.oobeCullFrustumVis != None:
+                self.oobeCullFrustumVis.removeNode()
+                self.oobeCullFrustumVis = None
+
     def screenshot(self, namePrefix='screenshot'):
         # Get the current date and time to uniquify the image (down to the second)
         date = time.ctime(time.time())

+ 5 - 5
direct/src/showbase/showBase.cxx

@@ -40,8 +40,7 @@
 #include <lightTransition.h>
 #include <materialTransition.h>
 #include <camera.h>
-#include <frustum.h>
-#include <orthoProjection.h>
+#include <orthographicLens.h>
 #include <appTraverser.h>
 #include <get_config_path.h>
 #include <allTransitionsWrapper.h>
@@ -180,9 +179,10 @@ setup_panda_2d(GraphicsWindow *win, const string &graph_name) {
   Camera *cam2d = new Camera("cam2d");
   new RenderRelation(render2d, cam2d);
 
-  Frustumf frustum2d;
-  frustum2d.make_ortho(-1000.0f,1000.0f);
-  cam2d->set_projection(OrthoProjection(frustum2d));
+  PT(Lens) lens = new OrthographicLens;
+  lens->set_film_size(2.0);
+  lens->set_near_far(-1000.0f, 1000.0f);
+  cam2d->set_lens(lens);
 
   add_render_layer(win, render2d_top, cam2d);
 

+ 2 - 2
direct/src/tkpanels/DirectSessionPanel.py

@@ -736,12 +736,12 @@ class DirectSessionPanel(AppShell):
     def setNear(self, near):
         dr = self.activeDisplayRegion
         if dr:
-            dr.camNode.setNear(near)
+            dr.camLens.setNear(near)
 
     def setFar(self, far):
         dr = self.activeDisplayRegion
         if dr:
-            dr.camNode.setFar(far)
+            dr.camLens.setFar(far)
 
     def setHFov(self, hFov):
         dr = self.activeDisplayRegion

+ 8 - 6
panda/src/chancfg/chancfg.cxx

@@ -23,7 +23,7 @@
 #include <hardwareChannel.h>
 #include <camera.h>
 #include <frustum.h>
-#include <perspectiveProjection.h>
+#include <perspectiveLens.h>
 #include <renderRelation.h>
 #include <transformTransition.h>
 #include <dSearchPath.h>
@@ -299,15 +299,17 @@ void ChanConfig::chan_eval(GraphicsWindow* win, WindowItem& W, LayoutItem& L,
          break;
      }
 
-     Frustumf frust;
-     frust.make_perspective(hFov, vFov, 1., 10000.);
-     cam->set_projection(PerspectiveProjection(frust));
+     PT(Lens) lens = new PerspectiveLens;
+     lens->set_fov(hFov, vFov);
+     lens->set_near_far(1.0f, 10000.0f);
+     cam->set_lens(lens);
+
      // hfov and vfov for camera are switched from what was specified
      // if the orientation is sideways.
      if (chancfg_cat->is_debug())
        chancfg_cat->debug() << "ChanEval:: camera hfov = "
-         << cam->get_hfov() << "  vfov = "
-         << cam->get_vfov() << endl;
+         << lens->get_hfov() << "  vfov = "
+         << lens->get_vfov() << endl;
      cam->set_scene(render);
 
      RenderRelation *tocam = new RenderRelation(camera[W.getCameraGroup(j)], cam);

+ 2 - 2
panda/src/collide/collide_headers.h

@@ -26,8 +26,8 @@
 #include <geomLinestrip.h>
 #include <geomNode.h>
 #include <pointerToArray.h>
-#include <projection.h>
-#include <projectionNode.h>
+#include <lens.h>
+#include <lensNode.h>
 #include <renderRelation.h>
 #include <transformTransition.h>
 

+ 6 - 6
panda/src/collide/collisionRay.I

@@ -22,7 +22,7 @@
 //  Description: Creates an invalid ray.  This isn't terribly useful;
 //               it's expected that the user will subsequently adjust
 //               the ray via set_origin()/set_direction() or
-//               set_projection().
+//               set_from_lens().
 ////////////////////////////////////////////////////////////////////
 INLINE CollisionRay::
 CollisionRay() :
@@ -135,15 +135,15 @@ get_direction() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CollisionRay::set_projection
+//     Function: CollisionRay::set_from_lens
 //       Access: Public
-//  Description: Accepts a ProjectionNode and a 2-d point in the range
+//  Description: Accepts a LensNode and a 2-d point in the range
 //               [-1,1].  Sets the CollisionRay so that it begins at
-//               the ProjectionNode's near plane and extends to
+//               the LensNode's near plane and extends to
 //               infinity, making it suitable for picking objects from
 //               the screen given a camera and a mouse location.
 ////////////////////////////////////////////////////////////////////
 INLINE bool CollisionRay::
-set_projection(ProjectionNode *camera, float px, float py) {
-  return set_projection(camera, LPoint2f(px, py));
+set_from_lens(LensNode *camera, float px, float py) {
+  return set_from_lens(camera, LPoint2f(px, py));
 }

+ 13 - 8
panda/src/collide/collisionRay.cxx

@@ -24,8 +24,8 @@
 #include <geomNode.h>
 #include <geomLinestrip.h>
 #include <boundingLine.h>
-#include <projectionNode.h>
-#include <projection.h>
+#include <lensNode.h>
+#include <lens.h>
 
 TypeHandle CollisionRay::_type_handle;
 
@@ -88,11 +88,11 @@ output(ostream &out) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CollisionRay::set_projection
+//     Function: CollisionRay::set_from_lens
 //       Access: Public
-//  Description: Accepts a ProjectionNode and a 2-d point in the range
+//  Description: Accepts a LensNode and a 2-d point in the range
 //               [-1,1].  Sets the CollisionRay so that it begins at
-//               the ProjectionNode's near plane and extends to
+//               the LensNode's near plane and extends to
 //               infinity, making it suitable for picking objects from
 //               the screen given a camera and a mouse location.
 //
@@ -100,15 +100,20 @@ output(ostream &out) const {
 //               otherwise.
 ////////////////////////////////////////////////////////////////////
 bool CollisionRay::
-set_projection(ProjectionNode *camera, const LPoint2f &point) {
-  Projection *proj = camera->get_projection();
+set_from_lens(LensNode *camera, const LPoint2f &point) {
+  Lens *lens = camera->get_lens();
 
   bool success = true;
-  if (!proj->extrude(point, _origin, _direction)) {
+  LPoint3f near_point, far_point;
+  if (!lens->extrude(point, near_point, far_point)) {
     _origin = LPoint3f::origin();
     _direction = LVector3f::forward();
     success = false;
+  } else {
+    _origin = near_point;
+    _direction = far_point - near_point;
   }
+
   mark_bound_stale();
   mark_viz_stale();
 

+ 3 - 3
panda/src/collide/collisionRay.h

@@ -23,7 +23,7 @@
 
 #include "collisionSolid.h"
 
-class ProjectionNode;
+class LensNode;
 
 ///////////////////////////////////////////////////////////////////
 //       Class : CollisionRay
@@ -63,8 +63,8 @@ PUBLISHED:
   INLINE void set_direction(float x, float y, float z);
   INLINE const LVector3f &get_direction() const;
 
-  bool set_projection(ProjectionNode *camera, const LPoint2f &point);
-  INLINE bool set_projection(ProjectionNode *camera, float px, float py);
+  bool set_from_lens(LensNode *camera, const LPoint2f &point);
+  INLINE bool set_from_lens(LensNode *camera, float px, float py);
 
 protected:
   virtual void recompute_bound();

+ 6 - 6
panda/src/collide/collisionSegment.I

@@ -22,7 +22,7 @@
 //  Description: Creates an invalid segment.  This isn't terribly useful;
 //               it's expected that the user will subsequently adjust
 //               the segment via set_origin()/set_direction() or
-//               set_projection().
+//               set_from_lens().
 ////////////////////////////////////////////////////////////////////
 INLINE CollisionSegment::
 CollisionSegment() :
@@ -138,15 +138,15 @@ get_point_b() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CollisionSegment::set_projection
+//     Function: CollisionSegment::set_from_lens
 //       Access: Public
-//  Description: Accepts a ProjectionNode and a 2-d point in the range
+//  Description: Accepts a LensNode and a 2-d point in the range
 //               [-1,1].  Sets the CollisionSegment so that it begins at
-//               the ProjectionNode's near plane and extends to the
+//               the LensNode's near plane and extends to the
 //               far plane, making it suitable for picking objects
 //               from the screen given a camera and a mouse location.
 ////////////////////////////////////////////////////////////////////
 INLINE bool CollisionSegment::
-set_projection(ProjectionNode *camera, float px, float py) {
-  return set_projection(camera, LPoint2f(px, py));
+set_from_lens(LensNode *camera, float px, float py) {
+  return set_from_lens(camera, LPoint2f(px, py));
 }

+ 10 - 15
panda/src/collide/collisionSegment.cxx

@@ -24,8 +24,8 @@
 
 #include <geom.h>
 #include <geomNode.h>
-#include <projectionNode.h>
-#include <projection.h>
+#include <lensNode.h>
+#include <lens.h>
 
 #include <geomLine.h>
 #include <geometricBoundingVolume.h>
@@ -91,11 +91,11 @@ output(ostream &out) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CollisionSegment::set_projection
+//     Function: CollisionSegment::set_from_lens
 //       Access: Public
-//  Description: Accepts a ProjectionNode and a 2-d point in the range
+//  Description: Accepts a LensNode and a 2-d point in the range
 //               [-1,1].  Sets the CollisionSegment so that it begins at
-//               the ProjectionNode's near plane and extends to the
+//               the LensNode's near plane and extends to the
 //               far plane, making it suitable for picking objects
 //               from the screen given a camera and a mouse location.
 //
@@ -103,21 +103,16 @@ output(ostream &out) const {
 //               otherwise.
 ////////////////////////////////////////////////////////////////////
 bool CollisionSegment::
-set_projection(ProjectionNode *camera, const LPoint2f &point) {
-  Projection *proj = camera->get_projection();
+set_from_lens(LensNode *camera, const LPoint2f &point) {
+  Lens *proj = camera->get_lens();
 
   bool success = true;
-  LPoint3f origin;
-  LVector3f direction;
-  if (!proj->extrude(point, origin, direction)) {
-    origin = LPoint3f::origin();
-    direction = LVector3f::forward();
+  if (!proj->extrude(point, _a, _b)) {
+    _a = LPoint3f::origin();
+    _b = _a + LVector3f::forward();
     success = false;
   }
 
-  _a = origin;
-  _b = origin + direction;
-
   mark_bound_stale();
   mark_viz_stale();
 

+ 3 - 3
panda/src/collide/collisionSegment.h

@@ -23,7 +23,7 @@
 
 #include "collisionSolid.h"
 
-class ProjectionNode;
+class LensNode;
 
 ///////////////////////////////////////////////////////////////////
 //       Class : CollisionSegment
@@ -66,8 +66,8 @@ PUBLISHED:
   INLINE void set_point_b(float x, float y, float z);
   INLINE const LPoint3f &get_point_b() const;
 
-  bool set_projection(ProjectionNode *camera, const LPoint2f &point);
-  INLINE bool set_projection(ProjectionNode *camera, float px, float py);
+  bool set_from_lens(LensNode *camera, const LPoint2f &point);
+  INLINE bool set_from_lens(LensNode *camera, float px, float py);
 
 protected:
   virtual void recompute_bound();

+ 1 - 1
panda/src/cull/cullTraverser.cxx

@@ -263,7 +263,7 @@ traverse(Node *root,
   LMatrix4f rel_from_camera;
   NodeTransitionWrapper ntw(TransformTransition::get_class_type());
   const DisplayRegion *dr = _gsg->get_current_display_region();
-  ProjectionNode *camera = dr->get_cull_frustum();
+  LensNode *camera = dr->get_cull_frustum();
   wrt(camera, root, begin(), end(), ntw, get_graph_type());
   const TransformTransition *tt;
   if (get_transition_into(tt, ntw)) {

+ 4 - 4
panda/src/display/displayRegion.I

@@ -105,7 +105,7 @@ get_camera() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::set_cull_frustum
 //       Access: Public
-//  Description: Sets the ProjectionNode that will be used to perform
+//  Description: Sets the LensNode that will be used to perform
 //               view-frustum culling for this particular
 //               DisplayRegion.  Normally, this is the same as the
 //               camera (and is implicitly set when set_camera() is
@@ -115,18 +115,18 @@ get_camera() const {
 //               observed from a third-person perspective.
 ////////////////////////////////////////////////////////////////////
 INLINE void DisplayRegion::
-set_cull_frustum(ProjectionNode *cull_frustum) {
+set_cull_frustum(LensNode *cull_frustum) {
   _cull_frustum = cull_frustum;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::get_cull_frustum
 //       Access: Public
-//  Description: Returns the ProjectionNode that will be used to
+//  Description: Returns the LensNode that will be used to
 //               perform view-frustum culling for this particular
 //               DisplayRegion.  See set_cull_frustum().
 ////////////////////////////////////////////////////////////////////
-INLINE ProjectionNode *DisplayRegion::
+INLINE LensNode *DisplayRegion::
 get_cull_frustum() const {
   return _cull_frustum;
 }

+ 3 - 3
panda/src/display/displayRegion.h

@@ -65,8 +65,8 @@ PUBLISHED:
   void set_camera(Camera *camera);
   INLINE Camera *get_camera() const;
 
-  INLINE void set_cull_frustum(ProjectionNode *cull_frustum);
-  INLINE ProjectionNode *get_cull_frustum() const;
+  INLINE void set_cull_frustum(LensNode *cull_frustum);
+  INLINE LensNode *get_cull_frustum() const;
 
   INLINE void set_active(bool active);
   INLINE bool is_active() const;
@@ -94,7 +94,7 @@ protected:
 
   GraphicsLayer *_layer;
   PT(Camera) _camera;
-  PT(ProjectionNode) _cull_frustum;
+  PT(LensNode) _cull_frustum;
 
   bool _active;
 

+ 9 - 7
panda/src/display/graphicsStateGuardian.I

@@ -129,15 +129,17 @@ get_state() const {
 */
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::get_current_projection_node
+//     Function: GraphicsStateGuardian::get_current_camera
 //       Access: Public
 //  Description: Returns the node currently being used as the
-//               projection node (i.e. the camera) for this scene, as
-//               set by the last call to render_subgraph().
-////////////////////////////////////////////////////////////////////
-INLINE ProjectionNode *GraphicsStateGuardian::
-get_current_projection_node(void) const {
-  return _current_projection_node;
+//               camera for this scene, as set by the last call to
+//               render_subgraph().  This actually might be any kind
+//               of LensNode, not specifically a Camera node, although
+//               it will usually be a Camera.
+////////////////////////////////////////////////////////////////////
+INLINE LensNode *GraphicsStateGuardian::
+get_current_camera(void) const {
+  return _current_camera;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 4 - 4
panda/src/display/graphicsStateGuardian.h

@@ -105,9 +105,9 @@ public:
   virtual void prepare_display_region()=0;
 
   virtual void render_frame()=0;
-  virtual void render_scene(Node *root, ProjectionNode *projnode)=0;
+  virtual void render_scene(Node *root, LensNode *projnode)=0;
   virtual void render_subgraph(RenderTraverser *traverser,
-                               Node *subgraph, ProjectionNode *projnode,
+                               Node *subgraph, LensNode *projnode,
                                const AllTransitionsWrapper &net_trans)=0;
   virtual void render_subgraph(RenderTraverser *traverser,
                                Node *subgraph,
@@ -136,7 +136,7 @@ public:
 
   RenderBuffer get_render_buffer(int buffer_type);
 
-  INLINE ProjectionNode *get_current_projection_node(void) const ;
+  INLINE LensNode *get_current_camera(void) const ;
   INLINE const Node* get_current_root_node(void) const;
 
   INLINE const DisplayRegion *get_current_display_region(void) const;
@@ -222,7 +222,7 @@ protected:
 
   // These must be set by render_scene().
   Node *_current_root_node;
-  ProjectionNode *_current_projection_node;
+  LensNode *_current_camera;
   CPT(DisplayRegion) _current_display_region;
 
   // This is used by wants_normals()

+ 27 - 25
panda/src/dxgsg/dxGraphicsStateGuardian.cxx

@@ -20,7 +20,7 @@
 #include <directRenderTraverser.h>
 #include <cullTraverser.h>
 #include <displayRegion.h>
-#include <projectionNode.h>
+#include <lensNode.h>
 #include <camera.h>
 #include <renderBuffer.h>
 #include <geom.h>
@@ -28,14 +28,13 @@
 #include <geomIssuer.h>
 #include <graphicsWindow.h>
 #include <graphicsChannel.h>
-#include <projection.h>
+#include <lens.h>
 #include <get_rel_pos.h>
-#include <perspectiveProjection.h>
+#include <perspectiveLens.h>
 #include <ambientLight.h>
 #include <directionalLight.h>
 #include <pointLight.h>
 #include <spotlight.h>
-#include <projectionNode.h>
 #include <transformTransition.h>
 #include <colorTransition.h>
 #include <lightTransition.h>
@@ -1611,12 +1610,12 @@ report_texmgr_stats() {
 //     Function: DXGraphicsStateGuardian::render_scene
 //       Access: Public, Virtual
 //  Description: Renders an entire scene, from the root node of the
-//               scene graph, as seen from a particular ProjectionNode
+//               scene graph, as seen from a particular LensNode
 //               and with a given initial state.  This initial state
 //               may be modified during rendering.
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::
-render_scene(Node *root, ProjectionNode *projnode) {
+render_scene(Node *root, LensNode *projnode) {
 #ifdef GSG_VERBOSE
     _pass_number = 0;
     dxgsg_cat.debug()
@@ -1639,28 +1638,31 @@ render_scene(Node *root, ProjectionNode *projnode) {
 //     Function: DXGraphicsStateGuardian::render_subgraph
 //       Access: Public, Virtual
 //  Description: Renders a subgraph of the scene graph as seen from a
-//               given projection node, and with a particular initial
+//               given lens node, and with a particular initial
 //               state.  This state may be modified by the render
 //               process.
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::
 render_subgraph(RenderTraverser *traverser,
-                Node *subgraph, ProjectionNode *projnode,
+                Node *subgraph, LensNode *projnode,
                 const AllTransitionsWrapper &net_trans) {
-    ProjectionNode *old_projection_node = _current_projection_node;
-    _current_projection_node = projnode;
+    LensNode *old_camera = _current_camera;
+    _current_camera = projnode;
     LMatrix4f old_projection_mat = _current_projection_mat;
 
+    Lens *lens = projnode->get_lens();
+    const LMatrix4f &projection_mat = lens->get_projection_mat();
+
     // d3d is left-handed coord system
-    LMatrix4f projection_mat = projnode->get_projection()->get_projection_mat(CS_yup_left);
+    _current_projection_mat = 
+      LMatrix4f::convert_mat(CS_yup_left, lens->get_coordinate_system()) *
+      projection_mat;
+    _projection_mat_stack_count++;
 
 #if 0
-    dxgsg_cat.spam() << "cur projection matrix: " << projection_mat <<"\n";
+    dxgsg_cat.spam() << "cur projection matrix: " << _current_projection_mat <<"\n";
 #endif
 
-    _current_projection_mat = projection_mat;
-    _projection_mat_stack_count++;
-
 #ifdef _DEBUG
    {
       static bool bPrintedMsg=false;
@@ -1686,8 +1688,8 @@ render_subgraph(RenderTraverser *traverser,
     // We infer the modelview matrix by doing a wrt on the projection
     // node.
     LMatrix4f modelview_mat;
-    get_rel_mat(subgraph, _current_projection_node, modelview_mat);  //needs reversal from glgsg, probably due D3D LH coordsys
-//  get_rel_mat(_current_projection_node, subgraph, modelview_mat);
+    get_rel_mat(subgraph, _current_camera, modelview_mat);  //needs reversal from glgsg, probably due D3D LH coordsys
+//  get_rel_mat(_current_camera, subgraph, modelview_mat);
 
     if (_coordinate_system != CS_yup_left) {
         // Now we build the coordinate system conversion into the
@@ -1704,7 +1706,7 @@ render_subgraph(RenderTraverser *traverser,
 
     render_subgraph(traverser, subgraph, sub_trans);
 
-    _current_projection_node = old_projection_node;
+    _current_camera = old_camera;
     _current_projection_mat = old_projection_mat;
     _projection_mat_stack_count--;
 
@@ -1720,7 +1722,7 @@ render_subgraph(RenderTraverser *traverser,
 //     Function: DXGraphicsStateGuardian::render_subgraph
 //       Access: Public, Virtual
 //  Description: Renders a subgraph of the scene graph as seen from the
-//               current projection node, and with a particular
+//               current lens node, and with a particular
 //               initial state.  This state may be modified during the
 //               render process.
 ////////////////////////////////////////////////////////////////////
@@ -2484,8 +2486,8 @@ draw_sprite(GeomSprite *geom, GeomContext *gc) {
         modelview_mat = ctatt->get_matrix();
 
     // get the camera information
-    float aspect_ratio;
-    aspect_ratio = _actual_display_region->get_camera()->get_aspect();
+    float aspect_ratio =
+      get_current_camera()->get_lens()->get_aspect_ratio();
 
     // null the world xform, so sprites are orthog to scrn  (but not necessarily camera pnt unless they lie along z-axis)
     _d3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matIdentity);
@@ -4574,7 +4576,7 @@ apply_fog(Fog *fog) {
                 // properties.
                 float fog_start, fog_end;
                 fog->compute_linear_range(fog_start, fog_end,
-                                          _current_projection_node,
+                                          _current_camera,
                                           _coordinate_system);
 
                 _d3dDevice->SetRenderState( D3DRENDERSTATE_FOGSTART,
@@ -4647,7 +4649,7 @@ void DXGraphicsStateGuardian::apply_light( DirectionalLight* light ) {
     alight.dcvSpecular = *(D3DCOLORVALUE *)(light->get_specular().get_data());
 
     alight.dvDirection = *(D3DVECTOR *)
-                         (get_rel_forward( light, _current_projection_node, CS_yup_left).get_data());
+                         (get_rel_forward( light, _current_camera, CS_yup_left).get_data());
 
     alight.dvRange =  D3DLIGHT_RANGE_MAX;
     alight.dvFalloff =  1.0f;
@@ -4692,12 +4694,12 @@ void DXGraphicsStateGuardian::apply_light( Spotlight* light ) {
 
     // Position needs to specify x, y, z, and w
     // w == 1 implies non-infinite position
-    LPoint3f pos = get_rel_pos( light, _current_projection_node );
+    LPoint3f pos = get_rel_pos( light, _current_camera );
     LPoint4f fpos( pos[0], pos[1], pos[2], 1 );
     glLightfv( id, GL_POSITION, fpos.get_data() );
 
     glLightfv( id, GL_SPOT_DIRECTION,
-               get_rel_forward( light, _current_projection_node,
+               get_rel_forward( light, _current_camera,
                                 _coordinate_system ).get_data() );
     glLightf( id, GL_SPOT_EXPONENT, light->get_exponent() );
     glLightf( id, GL_SPOT_CUTOFF,

+ 2 - 2
panda/src/dxgsg/dxGraphicsStateGuardian.h

@@ -137,9 +137,9 @@ public:
   virtual void prepare_display_region();
 
   virtual void render_frame();
-  virtual void render_scene(Node *root, ProjectionNode *projnode);
+  virtual void render_scene(Node *root, LensNode *projnode);
   virtual void render_subgraph(RenderTraverser *traverser,
-                   Node *subgraph, ProjectionNode *projnode,
+                   Node *subgraph, LensNode *projnode,
                    const AllTransitionsWrapper &net_trans);
   virtual void render_subgraph(RenderTraverser *traverser,
                    Node *subgraph,

+ 5 - 6
panda/src/effects/lensFlareNode.cxx

@@ -28,8 +28,7 @@
 #include "transformTransition.h"
 #include "transparencyTransition.h"
 #include "renderTraverser.h"
-#include "orthoProjection.h"
-#include "perspectiveProjection.h"
+#include "lens.h"
 #include "get_rel_pos.h"
 #include "clockObject.h"
 #include "allTransitionsWrapper.h"
@@ -313,8 +312,8 @@ sub_render(const AllTransitionsWrapper &input_trans,
   nassertr(_light_node != (Node*) NULL, false);
 
   //First we need the light position
-  ProjectionNode *camera_node = gsg->get_current_projection_node();
-  PerspectiveProjection *pp = DCAST(PerspectiveProjection, camera_node->get_projection());
+  LensNode *camera_node = gsg->get_current_camera();
+  Lens *lens = camera_node->get_lens();
 
   LPoint3f light_pos = get_rel_pos(_light_node, camera_node);
 
@@ -336,7 +335,7 @@ sub_render(const AllTransitionsWrapper &input_trans,
   //doing everything in camera space, this should merely be the
   //distance between the camera and the near clipping plane projected
   //along Y into the screen
-  LPoint3f center = LPoint3f::origin() + LPoint3f::rfu(0,pp->get_frustum()._fnear,0);
+  LPoint3f center = LPoint3f::origin() + LPoint3f::rfu(0,lens->get_near(),0);
   center = center * inv_light_mat * modelview_mat;
 
   //Now lets get the vector from the light to the center.
@@ -354,7 +353,7 @@ sub_render(const AllTransitionsWrapper &input_trans,
   dot = (dot < 0.0f) ? -dot : dot;
 
   prepare_flares(delta, light_pos, dot);
-  prepare_blind(dot, pp->get_frustum()._fnear);
+  prepare_blind(dot, lens->get_near());
 
   render_children(_flare_arcs, input_trans, gsg);
   render_child(_blind_arc, input_trans, gsg);

+ 4 - 5
panda/src/framework/framework.cxx

@@ -85,7 +85,7 @@
 #include "textNode.h"
 #include "depthTestTransition.h"
 #include "depthWriteTransition.h"
-#include "orthoProjection.h"
+#include "orthographicLens.h"
 #include "transparencyTransition.h"
 #include "bamReader.h"
 #include "collisionRay.h"
@@ -491,10 +491,9 @@ void setup_framerate(void) {
   PT(Camera) cam2d = new Camera("framerate_cam");
   new RenderRelation(framerate_node, cam2d);
   cam2d->set_scene(framerate_top);
-
-  Frustumf frustum2d;
-  frustum2d.make_ortho_2D();
-  cam2d->set_projection(OrthoProjection(frustum2d));
+  PT(Lens) lens = new OrthographicLens;
+  lens->set_film_size(2.0);
+  cam2d->set_lens(lens);
 
   // Now create a new layer
   // eventually this should be done through chanconfig'

+ 32 - 78
panda/src/glgsg/glGraphicsStateGuardian.cxx

@@ -26,22 +26,22 @@
 #include "directRenderTraverser.h"
 #include "cullTraverser.h"
 #include "displayRegion.h"
-#include "projectionNode.h"
+#include "lensNode.h"
 #include "camera.h"
 #include "renderBuffer.h"
 #include "geom.h"
 #include "geomIssuer.h"
 #include "graphicsWindow.h"
 #include "graphicsChannel.h"
-#include "projection.h"
+#include "lens.h"
 #include "get_rel_pos.h"
-#include "perspectiveProjection.h"
+#include "perspectiveLens.h"
 #include "ambientLight.h"
 #include "directionalLight.h"
 #include "pointLight.h"
 #include "spotlight.h"
 #include "GL/glu.h"
-#include "projectionNode.h"
+#include "lensNode.h"
 #include "transformTransition.h"
 #include "colorMatrixTransition.h"
 #include "alphaTransformTransition.h"
@@ -568,12 +568,12 @@ render_frame() {
 //     Function: GLGraphicsStateGuardian::render_scene
 //       Access: Public, Virtual
 //  Description: Renders an entire scene, from the root node of the
-//               scene graph, as seen from a particular ProjectionNode
+//               scene graph, as seen from a particular LensNode
 //               and with a given initial state.  This initial state
 //               may be modified during rendering.
 ////////////////////////////////////////////////////////////////////
 void GLGraphicsStateGuardian::
-render_scene(Node *root, ProjectionNode *projnode) {
+render_scene(Node *root, LensNode *projnode) {
 #ifdef GSG_VERBOSE
   _pass_number = 0;
   glgsg_cat.debug()
@@ -596,13 +596,13 @@ render_scene(Node *root, ProjectionNode *projnode) {
 //     Function: GLGraphicsStateGuardian::render_subgraph
 //       Access: Public, Virtual
 //  Description: Renders a subgraph of the scene graph as seen from a
-//               given projection node, and with a particular initial
+//               given lens node, and with a particular initial
 //               state.  This state may be modified by the render
 //               process.
 ////////////////////////////////////////////////////////////////////
 void GLGraphicsStateGuardian::
 render_subgraph(RenderTraverser *traverser,
-                Node *subgraph, ProjectionNode *projnode,
+                Node *subgraph, LensNode *projnode,
                 const AllTransitionsWrapper &net_trans) {
   // Calling activate() frequently seems to be intolerably expensive
   // on some platforms.  We'll limit ourselves for now to calling it
@@ -610,34 +610,37 @@ render_subgraph(RenderTraverser *traverser,
 
   //  activate();
 
-  ProjectionNode *old_projection_node = _current_projection_node;
-  _current_projection_node = projnode;
+  LensNode *old_camera = _current_camera;
+  _current_camera = projnode;
   LMatrix4f old_projection_mat = _current_projection_mat;
 
+  Lens *lens = projnode->get_lens();
+  const LMatrix4f &projection_mat = lens->get_projection_mat();
+
   // The projection matrix must always be right-handed Y-up, even if
   // our coordinate system of choice is otherwise, because certain GL
   // calls (specifically glTexGen(GL_SPHERE_MAP)) assume this kind of
-  // a coordinate system.  Sigh.  In order to implement a Z-up
-  // coordinate system, we'll store the Z-up conversion in the
-  // modelview matrix.
-  LMatrix4f projection_mat =
-    projnode->get_projection()->get_projection_mat(CS_yup_right);
-
-  _current_projection_mat = projection_mat;
+  // a coordinate system.  Sigh.  In order to implement a Z-up (or
+  // other arbitrary) coordinate system, we'll use a Y-up projection
+  // matrix, and store the conversion to our coordinate system of
+  // choice in the modelview matrix.
+  _current_projection_mat =
+    LMatrix4f::convert_mat(CS_yup_right, lens->get_coordinate_system()) *
+    projection_mat;
   _projection_mat_stack_count++;
 
   // We load the projection matrix directly.
 #ifdef GSG_VERBOSE
   glgsg_cat.debug()
-    << "glMatrixMode(GL_PROJECTION): " << projection_mat << endl;
+    << "glMatrixMode(GL_PROJECTION): " << _current_projection_mat << endl;
 #endif
   glMatrixMode(GL_PROJECTION);
   glLoadMatrixf(_current_projection_mat.get_data());
 
-  // We infer the modelview matrix by doing a wrt on the projection
+  // We infer the modelview matrix by doing a wrt on the lens
   // node.
   LMatrix4f modelview_mat;
-  get_rel_mat(subgraph, _current_projection_node, modelview_mat);
+  get_rel_mat(subgraph, _current_camera, modelview_mat);
 
   if (_coordinate_system != CS_yup_right) {
     // Now we build the coordinate system conversion into the
@@ -654,7 +657,7 @@ render_subgraph(RenderTraverser *traverser,
 
   render_subgraph(traverser, subgraph, sub_trans);
 
-  _current_projection_node = old_projection_node;
+  _current_camera = old_camera;
   _current_projection_mat = old_projection_mat;
   _projection_mat_stack_count--;
 
@@ -673,7 +676,7 @@ render_subgraph(RenderTraverser *traverser,
 //     Function: GLGraphicsStateGuardian::render_subgraph
 //       Access: Public, Virtual
 //  Description: Renders a subgraph of the scene graph as seen from the
-//               current projection node, and with a particular
+//               current lens node, and with a particular
 //               initial state.  This state may be modified during the
 //               render process.
 ////////////////////////////////////////////////////////////////////
@@ -999,40 +1002,8 @@ draw_sprite(GeomSprite *geom, GeomContext *) {
     modelview_mat = ctatt->get_matrix();
 
   // get the camera information
-  float aspect_ratio = _actual_display_region->get_camera()->get_aspect();
-
-  // Note on DO_CHARLES_PROJECTION_MAT
-  // apparently adjusting the projection as done below is incorrect
-  // as long as the camera points forward at the view plane, no distortion/warping
-  // will be apparent, which is what this special projection was supposed to correct
-
-#ifdef DO_CHARLES_PROJECTION_MAT
-  // to assure that the scale between the two frustra stays the same
-  // (if they are different, sprites move at different speeds than the world),
-  // we have to apply the frustum inverse to the point, then render it in our
-  // own frustum.  Since the z values are identical and 1:1, we only need
-  // concern ourselves with the x and y mappings, which are conveniently linear.
-
-  float x_frustum_scale, y_frustum_scale;
-  float recip_x_frustum_scale, recip_y_frustum_scale;
-  float tnear, tfar, hfov;
-
-  // get the camera information
-  tnear = _actual_display_region->get_camera()->get_near();
-  tfar = _actual_display_region->get_camera()->get_far();
-  hfov = _actual_display_region->get_camera()->get_hfov();
-
-  // extract the left and top bounds of the current camera
-  x_frustum_scale = tanf(hfov * 0.5f * (3.1415926f / 180.0f)) * tnear;
-  recip_x_frustum_scale = 1.0f / x_frustum_scale;
-  y_frustum_scale = x_frustum_scale / aspect_ratio;
-  recip_y_frustum_scale = 1.0f / y_frustum_scale;
-
-  // load up our own matrices
-  glMatrixMode(GL_PROJECTION);
-  glLoadIdentity();
-  glFrustum(-1.0f, 1.0f, -1.0f, 1.0f, tnear, tfar);
-#endif
+  float aspect_ratio = 
+    get_current_camera()->get_lens()->get_aspect_ratio();
 
   // load up our own matrices
   glMatrixMode(GL_MODELVIEW);
@@ -1123,21 +1094,8 @@ draw_sprite(GeomSprite *geom, GeomContext *) {
 
     // this mult converts to y-up cameraspace.
     cameraspace_vert = source_vert * modelview_mat;
-
-#ifdef DO_CHARLES_PROJECTION_MAT
-    float x,y,z;
-
-    // do the inverse transform on the cameraspace point.
-    x = cameraspace_vert[0] ;//* recip_x_frustum_scale;
-    y = cameraspace_vert[1] ;//* recip_y_frustum_scale;
-    z = cameraspace_vert[2];
-
-    // build the final object that will go into the vector.
-    ws._v.set(x, y, z);
-#else
     // build the final object that will go into the vector.
     ws._v.set(cameraspace_vert[0],cameraspace_vert[1],cameraspace_vert[2]);
-#endif
 
     if (color_overall == false)
       ws._c = geom->get_next_color(ci);
@@ -1234,10 +1192,6 @@ draw_sprite(GeomSprite *geom, GeomContext *) {
   if(alpha && _dithering_enabled)
      glEnable(GL_DITHER);
 
-#ifdef DO_CHARLES_PROJECTION_MAT
-  glMatrixMode(GL_PROJECTION);
-  glLoadMatrixf(_current_projection_mat.get_data());
-#endif
   report_errors();
   _draw_primitive_pcollector.stop();
 }
@@ -2465,7 +2419,7 @@ apply_fog(Fog *fog) {
     // object knows how to decode its parameters into camera-relative
     // properties.
     float onset, opaque;
-    fog->compute_linear_range(onset, opaque, _current_projection_node,
+    fog->compute_linear_range(onset, opaque, _current_camera,
                               _coordinate_system);
     call_glFogStart(onset);
     call_glFogEnd(opaque);
@@ -2511,7 +2465,7 @@ void GLGraphicsStateGuardian::apply_light( PointLight* light )
 
     // Position needs to specify x, y, z, and w
     // w == 1 implies non-infinite position
-  LPoint3f pos = get_rel_pos( light, _current_projection_node );
+  LPoint3f pos = get_rel_pos( light, _current_camera );
   LPoint4f fpos( pos[0], pos[1], pos[2], 1 );
   glLightfv( id, GL_POSITION, fpos.get_data() );
 
@@ -2570,7 +2524,7 @@ void GLGraphicsStateGuardian::apply_light( DirectionalLight* light )
 
     // Position needs to specify x, y, z, and w
     // w == 0 implies light is at infinity
-  LPoint3f dir = get_rel_forward( light, _current_projection_node,
+  LPoint3f dir = get_rel_forward( light, _current_camera,
                                   _coordinate_system );
   LPoint4f pos( -dir[0], -dir[1], -dir[2], 0 );
   glLightfv( id, GL_POSITION, pos.get_data() );
@@ -2628,12 +2582,12 @@ void GLGraphicsStateGuardian::apply_light( Spotlight* light )
 
     // Position needs to specify x, y, z, and w
     // w == 1 implies non-infinite position
-  LPoint3f pos = get_rel_pos( light, _current_projection_node );
+  LPoint3f pos = get_rel_pos( light, _current_camera );
   LPoint4f fpos( pos[0], pos[1], pos[2], 1 );
   glLightfv( id, GL_POSITION, fpos.get_data() );
 
   glLightfv( id, GL_SPOT_DIRECTION,
-             get_rel_forward( light, _current_projection_node,
+             get_rel_forward( light, _current_camera,
                               _coordinate_system ).get_data() );
   glLightf( id, GL_SPOT_EXPONENT, light->get_exponent() );
   glLightf( id, GL_SPOT_CUTOFF,

+ 2 - 2
panda/src/glgsg/glGraphicsStateGuardian.h

@@ -76,9 +76,9 @@ public:
   virtual void prepare_display_region();
 
   virtual void render_frame();
-  virtual void render_scene(Node *root, ProjectionNode *projnode);
+  virtual void render_scene(Node *root, LensNode *projnode);
   virtual void render_subgraph(RenderTraverser *traverser,
-                               Node *subgraph, ProjectionNode *projnode,
+                               Node *subgraph, LensNode *projnode,
                                const AllTransitionsWrapper &net_trans);
   virtual void render_subgraph(RenderTraverser *traverser,
                                Node *subgraph,

+ 9 - 8
panda/src/gobj/Sources.pp

@@ -4,7 +4,7 @@
 #begin lib_target
   #define TARGET gobj
   #define LOCAL_LIBS \
-    linmath mathutil pnmimage gsgbase graph putil
+    event linmath mathutil pnmimage gsgbase graph putil
 
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx 
 
@@ -14,9 +14,9 @@
      geomQuad.h geomSphere.h geomSprite.I geomSprite.h geomTri.h  \
      geomTrifan.h geomTristrip.h imageBuffer.I imageBuffer.h  \
      material.I material.h materialPool.I materialPool.h  \
-     orthoProjection.I orthoProjection.h perspectiveProjection.I  \
-     perspectiveProjection.h pixelBuffer.I pixelBuffer.N  \
-     pixelBuffer.h projection.h \
+     orthographicLens.I orthographicLens.h perspectiveLens.I  \
+     perspectiveLens.h pixelBuffer.I pixelBuffer.N  \
+     pixelBuffer.h lens.h lens.I \
      savedContext.I savedContext.h \
      texture.I texture.N texture.h \
      textureContext.I textureContext.h \
@@ -27,8 +27,8 @@
      geomLine.cxx geomLinestrip.cxx geomPoint.cxx geomPolygon.cxx  \
      geomQuad.cxx geomSphere.cxx geomSprite.cxx geomTri.cxx  \
      geomTrifan.cxx geomTristrip.cxx imageBuffer.cxx material.cxx  \
-     materialPool.cxx orthoProjection.cxx  \
-     perspectiveProjection.cxx pixelBuffer.cxx projection.cxx  \
+     materialPool.cxx orthographicLens.cxx  \
+     perspectiveLens.cxx pixelBuffer.cxx lens.cxx  \
      savedContext.cxx texture.cxx textureContext.cxx texturePool.cxx
 
   #define INSTALL_HEADERS \
@@ -38,8 +38,9 @@
     geomSprite.I geomSprite.h geomTri.h geomTrifan.h geomTristrip.h \
     geomprimitives.h imageBuffer.I imageBuffer.h material.I material.h \
     materialPool.I materialPool.h \
-    orthoProjection.I orthoProjection.h perspectiveProjection.I \
-    perspectiveProjection.h pixelBuffer.I pixelBuffer.h projection.h \
+    orthographicLens.I orthographicLens.h perspectiveLens.I \
+    perspectiveLens.h pixelBuffer.I pixelBuffer.h \
+    lens.h lens.I \
     savedContext.I savedContext.h \
     texture.I texture.h \
     textureContext.I textureContext.h \

+ 6 - 6
panda/src/gobj/config_gobj.cxx

@@ -24,10 +24,10 @@
 #include "geomprimitives.h"
 #include "imageBuffer.h"
 #include "material.h"
-#include "orthoProjection.h"
-#include "perspectiveProjection.h"
+#include "orthographicLens.h"
+#include "perspectiveLens.h"
 #include "pixelBuffer.h"
-#include "projection.h"
+#include "lens.h"
 #include "texture.h"
 
 #include <dconfig.h>
@@ -176,10 +176,10 @@ ConfigureFn(config_gobj) {
   ImageBuffer::init_type();
   LOD::init_type();
   Material::init_type();
-  OrthoProjection::init_type();
-  PerspectiveProjection::init_type();
+  OrthographicLens::init_type();
+  PerspectiveLens::init_type();
   PixelBuffer::init_type();
-  Projection::init_type();
+  Lens::init_type();
   Texture::init_type();
   dDrawable::init_type();
 

+ 3 - 3
panda/src/gobj/gobj_composite2.cxx

@@ -5,10 +5,10 @@
 #include "imageBuffer.cxx"
 #include "material.cxx"
 #include "materialPool.cxx"
-#include "orthoProjection.cxx"
-#include "perspectiveProjection.cxx"
+#include "orthographicLens.cxx"
+#include "perspectiveLens.cxx"
 #include "pixelBuffer.cxx"
-#include "projection.cxx"
+#include "lens.cxx"
 #include "savedContext.cxx"
 #include "texture.cxx"
 #include "textureContext.cxx"

+ 367 - 0
panda/src/gobj/lens.I

@@ -0,0 +1,367 @@
+// Filename: lens.I
+// Created by:  drose (29Nov01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::extrude
+//       Access: Published
+//  Description: Given a 2-d point in the range (-1,1) in both
+//               dimensions, where (0,0) is the center of the
+//               lens and (-1,-1) is the lower-left corner,
+//               compute the corresponding vector in space that maps
+//               to this point, if such a vector can be determined.
+//               The vector is returned by indicating the points on
+//               the near plane and far plane that both map to the
+//               indicated 2-d point.
+//
+//               Returns true if the vector is defined, or false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool Lens::
+extrude(const LPoint2f &point2d, LPoint3f &near_point, LPoint3f &far_point) const {
+  return extrude_impl(LPoint3f(point2d[0], point2d[1], 0.0f),
+                      near_point, far_point);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::extrude
+//       Access: Published
+//  Description: Given a 2-d point in the range (-1,1) in both
+//               dimensions, where (0,0) is the center of the
+//               lens and (-1,-1) is the lower-left corner,
+//               compute the corresponding vector in space that maps
+//               to this point, if such a vector can be determined.
+//               The vector is returned by indicating the points on
+//               the near plane and far plane that both map to the
+//               indicated 2-d point.
+//
+//               The z coordinate of the 2-d point is ignored.
+//
+//               Returns true if the vector is defined, or false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool Lens::
+extrude(const LPoint3f &point2d, LPoint3f &near_point, LPoint3f &far_point) const {
+  return extrude_impl(point2d, near_point, far_point);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::project
+//       Access: Published
+//  Description: Given a 3-d point in space, determine the 2-d point
+//               this maps to, in the range (-1,1) in both dimensions,
+//               where (0,0) is the center of the lens and
+//               (-1,-1) is the lower-left corner.
+//
+//               Returns true if the 3-d point is in front of the lens
+//               and within the viewing frustum (in which case point2d
+//               is filled in), or false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool Lens::
+project(const LPoint3f &point3d, LPoint2f &point2d) const {
+  LPoint3f result;
+  if (project_impl(point3d, result)) {
+    point2d.set(result[0], result[1]);
+    return true;
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::project
+//       Access: Published
+//  Description: Given a 3-d point in space, determine the 2-d point
+//               this maps to, in the range (-1,1) in both dimensions,
+//               where (0,0) is the center of the lens and
+//               (-1,-1) is the lower-left corner.
+//
+//               Some lens types also set the z coordinate of the 2-d
+//               point to a value in the range (-1, 1), where 1
+//               represents a point on the near plane, and -1
+//               represents a point on the far plane.
+//
+//               Returns true if the 3-d point is in front of the lens
+//               and within the viewing frustum (in which case point2d
+//               is filled in), or false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool Lens::
+project(const LPoint3f &point3d, LPoint3f &point2d) const {
+  return project_impl(point3d, point2d);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_change_event
+//       Access: Published
+//  Description: Sets the name of the event that will be generated
+//               whenever any properties of the Lens have
+//               changed.  This can be used to automatically track
+//               changes to camera fov, etc. in the simulation.
+////////////////////////////////////////////////////////////////////
+INLINE void Lens::
+set_change_event(const string &event) {
+  _change_event = event;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_change_event
+//       Access: Published
+//  Description: Returns the name of the event that will be generated
+//               whenever any properties of the Lens have
+//               changed.
+////////////////////////////////////////////////////////////////////
+INLINE const string &Lens::
+get_change_event() const {
+  return _change_event;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_coordinate_system
+//       Access: Published
+//  Description: Returns the coordinate system that all 3-d
+//               computations are performed within for this
+//               Lens.  Normally, this is CS_default.
+////////////////////////////////////////////////////////////////////
+INLINE CoordinateSystem Lens::
+get_coordinate_system() const {
+  return _cs;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_film_size
+//       Access: Published
+//  Description: Sets the size and shape of the "film" within the
+//               lens.  This both establishes the units used by
+//               calls like set_focal_length(), and establishes the
+//               aspect ratio of the frame.
+//
+//               In a physical camera, the field of view of a lens is
+//               determined by the lens' focal length and by the size
+//               of the film area exposed by the lens.  For instance,
+//               a 35mm camera exposes a rectangle on the film about
+//               24mm x 36mm, which means a 50mm lens gives about a
+//               40-degree horizontal field of view.
+//
+//               In the virtual camera, you may set the film size to
+//               any units here, and specify a focal length in the
+//               same units to simulate the same effect.  Or, you may
+//               ignore this parameter, and specify the field of view
+//               and aspect ratio of the lens directly.
+////////////////////////////////////////////////////////////////////
+INLINE void Lens::
+set_film_size(float width, float height) {
+  set_film_size(LVecBase2f(width, height));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_film_offset
+//       Access: Published
+//  Description: Sets the horizontal and vertical offset amounts of
+//               this Lens.  These are both in the same units
+//               specified in set_film_size().
+//
+//               This can be used to establish an off-axis lens.
+////////////////////////////////////////////////////////////////////
+INLINE void Lens::
+set_film_offset(float x, float y) {
+  set_film_offset(LVecBase2f(x, y));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_film_offset
+//       Access: Published
+//  Description: Sets the horizontal and vertical offset amounts of
+//               this Lens.  These are both in the same units
+//               specified in set_film_size().
+//
+//               This can be used to establish an off-axis lens.
+////////////////////////////////////////////////////////////////////
+INLINE void Lens::
+set_film_offset(const LVecBase2f &film_offset) {
+  _film_offset = film_offset;
+  adjust_comp_flags(CF_mat, 0);
+  throw_change_event();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_film_offset
+//       Access: Published
+//  Description: Returns the horizontal and vertical offset amounts of
+//               this Lens.  See set_film_offset().
+////////////////////////////////////////////////////////////////////
+INLINE const LVector2f &Lens::
+get_film_offset() const {
+  return _film_offset;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_fov
+//       Access: Published
+//  Description: Sets the field of view of the lens in both
+//               dimensions.  This establishes both the field of view
+//               and the aspect ratio of the lens.  This is one way to
+//               specify the field of view of a lens;
+//               set_focal_length() is another way.
+//
+//               For certain kinds of lenses (like OrthoLens),
+//               the field of view has no meaning.
+////////////////////////////////////////////////////////////////////
+INLINE void Lens::
+set_fov(float hfov, float vfov) {
+  set_fov(LVecBase2f(hfov, vfov));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_hfov
+//       Access: Published
+//  Description: Returns the horizontal component of fov only.  See
+//               get_fov().
+////////////////////////////////////////////////////////////////////
+INLINE float Lens::
+get_hfov() const {
+  return get_fov()[0];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_vfov
+//       Access: Published
+//  Description: Returns the vertical component of fov only.  See
+//               get_fov().
+////////////////////////////////////////////////////////////////////
+INLINE float Lens::
+get_vfov() const {
+  return get_fov()[1];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_near
+//       Access: Published
+//  Description: Defines the position of the near plane (or cylinder,
+//               sphere, whatever).  Points closer to the lens than
+//               this may not be rendered.
+////////////////////////////////////////////////////////////////////
+INLINE void Lens::
+set_near(float near_distance) {
+  _near_distance = near_distance;
+  adjust_comp_flags(CF_projection_mat | CF_projection_mat_inv, 0);
+  throw_change_event();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_near
+//       Access: Published
+//  Description: Returns the position of the near plane (or cylinder,
+//               sphere, whatever).
+////////////////////////////////////////////////////////////////////
+INLINE float Lens::
+get_near() const {
+  return _near_distance;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_far
+//       Access: Published
+//  Description: Defines the position of the far plane (or cylinder,
+//               sphere, whatever).  Points farther from the lens than
+//               this may not be rendered.
+////////////////////////////////////////////////////////////////////
+INLINE void Lens::
+set_far(float far_distance) {
+  _far_distance = far_distance;
+  adjust_comp_flags(CF_projection_mat | CF_projection_mat_inv, 0);
+  throw_change_event();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_far
+//       Access: Published
+//  Description: Returns the position of the far plane (or cylinder,
+//               sphere, whatever).
+////////////////////////////////////////////////////////////////////
+INLINE float Lens::
+get_far() const {
+  return _far_distance;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_near_far
+//       Access: Published
+//  Description: Simultaneously changes the near and far planes.
+////////////////////////////////////////////////////////////////////
+INLINE void Lens::
+set_near_far(float near_distance, float far_distance) {
+  _near_distance = near_distance;
+  _far_distance = far_distance;
+  adjust_comp_flags(CF_projection_mat | CF_projection_mat_inv, 0);
+  throw_change_event();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_view_hpr
+//       Access: Published
+//  Description: Sets the direction in which the lens is facing.
+//               Normally, this is down the forward axis (usually the
+//               Y axis), but it may be rotated.  This is only one way
+//               of specifying the rotation; you may also specify an
+//               explicit vector in which to look, or you may give a
+//               complete transformation matrix.
+////////////////////////////////////////////////////////////////////
+INLINE void Lens::
+set_view_hpr(float h, float p, float r) {
+  set_view_hpr(LVecBase3f(h, p, r));
+}
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_view_vector
+//       Access: Published
+//  Description: Specifies the direction in which the lens is facing
+//               by giving an axis to look along, and a perpendicular
+//               (or at least non-parallel) up axis.
+//
+//               See also set_view_hpr().
+////////////////////////////////////////////////////////////////////
+INLINE void Lens::
+set_view_vector(float x, float y, float z, float i, float j, float k) {
+  set_view_vector(LVector3f(x, y, z), LVector3f(i, j, k));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::adjust_user_flags
+//       Access: Protected
+//  Description: Clears from _user_flags the bits in the first
+//               parameter, and sets the bits in the second parameter.
+////////////////////////////////////////////////////////////////////
+INLINE void Lens::
+adjust_user_flags(int clear_flags, int set_flags) {
+  _user_flags = (_user_flags & ~clear_flags) | set_flags;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::adjust_comp_flags
+//       Access: Protected
+//  Description: Clears from _comp_flags the bits in the first
+//               parameter, and sets the bits in the second parameter.
+////////////////////////////////////////////////////////////////////
+INLINE void Lens::
+adjust_comp_flags(int clear_flags, int set_flags) {
+  _comp_flags = (_comp_flags & ~clear_flags) | set_flags;
+}
+
+EXPCL_PANDA INLINE ostream &
+operator << (ostream &out, const Lens &lens) {
+  lens.output(out);
+  return out;
+}

+ 1291 - 0
panda/src/gobj/lens.cxx

@@ -0,0 +1,1291 @@
+// Filename: lens.cxx
+// Created by:  drose (18Feb99)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "lens.h"
+#include "throw_event.h"
+#include "compose_matrix.h"
+#include "look_at.h"
+#include "geomLinestrip.h"
+#include "boundingHexahedron.h"
+#include "indent.h"
+#include "config_gobj.h"
+
+TypeHandle Lens::_type_handle;
+
+const float Lens::_default_fov = 40.0f;
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+Lens::
+Lens() {
+  clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+Lens::
+Lens(const Lens &copy) {
+  (*this) = copy;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void Lens::
+operator = (const Lens &copy) {
+  _change_event = copy._change_event;
+  _cs = copy._cs;
+  _film_size = copy._film_size;
+  _film_offset = copy._film_offset;
+  _focal_length = copy._focal_length;
+  _fov = copy._fov;
+  _aspect_ratio = copy._aspect_ratio;
+  _near_distance = copy._near_distance;
+  _far_distance = copy._far_distance;
+  _user_flags = copy._user_flags;
+  _comp_flags = 0;
+
+  // We don't copy the _geom_coords array.  That's unique to each
+  // Lens.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_coordinate_system
+//       Access: Published
+//  Description: Specifies the coordinate system that all 3-d
+//               computations are performed within for this
+//               Lens.  Normally, this is CS_default.
+////////////////////////////////////////////////////////////////////
+void Lens::
+set_coordinate_system(CoordinateSystem cs) {
+  _cs = cs;
+  adjust_comp_flags(CF_mat | CF_view_hpr | CF_view_vector, 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::clear
+//       Access: Published
+//  Description: Resets all lens parameters to their initial default
+//               settings.
+////////////////////////////////////////////////////////////////////
+void Lens::
+clear() {
+  _change_event = "";
+  _cs = CS_default;
+  _film_size.set(1.0f, 1.0f);
+  _film_offset.set(0.0f, 0.0f);
+  _focal_length = 1.0f;
+  _fov.set(_default_fov, _default_fov);
+  _aspect_ratio = 1.0f;
+  _near_distance = 1.0f;
+  _far_distance = 1000.0f;
+  _view_hpr.set(0.0f, 0.0f, 0.0f);
+  _view_vector.set(0.0f, 1.0f, 0.0f);
+  _up_vector.set(0.0f, 0.0f, 1.0f);
+  _iod_offset = 0.0f;
+  _user_flags = 0;
+  _comp_flags = CF_fov;
+
+  // Assign an initial arbitrary sequence to these three.
+  _film_size_seq = 0;
+  _focal_length_seq = 1;
+  _fov_seq = 2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_film_size
+//       Access: Published
+//  Description: Sets the horizontal size of the film without changing
+//               its shape.  The aspect ratio remains unchanged; this
+//               computes the vertical size of the film to
+//               automatically maintain the aspect ratio.
+////////////////////////////////////////////////////////////////////
+void Lens::
+set_film_size(float width) {
+  _film_size.set(width, width / get_aspect_ratio());
+
+  // We can't specify all three of focal length, fov, and film size.
+  // Throw out the oldest one.
+  resequence_fov_triad(_film_size_seq, _focal_length_seq, _fov_seq);
+
+  if (_fov_seq == 0) {
+    // Throw out fov if it's oldest.
+    adjust_user_flags(UF_hfov | UF_vfov | UF_film_height,
+                      UF_film_width);
+  } else {
+    // Otherwise, throw out focal length.
+    nassertv(_focal_length_seq == 0);
+    adjust_user_flags(UF_focal_length | UF_film_height,
+                      UF_film_width);
+  }
+  adjust_comp_flags(CF_mat | CF_focal_length | CF_fov,
+                    CF_film_size);
+  throw_change_event();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_film_size
+//       Access: Published
+//  Description: Sets the size and shape of the "film" within the
+//               lens.  This both establishes the units used by
+//               calls like set_focal_length(), and establishes the
+//               aspect ratio of the frame.
+//
+//               In a physical camera, the field of view of a lens is
+//               determined by the lens' focal length and by the size
+//               of the film area exposed by the lens.  For instance,
+//               a 35mm camera exposes a rectangle on the film about
+//               24mm x 36mm, which means a 50mm lens gives about a
+//               40-degree horizontal field of view.
+//
+//               In the virtual camera, you may set the film size to
+//               any units here, and specify a focal length in the
+//               same units to simulate the same effect.  Or, you may
+//               ignore this parameter, and specify the field of view
+//               and aspect ratio of the lens directly.
+////////////////////////////////////////////////////////////////////
+void Lens::
+set_film_size(const LVecBase2f &film_size) {
+  _film_size = film_size;
+
+  // We can't specify all three of focal length, fov, and film size.
+  // Throw out the oldest one.
+  resequence_fov_triad(_film_size_seq, _focal_length_seq, _fov_seq);
+
+  if (_fov_seq == 0) {
+    // Throw out fov if it's oldest.
+    adjust_user_flags(UF_hfov | UF_vfov | UF_aspect_ratio,
+                      UF_film_width | UF_film_height);
+  } else {
+    // Otherwise, throw out focal length.
+    nassertv(_focal_length_seq == 0);
+    adjust_user_flags(UF_focal_length | UF_vfov | UF_aspect_ratio,
+                      UF_film_width | UF_film_height);
+  }
+  adjust_comp_flags(CF_mat | CF_focal_length | CF_fov | CF_aspect_ratio,
+                    CF_film_size);
+
+  // Also, the user has implicitly specified an aspect ratio.  Make it
+  // stick until the user tells us something different.
+  compute_aspect_ratio();
+  adjust_user_flags(0, UF_aspect_ratio);
+
+  throw_change_event();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_film_size
+//       Access: Published
+//  Description: Returns the horizontal and vertical film size of
+//               the virtual film.  See set_film_size().
+////////////////////////////////////////////////////////////////////
+const LVecBase2f &Lens::
+get_film_size() const {
+  if ((_comp_flags & CF_film_size) == 0) {
+    // We pretend this is a const method, even though it may call a
+    // non-const method to recompute the internal values.  We can do
+    // this because this is just compute-on-demand.
+    ((Lens *)this)->compute_film_size();
+  }
+  return _film_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_focal_length
+//       Access: Published
+//  Description: Sets the focal length of the lens.  This may adjust
+//               the field-of-view correspondingly, and is an
+//               alternate way to specify field of view.
+//
+//               For certain kinds of lenses (e.g. OrthographicLens),
+//               the focal length has no meaning.
+////////////////////////////////////////////////////////////////////
+void Lens::
+set_focal_length(float focal_length) {
+  _focal_length = focal_length;
+
+  // We can't specify all three of focal length, fov, and film size.
+  // Throw out the oldest one.
+  resequence_fov_triad(_focal_length_seq, _film_size_seq, _fov_seq);
+
+  if (_film_size_seq == 0) {
+    // Throw out film size if it's oldest.
+    adjust_user_flags(UF_film_width | UF_film_height,
+                      UF_focal_length);
+  } else {
+    // Otherwise, throw out the fov.
+    nassertv(_fov_seq == 0);
+    adjust_user_flags(UF_hfov | UF_vfov,
+                      UF_focal_length);
+  }
+
+  adjust_comp_flags(CF_mat | CF_fov | CF_film_size,
+                    CF_focal_length);
+  throw_change_event();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_focal_length
+//       Access: Published
+//  Description: Returns the focal length of the lens.  This may have
+//               been set explicitly by a previous call to
+//               set_focal_length(), or it may be computed based on
+//               the lens' fov and film_size.  For certain kinds of
+//               lenses, the focal length has no meaning.
+////////////////////////////////////////////////////////////////////
+float Lens::
+get_focal_length() const {
+  if ((_comp_flags & CF_focal_length) == 0) {
+    ((Lens *)this)->compute_focal_length();
+  }
+  return _focal_length;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_fov
+//       Access: Published
+//  Description: Sets the horizontal field of view of the lens without
+//               changing the aspect ratio.  The vertical field of
+//               view is adjusted to maintain the same aspect ratio.
+////////////////////////////////////////////////////////////////////
+void Lens::
+set_fov(float hfov) {
+  _fov[0] = hfov;
+
+  // We can't specify all three of focal length, fov, and film size.
+  // Throw out the oldest one.
+  resequence_fov_triad(_fov_seq, _focal_length_seq, _film_size_seq);
+
+  if (_focal_length_seq == 0) {
+    // Throw out focal length if it's oldest.
+    adjust_user_flags(UF_focal_length | UF_vfov,
+                      UF_hfov);
+  } else {
+    // Otherwise, throw out film size.
+    nassertv(_film_size_seq == 0);
+    adjust_user_flags(UF_film_width | UF_film_height | UF_vfov,
+                      UF_hfov);
+  }
+  adjust_comp_flags(CF_mat | CF_focal_length | CF_fov | CF_film_size,
+                    0);
+  // We leave CF_fov off of comp_flags, because we will still need to
+  // recompute the vertical fov.  It's not exactly the same as hfov *
+  // get_aspect_ratio().
+  throw_change_event();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_fov
+//       Access: Published
+//  Description: Sets the field of view of the lens in both
+//               dimensions.  This establishes both the field of view
+//               and the aspect ratio of the lens.  This is one way to
+//               specify the field of view of a lens;
+//               set_focal_length() is another way.
+//
+//               For certain kinds of lenses (like OrthographicLens),
+//               the field of view has no meaning.
+////////////////////////////////////////////////////////////////////
+void Lens::
+set_fov(const LVecBase2f &fov) {
+  _fov = fov;
+
+  // We can't specify all three of focal length, fov, and film size.
+  // Throw out the oldest one.
+  resequence_fov_triad(_fov_seq, _focal_length_seq, _film_size_seq);
+
+  if (_focal_length_seq == 0) {
+    // Throw out focal length if it's oldest.
+    adjust_user_flags(UF_focal_length | UF_film_height | UF_aspect_ratio,
+                      UF_hfov | UF_vfov);
+  } else {
+    // Otherwise, throw out film size.
+    nassertv(_film_size_seq == 0);
+    adjust_user_flags(UF_film_width | UF_film_height | UF_aspect_ratio,
+                      UF_hfov | UF_vfov);
+  }
+  adjust_comp_flags(CF_mat | CF_focal_length | CF_film_size | CF_aspect_ratio,
+                    CF_fov);
+
+  // Also, the user has implicitly specified an aspect ratio.  Make it
+  // stick until the user tells us something different.
+  compute_aspect_ratio();
+  adjust_user_flags(0, UF_aspect_ratio);
+
+  throw_change_event();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_fov
+//       Access: Published
+//  Description: Returns the horizontal and vertical film size of
+//               the virtual film.  See set_fov().
+////////////////////////////////////////////////////////////////////
+const LVecBase2f &Lens::
+get_fov() const {
+  if ((_comp_flags & CF_fov) == 0) {
+    ((Lens *)this)->compute_fov();
+  }
+  return _fov;
+}
+                
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_aspect_ratio
+//       Access: Published
+//  Description: Sets the aspect ratio of the lens.  This is the ratio
+//               of the height to the width of the generated image.
+//               Setting this overrides the two-parameter fov or film
+//               size setting.
+////////////////////////////////////////////////////////////////////
+void Lens::
+set_aspect_ratio(float aspect_ratio) {
+  _aspect_ratio = aspect_ratio;
+  adjust_user_flags(UF_film_height | UF_vfov,
+                    UF_aspect_ratio);
+  adjust_comp_flags(CF_mat | CF_film_size | CF_fov,
+                    CF_aspect_ratio);
+  throw_change_event();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_aspect_ratio
+//       Access: Published
+//  Description: Returns the aspect ratio of the Lens.  This is
+//               determined based on the indicated film size; see
+//               set_film_size().
+////////////////////////////////////////////////////////////////////
+float Lens::
+get_aspect_ratio() const {
+  if ((_comp_flags & CF_aspect_ratio) == 0) {
+    ((Lens *)this)->compute_aspect_ratio();
+  }
+  return _aspect_ratio;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_view_hpr
+//       Access: Published
+//  Description: Sets the direction in which the lens is facing.
+//               Normally, this is down the forward axis (usually the
+//               Y axis), but it may be rotated.  This is only one way
+//               of specifying the rotation; you may also specify an
+//               explicit vector in which to look, or you may give a
+//               complete transformation matrix.
+////////////////////////////////////////////////////////////////////
+void Lens::
+set_view_hpr(const LVecBase3f &view_hpr) {
+  _view_hpr = view_hpr;
+  adjust_user_flags(UF_view_vector | UF_view_mat,
+                    UF_view_hpr);
+  adjust_comp_flags(CF_mat | CF_view_vector | CF_iod_offset,
+                    CF_view_hpr);
+  throw_change_event();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_view_hpr
+//       Access: Published
+//  Description: Returns the direction in which the lens is facing.
+////////////////////////////////////////////////////////////////////
+const LVecBase3f &Lens::
+get_view_hpr() const {
+  if ((_comp_flags & CF_view_hpr) == 0) {
+    ((Lens *)this)->compute_view_hpr();
+  }
+  return _view_hpr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_view_vector
+//       Access: Published
+//  Description: Specifies the direction in which the lens is facing
+//               by giving an axis to look along, and a perpendicular
+//               (or at least non-parallel) up axis.
+//
+//               See also set_view_hpr().
+////////////////////////////////////////////////////////////////////
+void Lens::
+set_view_vector(const LVector3f &view_vector, const LVector3f &up_vector) {
+  _view_vector = view_vector;
+  _up_vector = up_vector;
+  adjust_user_flags(UF_view_hpr | UF_view_mat,
+                    UF_view_vector);
+  adjust_comp_flags(CF_mat | CF_view_hpr | CF_iod_offset,
+                    CF_view_vector);
+  throw_change_event();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_view_vector
+//       Access: Published
+//  Description: Returns the axis along which the lens is facing.
+////////////////////////////////////////////////////////////////////
+const LVector3f &Lens::
+get_view_vector() const {
+  if ((_comp_flags & CF_view_vector) == 0) {
+    ((Lens *)this)->compute_view_vector();
+  }
+  return _view_vector;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_up_vector
+//       Access: Published
+//  Description: Returns the axis perpendicular to the camera's view
+//               vector that indicates the "up" direction.
+////////////////////////////////////////////////////////////////////
+const LVector3f &Lens::
+get_up_vector() const {
+  if ((_comp_flags & CF_view_vector) == 0) {
+    ((Lens *)this)->compute_view_vector();
+  }
+  return _up_vector;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_iod_offset
+//       Access: Published
+//  Description: Sets the amount by which the lens is shifted to the
+//               right, perpendicular to its view vector and up
+//               vector.  This is normally used to shift one or both
+//               lens of a stereo camera to generate parallax.  You
+//               can also simply set a complete transformation matrix
+//               (via set_view_mat()) that includes an arbitrary
+//               translation.
+////////////////////////////////////////////////////////////////////
+void Lens::
+set_iod_offset(float iod_offset) {
+  _iod_offset = iod_offset;
+  adjust_user_flags(UF_view_mat,
+                    UF_iod_offset);
+  adjust_comp_flags(CF_mat | CF_view_hpr | CF_view_vector,
+                    CF_iod_offset);
+  throw_change_event();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_iod_offset
+//       Access: Published
+//  Description: Returns the aspect ratio of the Lens.  This is
+//               determined based on the indicated film size; see
+//               set_film_size().
+////////////////////////////////////////////////////////////////////
+float Lens::
+get_iod_offset() const {
+  if ((_comp_flags & CF_iod_offset) == 0) {
+    ((Lens *)this)->compute_iod_offset();
+  }
+  return _iod_offset;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::set_view_mat
+//       Access: Published
+//  Description: Sets an arbitrary transformation on the lens.  This
+//               replaces the individual transformation components
+//               like set_view_hpr() or set_iod_offset().
+//
+//               Setting a transformation here will have a slightly
+//               different effect than putting one on the LensNode
+//               that contains this lens.  In particular, lighting and
+//               other effects computations will still be performed on
+//               the lens in its untransformed (facing forward)
+//               position, but the actual projection matrix will be
+//               transformed by this matrix.
+////////////////////////////////////////////////////////////////////
+void Lens::
+set_view_mat(const LMatrix4f &view_mat) {
+  _lens_mat = view_mat;
+  adjust_user_flags(UF_view_vector | UF_view_hpr | UF_iod_offset,
+                    UF_view_mat);
+  adjust_comp_flags(CF_lens_mat_inv | CF_view_hpr | CF_view_vector | CF_iod_offset,
+                    CF_lens_mat);
+  throw_change_event();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_view_mat
+//       Access: Published
+//  Description: Returns the direction in which the lens is facing.
+////////////////////////////////////////////////////////////////////
+const LMatrix4f &Lens::
+get_view_mat() const {
+  if ((_comp_flags & CF_lens_mat) == 0) {
+    ((Lens *)this)->compute_lens_mat();
+  }
+  return _lens_mat;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::recompute_all
+//       Access: Published
+//  Description: Forces all internal parameters of the Lens to be
+//               recomputed.  Normally, this should never need to be
+//               called; it is provided only to assist in debugging.
+////////////////////////////////////////////////////////////////////
+void Lens::
+recompute_all() {
+  _comp_flags = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::is_linear
+//       Access: Published, Virtual
+//  Description: Returns true if the lens represents a linear
+//               projection (e.g. PerspectiveLens, OrthographicLens),
+//               and therefore there is a valid matrix returned by
+//               get_projection_mat(), or false otherwise.
+////////////////////////////////////////////////////////////////////
+bool Lens::
+is_linear() const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::make_geometry
+//       Access: Published, Virtual
+//  Description: Allocates and returns a new Geom that can be rendered
+//               to show a visible representation of the frustum used
+//               for this kind of lens, if it makes sense to do
+//               so.  If a visible representation cannot be created,
+//               returns NULL.
+////////////////////////////////////////////////////////////////////
+PT(Geom) Lens::
+make_geometry() {
+  // The default behavior for make_geometry() will be to draw a
+  // hexahedron around the eight vertices of the frustum.  If the lens
+  // is non-linear, the hexahedron will be curved; in this case, we'll
+  // subdivide the lines into several segments to get an approximation
+  // of the curve.
+
+  // First, define all the points we'll use in this Geom.  That's one
+  // point at each corner of the near and far planes (and possibly
+  // more points along the edges).
+  int num_segments = define_geom_coords();
+  if (num_segments == 0) {
+    // Can't do a frustum.
+    _geom_coords.clear();
+    return (Geom *)NULL;
+  }
+
+  // Now string together the line segments.
+  PTA_ushort vindex;
+  PTA_int lengths;
+  PTA_Colorf colors;
+
+  int num_points = num_segments * 4;
+
+  // Draw a frame around the near plane.
+  int i;
+  for (i = 0; i < num_points; i++) {
+    vindex.push_back(i * num_segments * 2);
+  }
+  vindex.push_back(0);
+  lengths.push_back(num_points + 1);
+
+  // Draw a frame around the far plane.
+  for (i = 0; i < num_points; i++) {
+    vindex.push_back(i * num_segments * 2 + 1);
+  }
+  vindex.push_back(1);
+  lengths.push_back(num_points + 1);
+
+  // Draw connecting lines at the corners.
+  vindex.push_back(0);
+  vindex.push_back(1);
+  lengths.push_back(2);
+
+  vindex.push_back(num_segments * 2 + 0);
+  vindex.push_back(num_segments * 2+ 1);
+  lengths.push_back(2);
+
+  vindex.push_back(num_segments * 4 + 0);
+  vindex.push_back(num_segments * 4 + 1);
+  lengths.push_back(2);
+
+  vindex.push_back(num_segments * 6 + 0);
+  vindex.push_back(num_segments * 6 + 1);
+  lengths.push_back(2);
+
+  // And one more line for the viewing axis.
+  vindex.push_back(num_segments * 8 + 0);
+  vindex.push_back(num_segments * 8 + 1);
+  lengths.push_back(2);
+
+  // We just specify overall color.
+  colors.push_back(Colorf(1.0, 1.0, 1.0, 1.0));
+
+  GeomLinestrip *gline = new GeomLinestrip;
+  gline->set_coords(_geom_coords, vindex);
+  gline->set_colors(colors, G_OVERALL);
+  gline->set_lengths(lengths);
+  gline->set_num_prims(lengths.size());
+
+  return gline;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::make_bounds
+//       Access: Published, Virtual
+//  Description: Allocates and returns a new BoundingVolume that
+//               encloses the frustum used for this kind of
+//               lens, if possible.  If a suitable bounding
+//               volume cannot be created, returns NULL.
+////////////////////////////////////////////////////////////////////
+PT(BoundingVolume) Lens::
+make_bounds() const {
+  // The default bounding volume is a hexahedron based on the eight
+  // corners of the frustum.
+  LPoint3f fll, flr, ful, fur;
+  LPoint3f nll, nlr, nul, nur;
+
+  // Upper left.
+  if (!extrude(LPoint2f(-1.0, 1.0), nul, ful)) {
+    return (BoundingVolume *)NULL;
+  }
+
+  // Upper right.
+  if (!extrude(LPoint2f(1.0, 1.0), nur, fur)) {
+    return (BoundingVolume *)NULL;
+  }
+
+  // Lower right.
+  if (!extrude(LPoint2f(1.0, -1.0), nlr, flr)) {
+    return (BoundingVolume *)NULL;
+  }
+
+  // Lower left.
+  if (!extrude(LPoint2f(-1.0, -1.0), nll, fll)) {
+    return (BoundingVolume *)NULL;
+  }
+
+  return new BoundingHexahedron(fll, flr, fur, ful, nll, nlr, nur, nul);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_projection_mat
+//       Access: Published
+//  Description: Returns the complete transformation matrix from a 3-d
+//               point in space to a point on the film, if such a
+//               matrix exists, or the identity matrix if the lens is
+//               nonlinear.
+////////////////////////////////////////////////////////////////////
+const LMatrix4f &Lens::
+get_projection_mat() const {
+  if ((_comp_flags & CF_projection_mat) == 0) {
+    ((Lens *)this)->compute_projection_mat();
+  }
+  return _projection_mat;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_projection_mat_inv
+//       Access: Public
+//  Description: Returns the matrix that transforms from a 2-d point
+//               on the film to a 3-d vector in space, if such a
+//               matrix exists.
+////////////////////////////////////////////////////////////////////
+const LMatrix4f &Lens::
+get_projection_mat_inv() const {
+  if ((_comp_flags & CF_projection_mat_inv) == 0) {
+    Lens *non_const = (Lens *)this;
+    const LMatrix4f &projection_mat = get_projection_mat();
+    non_const->_projection_mat_inv.invert_from(projection_mat);
+    non_const->adjust_comp_flags(0, CF_projection_mat_inv);
+  }
+  return _projection_mat_inv;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void Lens::
+output(ostream &out) const {
+  out << get_type();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void Lens::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level) << get_type() << " fov = " << get_fov() << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::throw_change_event
+//       Access: Protected
+//  Description: Throws the event associated with changing properties
+//               on this Lens, if any.
+////////////////////////////////////////////////////////////////////
+void Lens::
+throw_change_event() {
+  if (!_change_event.empty()) {
+    throw_event(_change_event);
+  }
+
+  // Also update the _geom_coords, if it is in use.
+  if (!_geom_coords.is_null()) {
+    if (_geom_coords.get_ref_count() == 1) {
+      // No one's using the array any more (other than us), so release
+      // it.
+      _geom_coords.clear();
+    } else {
+      // Someone else still has a handle to the array, so recompute
+      // it.
+      define_geom_coords();
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_film_mat
+//       Access: Protected
+//  Description: Returns the matrix that transforms from a point
+//               behind the lens to a point on the film.
+////////////////////////////////////////////////////////////////////
+const LMatrix4f &Lens::
+get_film_mat() const {
+  if ((_comp_flags & CF_film_mat) == 0) {
+    ((Lens *)this)->compute_film_mat();
+  }
+  return _film_mat;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_film_mat_inv
+//       Access: Protected
+//  Description: Returns the matrix that transforms from a point on
+//               the film to a point behind the lens.
+////////////////////////////////////////////////////////////////////
+const LMatrix4f &Lens::
+get_film_mat_inv() const {
+  if ((_comp_flags & CF_film_mat_inv) == 0) {
+    Lens *non_const = (Lens *)this;
+    const LMatrix4f &film_mat = get_film_mat();
+    non_const->_film_mat_inv.invert_from(film_mat);
+    non_const->adjust_comp_flags(0, CF_film_mat_inv);
+  }
+  return _film_mat_inv;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_lens_mat
+//       Access: Protected
+//  Description: Returns the matrix that transforms from a point
+//               in front of the lens to a point in space.
+////////////////////////////////////////////////////////////////////
+const LMatrix4f &Lens::
+get_lens_mat() const {
+  if ((_comp_flags & CF_lens_mat) == 0) {
+    ((Lens *)this)->compute_lens_mat();
+  }
+  return _lens_mat;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::get_lens_mat_inv
+//       Access: Protected
+//  Description: Returns the matrix that transforms from a point in
+//               space to a point in front of the lens.
+////////////////////////////////////////////////////////////////////
+const LMatrix4f &Lens::
+get_lens_mat_inv() const {
+  if ((_comp_flags & CF_lens_mat_inv) == 0) {
+    Lens *non_const = (Lens *)this;
+    const LMatrix4f &lens_mat = get_lens_mat();
+    non_const->_lens_mat_inv.invert_from(lens_mat);
+    non_const->adjust_comp_flags(0, CF_lens_mat_inv);
+  }
+  return _lens_mat_inv;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::extrude
+//       Access: Protected, Virtual
+//  Description: Given a 2-d point in the range (-1,1) in both
+//               dimensions, where (0,0) is the center of the
+//               lens and (-1,-1) is the lower-left corner,
+//               compute the corresponding vector in space that maps
+//               to this point, if such a vector can be determined.
+//               The vector is returned by indicating the points on
+//               the near plane and far plane that both map to the
+//               indicated 2-d point.
+//
+//               The z coordinate of the 2-d point is ignored.
+//
+//               Returns true if the vector is defined, or false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool Lens::
+extrude_impl(const LPoint3f &point2d, LPoint3f &near_point, LPoint3f &far_point) const {
+  const LMatrix4f &projection_mat_inv = get_projection_mat_inv();
+  {
+    LVecBase4f full(point2d[0], point2d[1], -1.0f, 1.0f);
+    full = projection_mat_inv.xform(full);
+    if (full[3] == 0.0f) {
+      return false;
+    }
+    near_point.set(full[0] / full[3], full[1] / full[3], full[2] / full[3]);
+  }
+  {
+    LVecBase4f full(point2d[0], point2d[1], 1.0f, 1.0f);
+    full = projection_mat_inv.xform(full);
+    if (full[3] == 0.0f) {
+      return false;
+    }
+    far_point.set(full[0] / full[3], full[1] / full[3], full[2] / full[3]);
+  }
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::project_impl
+//       Access: Protected, Virtual
+//  Description: Given a 3-d point in space, determine the 2-d point
+//               this maps to, in the range (-1,1) in both dimensions,
+//               where (0,0) is the center of the lens and
+//               (-1,-1) is the lower-left corner.
+//
+//               Some lens types also set the z coordinate of the 2-d
+//               point to a value in the range (-1, 1), where 1
+//               represents a point on the near plane, and -1
+//               represents a point on the far plane.
+//
+//               Returns true if the 3-d point is in front of the lens
+//               and within the viewing frustum (in which case point2d
+//               is filled in), or false otherwise.
+////////////////////////////////////////////////////////////////////
+bool Lens::
+project_impl(const LPoint3f &point3d, LPoint3f &point2d) const {
+  const LMatrix4f &projection_mat = get_projection_mat();
+  LVecBase4f full(point3d[0], point3d[1], point3d[2], 1.0f);
+  full = projection_mat.xform(full);
+  if (full[3] == 0.0f) {
+    return false;
+  }
+  point2d.set(full[0] / full[3], full[1] / full[3], full[2] / full[3]);
+  return point2d[0] >= -1.0f && point2d[0] <= 1.0f && 
+    point2d[1] >= -1.0f && point2d[1] <= 1.0f;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::compute_film_size
+//       Access: Protected, Virtual
+//  Description: Computes the size and shape of the film behind the
+//               camera, based on the aspect ratio and fov.
+////////////////////////////////////////////////////////////////////
+void Lens::
+compute_film_size() {
+  if ((_user_flags & UF_film_width) == 0) {
+    if ((_user_flags & (UF_hfov | UF_focal_length)) == (UF_hfov | UF_focal_length)) {
+      _film_size[0] = fov_to_film(_fov[0], _focal_length, true);
+    } else {
+      _film_size[0] = 1.0f;
+    }
+  }
+
+  if ((_user_flags & UF_film_height) == 0) {
+    if ((_user_flags & (UF_vfov | UF_focal_length)) == (UF_vfov | UF_focal_length)) {
+      _film_size[1] = fov_to_film(_fov[1], _focal_length, false);
+
+    } else if ((_user_flags & (UF_hfov | UF_vfov)) == (UF_hfov | UF_vfov)) {
+      // If we don't have a focal length, but we have an explicit vfov
+      // and hfov, we can infer the focal length is whatever makes the
+      // film width, above, be what it is.
+      if ((_comp_flags & CF_focal_length) == 0) {
+        _focal_length = fov_to_focal_length(_fov[0], _film_size[0], true);
+        adjust_comp_flags(0, CF_focal_length);
+      }
+      _film_size[1] = fov_to_film(_fov[1], _focal_length, false);
+
+    } else if ((_user_flags & UF_aspect_ratio) != 0) {
+      _film_size[1] = _film_size[0] / _aspect_ratio;
+
+    } else {
+      // Default is an aspect ratio of 1.
+      _film_size[1] = _film_size[0];
+    }
+  }
+
+  adjust_comp_flags(0, CF_film_size);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::compute_focal_length
+//       Access: Protected, Virtual
+//  Description: Computes the focal length of the lens, based on the
+//               fov and film size.  This is based on the horizontal
+//               dimension.
+////////////////////////////////////////////////////////////////////
+void Lens::
+compute_focal_length() {
+  if ((_user_flags & UF_focal_length) == 0) {
+    const LVecBase2f &film_size = get_film_size();
+    const LVecBase2f &fov = get_fov();
+    _focal_length = fov_to_focal_length(fov[0], film_size[0], true);
+  }
+
+  adjust_comp_flags(0, CF_focal_length);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::compute_fov
+//       Access: Protected, Virtual
+//  Description: Computes the field of view of the lens, based on the
+//               film size and focal length.
+////////////////////////////////////////////////////////////////////
+void Lens::
+compute_fov() {
+  const LVecBase2f &film_size = get_film_size();
+
+  if ((_user_flags & UF_hfov) == 0) {
+    if ((_user_flags & UF_focal_length) != 0) {
+      _fov[0] = film_to_fov(film_size[0], _focal_length, true);
+    } else {
+      _fov[0] = _default_fov;
+    }
+  }
+
+  if ((_user_flags & UF_vfov) == 0) {
+    if ((_user_flags & UF_focal_length) == 0 &&
+        (_comp_flags & CF_focal_length) == 0) {
+      // If we don't have an explicit focal length, we can infer it
+      // from the above.
+      _focal_length = fov_to_focal_length(_fov[0], film_size[0], true);
+      adjust_comp_flags(0, CF_focal_length);
+    }
+    _fov[1] = film_to_fov(film_size[1], _focal_length, false);
+  }
+
+  adjust_comp_flags(0, CF_fov);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::compute_aspect_ratio
+//       Access: Protected, Virtual
+//  Description: Computes the aspect ratio of the film rectangle, as a
+//               ratio of width to height.
+////////////////////////////////////////////////////////////////////
+void Lens::
+compute_aspect_ratio() {
+  if ((_user_flags & UF_aspect_ratio) == 0) {
+    const LVecBase2f &film_size = get_film_size();
+    if (film_size[1] == 0.0f) {
+      _aspect_ratio = 1.0f;
+    } else {
+      _aspect_ratio = film_size[0] / film_size[1];
+    }
+    adjust_comp_flags(0, CF_aspect_ratio);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::compute_view_hpr
+//       Access: Protected, Virtual
+//  Description: Computes the Euler angles representing the lens'
+//               rotation.
+////////////////////////////////////////////////////////////////////
+void Lens::
+compute_view_hpr() {
+  if ((_user_flags & UF_view_hpr) == 0) {
+    const LMatrix4f &view_mat = get_view_mat();
+    LVecBase3f scale, translate;
+    decompose_matrix(view_mat, scale, _view_hpr, translate, _cs);
+  }
+  adjust_comp_flags(0, CF_view_hpr);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::compute_view_vector
+//       Access: Protected, Virtual
+//  Description: Computes the view vector and up vector for the lens.
+////////////////////////////////////////////////////////////////////
+void Lens::
+compute_view_vector() {
+  if ((_user_flags & UF_view_vector) == 0) {
+    const LMatrix4f &view_mat = get_view_mat();
+    _view_vector = LVector3f::forward(_cs) * view_mat;
+    _up_vector = LVector3f::up(_cs) * view_mat;
+  }
+  adjust_comp_flags(0, CF_view_vector);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::compute_iod_offset
+//       Access: Protected, Virtual
+//  Description: Computes the IOD offset: the translation along the
+//               "right" axis.
+////////////////////////////////////////////////////////////////////
+void Lens::
+compute_iod_offset() {
+  if ((_user_flags & UF_iod_offset) == 0) {
+    const LMatrix4f &lens_mat_inv = get_lens_mat_inv();
+    LVector3f translate;
+    lens_mat_inv.get_row3(translate, 3);
+    _iod_offset = -translate.dot(LVector3f::right(_cs));
+  }
+  adjust_comp_flags(0, CF_iod_offset);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::compute_projection_mat
+//       Access: Protected, Virtual
+//  Description: Computes the complete transformation matrix from 3-d
+//               point to 2-d point, if the lens is linear.
+////////////////////////////////////////////////////////////////////
+void Lens::
+compute_projection_mat() {
+  _projection_mat = LMatrix4f::ident_mat();
+  _projection_mat_inv = _projection_mat;
+  adjust_comp_flags(0, CF_projection_mat | CF_projection_mat_inv);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::compute_film_mat
+//       Access: Protected, Virtual
+//  Description: Computes the matrix that transforms from a point
+//               behind the lens to a point on the film.
+////////////////////////////////////////////////////////////////////
+void Lens::
+compute_film_mat() {
+  // The lens will return a point in the range [-film_size/2,
+  // film_size/2] in each dimension.  Convert this to [-1, 1], and
+  // also apply the offset.
+  const LVecBase2f &film_size = get_film_size();
+  const LVector2f &film_offset = get_film_offset();
+  _film_mat =
+    LMatrix4f::translate_mat(-film_offset[0], -film_offset[1], 0.0) *
+    LMatrix4f::scale_mat(2.0f / film_size[0], 2.0f / film_size[1], 1.0);
+  adjust_comp_flags(CF_film_mat_inv,
+                    CF_film_mat);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::compute_lens_mat
+//       Access: Protected, Virtual
+//  Description: Computes the matrix that transforms from a point
+//               in front of the lens to a point in space.
+////////////////////////////////////////////////////////////////////
+void Lens::
+compute_lens_mat() {
+  if ((_user_flags & UF_view_mat) == 0) {
+    if ((_user_flags & UF_view_hpr) != 0) {
+      compose_matrix(_lens_mat,
+                     LVecBase3f(1.0f, 1.0f, 1.0f), _view_hpr,
+                     LVecBase3f(0.0f, 0.0f, 0.0f), _cs);
+
+    } else if ((_user_flags & UF_view_vector) != 0) {
+      look_at(_lens_mat, _view_vector, _up_vector, _cs);
+
+    } else {
+      _lens_mat = LMatrix4f::ident_mat();
+    }
+
+    if ((_user_flags & UF_iod_offset) != 0) {
+      LVector3f iod_vector = _iod_offset * LVector3f::right(_cs);
+      _lens_mat = LMatrix4f::translate_mat(iod_vector) * _lens_mat;
+    }
+  }
+  adjust_comp_flags(CF_lens_mat_inv,
+                    CF_lens_mat);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::fov_to_film
+//       Access: Protected, Virtual
+//  Description: Given a field of view in degrees and a focal length,
+//               compute the corresponding width (or height) on the
+//               film.  If horiz is true, this is in the horizontal
+//               direction; otherwise, it is in the vertical direction
+//               (some lenses behave differently in each direction).
+////////////////////////////////////////////////////////////////////
+float Lens::
+fov_to_film(float, float, bool) const {
+  return 1.0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::fov_to_focal_length
+//       Access: Protected, Virtual
+//  Description: Given a field of view in degrees and a width (or
+//               height) on the film, compute the focal length of the
+//               lens.  If horiz is true, this is in the horizontal
+//               direction; otherwise, it is in the vertical direction
+//               (some lenses behave differently in each direction).
+////////////////////////////////////////////////////////////////////
+float Lens::
+fov_to_focal_length(float, float, bool) const {
+  return 1.0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::film_to_fov
+//       Access: Protected, Virtual
+//  Description: Given a width (or height) on the film and a focal
+//               length, compute the field of view in degrees.  If
+//               horiz is true, this is in the horizontal direction;
+//               otherwise, it is in the vertical direction (some
+//               lenses behave differently in each direction).
+////////////////////////////////////////////////////////////////////
+float Lens::
+film_to_fov(float, float, bool) const {
+  return _default_fov;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::resequence_fov_triad
+//       Access: Private, Static
+//  Description: Called whenever the user changes one of the three FOV
+//               parameters: fov, focal length, or film size.  This
+//               rearranges the three sequence numbers so the newest
+//               parameter has value 2, and the older parameters are
+//               kept in sequence order.
+//
+//               This is used to determine which two parameters of the
+//               three are the most recently changed, and conversely,
+//               which one the user has *not* changed recently.  It is
+//               this third value which should be discarded.
+////////////////////////////////////////////////////////////////////
+void Lens::
+resequence_fov_triad(char &newest, char &older_a, char &older_b) {
+  switch (newest) {
+  case 0:
+    newest = 2;
+    older_a--;
+    older_b--;
+    nassertv(older_a + older_b == 1);
+    return;
+
+  case 1:
+    newest = 2;
+    if (older_a == 2) {
+      nassertv(older_b == 0);
+      older_a = 1;
+    } else {
+      nassertv(older_a == 0 && older_b == 2);
+      older_b = 1;
+    }
+    return;
+
+  case 2:
+    nassertv(older_a + older_b == 1);
+    return;
+
+  default:
+    gobj_cat.error()
+      << "Invalid fov sequence numbers in lens: " << newest << ", " << older_a
+      << ", " << older_b << "\n";
+    nassertv(false);
+    return;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::define_geom_coords
+//       Access: Private
+//  Description: Adjusts (or defines for the first time) all the
+//               vertices in the _geom_coords array to match the
+//               properties of the lens.  This will update the visual
+//               representation of the lens's frustum to match the
+//               changing parameters.  Returns the number of line
+//               segments per edge.
+////////////////////////////////////////////////////////////////////
+int Lens::
+define_geom_coords() {
+  int num_segments = 1;
+  if (!is_linear()) {
+    num_segments = 10;
+  }
+
+  PTA_Vertexf coords;
+  LPoint3f near_point, far_point;
+  for (int si = 0; si < num_segments; si++) {
+    float t = 2.0f * (float)si / (float)num_segments;
+
+    // Upper left, top edge.
+    LPoint2f p1(-1.0f + t, 1.0);
+    if (!extrude(p1, near_point, far_point)) {
+      // Hey, this point is off the lens!  Can't do a frustum.
+      return 0;
+    }
+    coords.push_back(near_point);
+    coords.push_back(far_point);
+
+    // Upper right, right edge.
+    LPoint2f p2(1.0, 1.0f - t);
+    if (!extrude(p2, near_point, far_point)) {
+      // Hey, this point is off the lens!  Can't do a frustum.
+      return 0;
+    }
+    coords.push_back(near_point);
+    coords.push_back(far_point);
+
+    // Lower right, bottom edge.
+    LPoint2f p3(1.0f - t, -1.0);
+    if (!extrude(p3, near_point, far_point)) {
+      // Hey, this point is off the lens!  Can't do a frustum.
+      return 0;
+    }
+    coords.push_back(near_point);
+    coords.push_back(far_point);
+
+    // Lower left, left edge.
+    LPoint2f p4(-1.0, -1.0f + t);
+    if (!extrude(p4, near_point, far_point)) {
+      // Hey, this point is off the lens!  Can't do a frustum.
+      return 0;
+    }
+    coords.push_back(near_point);
+    coords.push_back(far_point);
+  }
+
+  // Finally, push one more pair for the viewing axis.
+  LPoint3f near_axis = LPoint3f::origin(_cs) + LVector3f::forward(_cs) * _near_distance;
+  LPoint3f far_axis = LPoint3f::origin(_cs) + LVector3f::forward(_cs) * _far_distance;
+  const LMatrix4f &lens_mat = get_lens_mat();
+  near_axis = near_axis * lens_mat;
+  far_axis = far_axis * lens_mat;
+  coords.push_back(near_axis);
+  coords.push_back(far_axis);
+  
+  if (_geom_coords.is_null()) {
+    // If the previous array is NULL, simply assign the pointer.
+    _geom_coords = coords;
+  } else {
+    // Otherwise, swap out the vectors within the array so other
+    // objects that share the PTA will get the new data.
+    _geom_coords.v().swap(coords.v());
+  }
+
+  return num_segments;
+}

+ 242 - 0
panda/src/gobj/lens.h

@@ -0,0 +1,242 @@
+// Filename: lens.h
+// Created by:  drose (18Feb99)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef LENS_H
+#define LENS_H
+
+#include "pandabase.h"
+
+#include "typedReferenceCount.h"
+#include "luse.h"
+#include "geom.h"
+
+class BoundingVolume;
+
+////////////////////////////////////////////////////////////////////
+//       Class : Lens
+// Description : A base class for any number of different kinds of
+//               lenses, linear and otherwise.  Presently, this
+//               includes perspective and orthographic lenses.
+//
+//               A Lens object is the main part of a Camera node
+//               (defined in sgraph), which defines the fundamental
+//               interface to point-of-view for rendering.  Lenses are
+//               also used in other contexts, however; for instance, a
+//               Spotlight is also defined using a lens.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA Lens : public TypedReferenceCount {
+public:
+  Lens();
+  Lens(const Lens &copy);
+  void operator = (const Lens &copy);
+
+PUBLISHED:
+  virtual PT(Lens) make_copy() const=0;
+
+  INLINE bool extrude(const LPoint2f &point2d,
+                      LPoint3f &near_point, LPoint3f &far_point) const;
+  INLINE bool extrude(const LPoint3f &point2d,
+                      LPoint3f &near_point, LPoint3f &far_point) const;
+  INLINE bool project(const LPoint3f &point3d, LPoint3f &point2d) const;
+  INLINE bool project(const LPoint3f &point3d, LPoint2f &point2d) const;
+
+  INLINE void set_change_event(const string &event);
+  INLINE const string &get_change_event() const;
+
+  void set_coordinate_system(CoordinateSystem cs);
+  INLINE CoordinateSystem get_coordinate_system() const;
+
+  void clear();
+
+  void set_film_size(float width);
+  INLINE void set_film_size(float width, float height);
+  void set_film_size(const LVecBase2f &film_size);
+  const LVecBase2f &get_film_size() const;
+
+  INLINE void set_film_offset(float x, float y);
+  INLINE void set_film_offset(const LVecBase2f &film_offset);
+  INLINE const LVector2f &get_film_offset() const;
+
+  void set_focal_length(float focal_length);
+  float get_focal_length() const;
+
+  void set_fov(float fov);
+  INLINE void set_fov(float hfov, float vfov);
+  void set_fov(const LVecBase2f &fov);
+  const LVecBase2f &get_fov() const;
+  INLINE float get_hfov() const;
+  INLINE float get_vfov() const;
+
+  void set_aspect_ratio(float aspect_ratio);
+  float get_aspect_ratio() const;
+
+  INLINE void set_near(float near_distance);
+  INLINE float get_near() const;
+  INLINE void set_far(float far_distance);
+  INLINE float get_far() const;
+  INLINE void set_near_far(float near_distance, float far_distance);
+  
+  INLINE void set_view_hpr(float h, float p, float r);
+  void set_view_hpr(const LVecBase3f &view_hpr);
+  const LVecBase3f &get_view_hpr() const;
+  INLINE void set_view_vector(float x, float y, float z, float i, float j, float k);
+  void set_view_vector(const LVector3f &view_vector, const LVector3f &up_vector);
+  const LVector3f &get_view_vector() const;
+  const LVector3f &get_up_vector() const;
+  void set_iod_offset(float offset);
+  float get_iod_offset() const;
+
+  void set_view_mat(const LMatrix4f &view_mat);
+  const LMatrix4f &get_view_mat() const;
+
+  void recompute_all();
+
+  virtual bool is_linear() const;
+  virtual PT(Geom) make_geometry();
+
+  virtual PT(BoundingVolume) make_bounds() const;
+
+  const LMatrix4f &get_projection_mat() const;
+  const LMatrix4f &get_projection_mat_inv() const;
+
+  virtual void output(ostream &out) const;
+  virtual void write(ostream &out, int indent_level = 0) const;
+
+protected:
+  INLINE void adjust_user_flags(int clear_flags, int set_flags);
+  INLINE void adjust_comp_flags(int clear_flags, int set_flags);
+
+  void throw_change_event();
+
+  const LMatrix4f &get_film_mat() const;
+  const LMatrix4f &get_film_mat_inv() const;
+
+  const LMatrix4f &get_lens_mat() const;
+  const LMatrix4f &get_lens_mat_inv() const;
+
+  virtual bool extrude_impl(const LPoint3f &point2d,
+                            LPoint3f &near_point, LPoint3f &far_point) const;
+  virtual bool project_impl(const LPoint3f &point3d, LPoint3f &point2d) const;
+
+  virtual void compute_film_size();
+  virtual void compute_focal_length();
+  virtual void compute_fov();
+  virtual void compute_aspect_ratio();
+  virtual void compute_view_hpr();
+  virtual void compute_view_vector();
+  virtual void compute_iod_offset();
+  virtual void compute_projection_mat();
+  virtual void compute_film_mat();
+  virtual void compute_lens_mat();
+
+  virtual float fov_to_film(float fov, float focal_length, bool horiz) const;
+  virtual float fov_to_focal_length(float fov, float film_size, bool horiz) const;
+  virtual float film_to_fov(float film_size, float focal_length, bool horiz) const;
+
+private:
+  static void resequence_fov_triad(char &newest, char &older_a, char &older_b);
+  int define_geom_coords();
+
+protected:
+  string _change_event;
+  CoordinateSystem _cs;
+
+  LVecBase2f _film_size;
+  LVector2f _film_offset;
+  float _focal_length;
+  LVecBase2f _fov;
+  float _aspect_ratio;
+  float _near_distance, _far_distance;
+
+  LVecBase3f _view_hpr;
+  LVector3f _view_vector, _up_vector;
+  float _iod_offset;
+
+  LMatrix4f _film_mat, _film_mat_inv;
+  LMatrix4f _lens_mat, _lens_mat_inv;
+  LMatrix4f _projection_mat, _projection_mat_inv;
+
+  enum UserFlags {
+    // Parameters the user may have explicitly specified.
+    UF_film_width          = 0x0001,
+    UF_film_height         = 0x0002,
+    UF_focal_length        = 0x0004,
+    UF_hfov                = 0x0008,
+    UF_vfov                = 0x0010,
+    UF_aspect_ratio        = 0x0020,
+    UF_view_hpr            = 0x0040,
+    UF_view_vector         = 0x0080,
+    UF_iod_offset          = 0x0100,
+    UF_view_mat            = 0x0200,
+  };
+
+  enum CompFlags {
+    // Values that may need to be recomputed.
+    CF_film_mat            = 0x0001,
+    CF_film_mat_inv        = 0x0002,
+    CF_lens_mat            = 0x0004,
+    CF_lens_mat_inv        = 0x0008,
+    CF_projection_mat      = 0x0010,
+    CF_projection_mat_inv  = 0x0020,
+    CF_mat                 = 0x003f,  // all of the above.
+
+    CF_focal_length        = 0x0040,
+    CF_fov                 = 0x0080,
+    CF_film_size           = 0x0100,
+    CF_aspect_ratio        = 0x0200,
+    CF_view_hpr            = 0x0400,
+    CF_view_vector         = 0x0800,
+    CF_iod_offset          = 0x1000,
+  };
+  short _user_flags;
+  short _comp_flags;
+
+  // The user may only specify two of these three parameters.
+  // Specifying the third parameter wipes out the first one specified.
+  // We therefore need to remember the order in which the user has
+  // specified these three parameters.  A bit of a mess.
+  char _focal_length_seq, _fov_seq, _film_size_seq;
+
+  PTA_Vertexf _geom_coords;
+
+  static const float _default_fov;
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedReferenceCount::init_type();
+    register_type(_type_handle, "Lens",
+                  TypedReferenceCount::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+EXPCL_PANDA INLINE ostream &operator << (ostream &out, const Lens &lens);
+
+#include "lens.I"
+
+#endif
+

+ 0 - 41
panda/src/gobj/orthoProjection.I

@@ -1,41 +0,0 @@
-// Filename: orthoProjection.I
-// Created by:  mike (18Feb99)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://www.panda3d.org/license.txt .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////
-//     Function: OrthoProjection::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE OrthoProjection::
-OrthoProjection(const Frustumf &frustum) : _frustum(frustum) {
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: OrthoProjection::get_frustum
-//       Access: Public
-//  Description: Returns the frustum that defines the perspective
-//               projection.
-////////////////////////////////////////////////////////////////////
-INLINE const Frustumf &OrthoProjection::
-get_frustum() const {
-  return _frustum;
-}
-
-
-

+ 0 - 142
panda/src/gobj/orthoProjection.cxx

@@ -1,142 +0,0 @@
-// Filename: orthoProjection.cxx
-// Created by:  mike (18Feb99)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://www.panda3d.org/license.txt .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "geomLine.h"
-#include "orthoProjection.h"
-
-#include <boundingHexahedron.h>
-
-TypeHandle OrthoProjection::_type_handle;
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: OrthoProjection::make_copy
-//       Access: Public, Virtual
-//  Description: Allocates a new Projection just like this one.
-////////////////////////////////////////////////////////////////////
-Projection *OrthoProjection::
-make_copy() const {
-  return new OrthoProjection(*this);
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: OrthoProjection::get_projection_mat
-//       Access: Public, Virtual
-//  Description: This computes a transform matrix that performs the
-//               orthographic transform defined by the frustum.
-////////////////////////////////////////////////////////////////////
-LMatrix4f OrthoProjection::
-get_projection_mat(CoordinateSystem cs) const {
-  return _frustum.get_ortho_projection_mat(cs);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: OrthoProjection::make_geometry
-//       Access: Public, Virtual
-//  Description: Creates a GeomLine that describes the shape of the
-//               frustum for this projection
-////////////////////////////////////////////////////////////////////
-Geom *OrthoProjection::
-make_geometry(const Colorf &color,
-              CoordinateSystem cs) const {
-  Vertexf rtn, ltn, lbn, rbn;
-  Vertexf rtf, ltf, lbf, rbf;
-
-  // x, y, and z here refer to the right, forward, and up vectors,
-  // which are not necessarily the x, y, and z axes.
-
-  LVector3f x = LVector3f::right(cs);
-  LVector3f y = LVector3f::forward(cs);
-  LVector3f z = LVector3f::up(cs);
-  LPoint3f o = LPoint3f::origin(cs);
-
-  Vertexf xl = x * _frustum._l;
-  Vertexf xr = x * _frustum._r;
-  Vertexf zt = z * _frustum._t;
-  Vertexf zb = z * _frustum._b;
-  Vertexf yn = o + (y * _frustum._fnear);
-
-  rtn = yn + zt + xr;
-  ltn = yn + zt + xl;
-  lbn = yn + zb + xl;
-  rbn = yn + zb + xr;
-
-  float fs = _frustum._ffar / _frustum._fnear;
-  Vertexf yf = o + (y * _frustum._ffar);
-
-  rtf = yf + ((zt + xr) * fs);
-  ltf = yf + ((zt + xl) * fs);
-  lbf = yf + ((zb + xl) * fs);
-  rbf = yf + ((zb + xr) * fs);
-
-  PTA_Vertexf coords=PTA_Vertexf::empty_array(0);
-  PTA_ushort vindex=PTA_ushort::empty_array(0);
-  PTA_Colorf colors=PTA_Colorf::empty_array(0);
-
-  // We just specify overall color
-  colors.push_back(color);
-
-  coords.push_back(rtn);
-  coords.push_back(ltn);
-  coords.push_back(lbn);
-  coords.push_back(rbn);
-  coords.push_back(rtf);
-  coords.push_back(ltf);
-  coords.push_back(lbf);
-  coords.push_back(rbf);
-  coords.push_back(o);
-
-  // Draw the near plane
-  vindex.push_back(0); vindex.push_back(1);
-  vindex.push_back(1); vindex.push_back(2);
-  vindex.push_back(2); vindex.push_back(3);
-  vindex.push_back(3); vindex.push_back(0);
-
-  // Draw the far plane
-  vindex.push_back(4); vindex.push_back(5);
-  vindex.push_back(5); vindex.push_back(6);
-  vindex.push_back(6); vindex.push_back(7);
-  vindex.push_back(7); vindex.push_back(4);
-
-  // Draw lines from eye to the corners
-  vindex.push_back(8); vindex.push_back(4);
-  vindex.push_back(8); vindex.push_back(5);
-  vindex.push_back(8); vindex.push_back(6);
-  vindex.push_back(8); vindex.push_back(7);
-
-  GeomLine* gline = new GeomLine;
-  gline->set_coords(coords, vindex);
-  gline->set_colors(colors, G_OVERALL);
-  gline->set_num_prims(12);
-
-  return gline;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: OrthoProjection::make_bounds
-//       Access: Public, Virtual
-//  Description: Allocates and returns a new BoundingVolume that
-//               encloses the frustum used for this kind of
-//               projection, if possible.  If a suitable bounding
-//               volume cannot be created, returns NULL.
-////////////////////////////////////////////////////////////////////
-BoundingVolume *OrthoProjection::
-make_bounds(CoordinateSystem cs) const {
-  return new BoundingHexahedron(_frustum, true, cs);
-}

+ 12 - 24
panda/src/sgraph/projectionNode.I → panda/src/gobj/orthographicLens.I

@@ -1,5 +1,5 @@
-// Filename: projectionNode.I
-// Created by:  drose (23May00)
+// Filename: orthographicLens.I
+// Created by:  mike (18Feb99)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -17,42 +17,30 @@
 ////////////////////////////////////////////////////////////////////
 
 ////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::Constructor
+//     Function: OrthographicLens::Constructor
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE ProjectionNode::
-ProjectionNode(const string &name) :
-  NamedNode(name)
-{
+INLINE OrthographicLens::
+OrthographicLens() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::Copy Constructor
+//     Function: OrthographicLens::Copy Constructor
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE ProjectionNode::
-ProjectionNode(const ProjectionNode &copy) :
-  NamedNode(copy),
-  _projection(copy._projection)
-{
+INLINE OrthographicLens::
+OrthographicLens(const OrthographicLens &copy) : Lens(copy) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::Copy Assignment Operator
+//     Function: OrthographicLens::Copy Assignment Operator
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void ProjectionNode::
-operator = (const ProjectionNode &copy) {
-  NamedNode::operator = (copy);
-  _projection = copy._projection;
+INLINE void OrthographicLens::
+operator = (const OrthographicLens &copy) {
+  Lens::operator = (copy);
 }
 
-INLINE ostream &operator << (ostream &out, const ProjectionNode &projnode) {
-  projnode.output(out);
-  return out;
-}
-
-

+ 114 - 0
panda/src/gobj/orthographicLens.cxx

@@ -0,0 +1,114 @@
+// Filename: orthographicLens.cxx
+// Created by:  mike (18Feb99)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "orthographicLens.h"
+#include "indent.h"
+
+TypeHandle OrthographicLens::_type_handle;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: OrthographicLens::make_copy
+//       Access: Public, Virtual
+//  Description: Allocates a new Lens just like this one.
+////////////////////////////////////////////////////////////////////
+PT(Lens) OrthographicLens::
+make_copy() const {
+  return new OrthographicLens(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OrthographicLens::is_linear
+//       Access: Published, Virtual
+//  Description: Returns true if the lens represents a linear
+//               projection (e.g. PerspectiveLens, OrthographicLens),
+//               and therefore there is a valid matrix returned by
+//               get_projection_mat(), or false otherwise.
+////////////////////////////////////////////////////////////////////
+bool OrthographicLens::
+is_linear() const {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OrthographicLens::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void OrthographicLens::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level) << get_type() << " film size = " << get_film_size() << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OrthographicLens::compute_projection_mat
+//       Access: Protected, Virtual
+//  Description: Computes the complete transformation matrix from 3-d
+//               point to 2-d point, if the lens is linear.
+////////////////////////////////////////////////////////////////////
+void OrthographicLens::
+compute_projection_mat() {
+  CoordinateSystem cs = _cs;
+  if (cs == CS_default) {
+    cs = default_coordinate_system;
+  }
+
+  float a = 2.0f / (_far_distance - _near_distance);
+  float b = -(_far_distance + _near_distance) / (_far_distance - _near_distance);
+
+  LMatrix4f canonical;
+  switch (cs) {
+  case CS_zup_right:
+    canonical.set(1.0f,  0.0f,  0.0f,  0.0f,
+                  0.0f,  0.0f,     a,  0.0f,
+                  0.0f,  1.0f,  0.0f,  0.0f,
+                  0.0f,  0.0f,     b,  1.0f);
+    break;
+
+  case CS_yup_right:
+    canonical.set(1.0f,  0.0f,  0.0f,  0.0f,
+                  0.0f,  1.0f,  0.0f,  0.0f,
+                  0.0f,  0.0f,    -a,  0.0f,
+                  0.0f,  0.0f,     b,  1.0f);
+    break;
+
+  case CS_zup_left:
+    canonical.set(1.0f,  0.0f,  0.0f,  0.0f,
+                  0.0f,  0.0f,    -a,  0.0f,
+                  0.0f,  1.0f,  0.0f,  0.0f,
+                  0.0f,  0.0f,     b,  1.0f);
+    break;
+
+  case CS_yup_left:
+    canonical.set(1.0f,  0.0f,  0.0f,  0.0f,
+                  0.0f,  1.0f,  0.0f,  0.0f,
+                  0.0f,  0.0f,     a,  0.0f,
+                  0.0f,  0.0f,     b,  1.0f);
+    break;
+
+  default:
+    gobj_cat.error()
+      << "Invalid coordinate system " << (int)cs << " in PerspectiveLens!\n";
+    canonical = LMatrix4f::ident_mat();
+  }
+
+
+  _projection_mat = get_lens_mat_inv() * canonical * get_film_mat();
+  adjust_comp_flags(CF_projection_mat_inv, 
+                    CF_projection_mat);
+}

+ 75 - 0
panda/src/gobj/orthographicLens.h

@@ -0,0 +1,75 @@
+// Filename: orthographicLens.h
+// Created by:  mike (18Feb99)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef ORTHOGRAPHICLENS_H
+#define ORTHOGRAPHICLENS_H
+
+#include "pandabase.h"
+
+#include "lens.h"
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : OrthographicLens
+// Description : An orthographic lens.  Although this kind of lens is
+//               linear, like a PerspectiveLens, it doesn't respect
+//               field-of-view or focal length parameters, and
+//               adjusting these will have no effect.  Instead, its
+//               field of view is controlled by adjusting the
+//               film_size; the orthographic lens represents a planar
+//               projection onto its imaginary film of the specified
+//               size, hanging in space.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA OrthographicLens : public Lens {
+PUBLISHED:
+  INLINE OrthographicLens();
+
+public:
+  INLINE OrthographicLens(const OrthographicLens &copy);
+  INLINE void operator = (const OrthographicLens &copy);
+
+public:
+  virtual PT(Lens) make_copy() const;
+  virtual bool is_linear() const;
+
+  virtual void write(ostream &out, int indent_level = 0) const;
+
+protected:
+  virtual void compute_projection_mat();
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    Lens::init_type();
+    register_type(_type_handle, "OrthographicLens",
+                  Lens::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "orthographicLens.I"
+
+#endif

+ 16 - 14
panda/src/gobj/perspectiveProjection.I → panda/src/gobj/perspectiveLens.I

@@ -1,4 +1,4 @@
-// Filename: perspectiveProjection.I
+// Filename: perspectiveLens.I
 // Created by:  drose (18Feb99)
 //
 ////////////////////////////////////////////////////////////////////
@@ -17,28 +17,30 @@
 ////////////////////////////////////////////////////////////////////
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PerspectiveProjection::Constructor
+//     Function: PerspectiveLens::Constructor
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE PerspectiveProjection::
-PerspectiveProjection(const Frustumf &frustum) : _frustum(frustum) {
+INLINE PerspectiveLens::
+PerspectiveLens() {
 }
 
-
 ////////////////////////////////////////////////////////////////////
-//     Function: PerspectiveProjection::get_frustum
+//     Function: PerspectiveLens::Copy Constructor
 //       Access: Public
-//  Description: Returns the frustum that defines the perspective
-//               projection.
+//  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE const Frustumf &PerspectiveProjection::
-get_frustum() const {
-  return _frustum;
+INLINE PerspectiveLens::
+PerspectiveLens(const PerspectiveLens &copy) : Lens(copy) {
 }
 
-INLINE void PerspectiveProjection::
-set_frustum(const Frustumf &frust) {
-  _frustum = frust;
+////////////////////////////////////////////////////////////////////
+//     Function: PerspectiveLens::Copy Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void PerspectiveLens::
+operator = (const PerspectiveLens &copy) {
+  Lens::operator = (copy);
 }
 

+ 146 - 0
panda/src/gobj/perspectiveLens.cxx

@@ -0,0 +1,146 @@
+// Filename: perspectiveLens.cxx
+// Created by:  drose (18Feb99)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "perspectiveLens.h"
+
+TypeHandle PerspectiveLens::_type_handle;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PerspectiveLens::make_copy
+//       Access: Public, Virtual
+//  Description: Allocates a new Lens just like this one.
+////////////////////////////////////////////////////////////////////
+PT(Lens) PerspectiveLens::
+make_copy() const {
+  return new PerspectiveLens(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PerspectiveLens::is_linear
+//       Access: Published, Virtual
+//  Description: Returns true if the lens represents a linear
+//               projection (e.g. PerspectiveLens, OrthographicLens),
+//               and therefore there is a valid matrix returned by
+//               get_projection_mat(), or false otherwise.
+////////////////////////////////////////////////////////////////////
+bool PerspectiveLens::
+is_linear() const {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PerspectiveLens::compute_projection_mat
+//       Access: Protected, Virtual
+//  Description: Computes the complete transformation matrix from 3-d
+//               point to 2-d point, if the lens is linear.
+////////////////////////////////////////////////////////////////////
+void PerspectiveLens::
+compute_projection_mat() {
+  CoordinateSystem cs = _cs;
+  if (cs == CS_default) {
+    cs = default_coordinate_system;
+  }
+
+  float fl = get_focal_length();
+  float a = (_far_distance + _near_distance) / (_far_distance - _near_distance);
+  float b = -2.0f * _far_distance * _near_distance / (_far_distance - _near_distance);
+
+  LMatrix4f canonical;
+  switch (cs) {
+  case CS_zup_right:
+    canonical.set(  fl,  0.0f,  0.0f,  0.0f,
+                  0.0f,  0.0f,     a,  1.0f,
+                  0.0f,    fl,  0.0f,  0.0f,
+                  0.0f,  0.0f,     b,  0.0f);
+    break;
+
+  case CS_yup_right:
+    canonical.set(  fl,  0.0f,  0.0f,  0.0f,
+                  0.0f,    fl,  0.0f,  0.0f,
+                  0.0f,  0.0f,    -a, -1.0f,
+                  0.0f,  0.0f,     b,  0.0f);
+    break;
+
+  case CS_zup_left:
+    canonical.set(  fl,  0.0f,  0.0f,  0.0f,
+                  0.0f,  0.0f,    -a, -1.0f,
+                  0.0f,    fl,  0.0f,  0.0f,
+                  0.0f,  0.0f,     b,  0.0f);
+    break;
+
+  case CS_yup_left:
+    canonical.set(  fl,  0.0f,  0.0f,  0.0f,
+                  0.0f,    fl,  0.0f,  0.0f,
+                  0.0f,  0.0f,     a,  1.0f,
+                  0.0f,  0.0f,     b,  0.0f);
+    break;
+
+  default:
+    gobj_cat.error()
+      << "Invalid coordinate system " << (int)cs << " in PerspectiveLens!\n";
+    canonical = LMatrix4f::ident_mat();
+  }
+
+
+  _projection_mat = get_lens_mat_inv() * canonical * get_film_mat();
+  adjust_comp_flags(CF_projection_mat_inv, 
+                    CF_projection_mat);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PerspectiveLens::fov_to_film
+//       Access: Protected, Virtual
+//  Description: Given a field of view in degrees and a focal length,
+//               compute the correspdonding width (or height) on the
+//               film.  If horiz is true, this is in the horizontal
+//               direction; otherwise, it is in the vertical direction
+//               (some lenses behave differently in each direction).
+////////////////////////////////////////////////////////////////////
+float PerspectiveLens::
+fov_to_film(float fov, float focal_length, bool) const {
+  return (ctan(deg_2_rad(fov * 0.5f)) * focal_length) * 2.0f;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PerspectiveLens::fov_to_focal_length
+//       Access: Protected, Virtual
+//  Description: Given a field of view in degrees and a width (or
+//               height) on the film, compute the focal length of the
+//               lens.  If horiz is true, this is in the horizontal
+//               direction; otherwise, it is in the vertical direction
+//               (some lenses behave differently in each direction).
+////////////////////////////////////////////////////////////////////
+float PerspectiveLens::
+fov_to_focal_length(float fov, float film_size, bool) const {
+  return film_size * 0.5f / ctan(deg_2_rad(fov * 0.5f));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PerspectiveLens::film_to_fov
+//       Access: Protected, Virtual
+//  Description: Given a width (or height) on the film and a focal
+//               length, compute the field of view in degrees.  If
+//               horiz is true, this is in the horizontal direction;
+//               otherwise, it is in the vertical direction (some
+//               lenses behave differently in each direction).
+////////////////////////////////////////////////////////////////////
+float PerspectiveLens::
+film_to_fov(float film_size, float focal_length, bool) const {
+  return rad_2_deg(catan(film_size * 0.5f / focal_length)) * 2.0f;
+}

+ 24 - 27
panda/src/gobj/orthoProjection.h → panda/src/gobj/perspectiveLens.h

@@ -1,5 +1,5 @@
-// Filename: orthoProjection.h
-// Created by:  mike (18Feb99)
+// Filename: perspectiveLens.h
+// Created by:  drose (18Feb99)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -16,37 +16,36 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#ifndef ORTHOPROJECTION_H
-#define ORTHOPROJECTION_H
+#ifndef PERSPECTIVELENS_H
+#define PERSPECTIVELENS_H
 
-#include <pandabase.h>
+#include "pandabase.h"
 
-#include "projection.h"
-#include <frustum.h>
+#include "lens.h"
 
 
 ////////////////////////////////////////////////////////////////////
-//       Class : OrthoProjection
-// Description : An orthographic-type projection, with a frustum.
+//       Class : PerspectiveLens
+// Description : A perspective-type lens: a normal camera.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA OrthoProjection : public Projection {
+class EXPCL_PANDA PerspectiveLens : public Lens {
 PUBLISHED:
-  INLINE OrthoProjection(const Frustumf &frustum);
+  INLINE PerspectiveLens();
 
 public:
-  virtual Projection *make_copy() const;
-  virtual LMatrix4f get_projection_mat(CoordinateSystem cs = CS_default) const;
-
-  virtual Geom* make_geometry(const Colorf &color = Colorf(0.0f, 1.0f, 0.0f, 1.0f),
-                              CoordinateSystem cs = CS_default) const;
-
-  virtual BoundingVolume *make_bounds(CoordinateSystem cs = CS_default) const;
-
-  INLINE const Frustumf &get_frustum() const;
+  INLINE PerspectiveLens(const PerspectiveLens &copy);
+  INLINE void operator = (const PerspectiveLens &copy);
 
+public:
+  virtual PT(Lens) make_copy() const;
+  virtual bool is_linear() const;
 
 protected:
-  Frustumf _frustum;
+  virtual void compute_projection_mat();
+
+  virtual float fov_to_film(float fov, float focal_length, bool horiz) const;
+  virtual float fov_to_focal_length(float fov, float film_size, bool horiz) const;
+  virtual float film_to_fov(float film_size, float focal_length, bool horiz) const;
 
 public:
   virtual TypeHandle get_type() const {
@@ -57,17 +56,15 @@ public:
     return _type_handle;
   }
   static void init_type() {
-    Projection::init_type();
-    register_type(_type_handle, "OrthoProjection",
-                  Projection::get_class_type());
+    Lens::init_type();
+    register_type(_type_handle, "PerspectiveLens",
+                  Lens::get_class_type());
   }
 
 private:
   static TypeHandle _type_handle;
 };
 
-#include "orthoProjection.I"
+#include "perspectiveLens.I"
 
 #endif
-
-

+ 0 - 219
panda/src/gobj/perspectiveProjection.cxx

@@ -1,219 +0,0 @@
-// Filename: perspectiveProjection.cxx
-// Created by:  drose (18Feb99)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://www.panda3d.org/license.txt .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "geomLine.h"
-#include "perspectiveProjection.h"
-
-#include <boundingHexahedron.h>
-
-
-TypeHandle PerspectiveProjection::_type_handle;
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: PerspectiveProjection::make_copy
-//       Access: Public, Virtual
-//  Description: Allocates a new Projection just like this one.
-////////////////////////////////////////////////////////////////////
-Projection *PerspectiveProjection::
-make_copy() const {
-  return new PerspectiveProjection(*this);
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: PerspectiveProjection::get_projection_mat
-//       Access: Public, Virtual
-//  Description: This computes a transform matrix that performs the
-//               perspective transform defined by the frustum.
-////////////////////////////////////////////////////////////////////
-LMatrix4f PerspectiveProjection::
-get_projection_mat(CoordinateSystem cs) const {
-  return _frustum.get_perspective_projection_mat(cs);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PerspectiveProjection::make_geometry
-//       Access: Public, Virtual
-//  Description: Creates a GeomLine that describes the shape of the
-//               frustum for this projection
-////////////////////////////////////////////////////////////////////
-Geom *PerspectiveProjection::
-make_geometry(const Colorf &color,
-              CoordinateSystem cs) const {
-  Vertexf rtn, ltn, lbn, rbn;
-  Vertexf rtf, ltf, lbf, rbf;
-
-  // x, y, and z here refer to the right, forward, and up vectors,
-  // which are not necessarily the x, y, and z axes.
-
-  LVector3f x = LVector3f::right(cs);
-  LVector3f y = LVector3f::forward(cs);
-  LVector3f z = LVector3f::up(cs);
-  LPoint3f o = LPoint3f::origin(cs);
-
-  Vertexf xl = x * _frustum._l;
-  Vertexf xr = x * _frustum._r;
-  Vertexf zt = z * _frustum._t;
-  Vertexf zb = z * _frustum._b;
-  Vertexf yn = o + (y * _frustum._fnear);
-
-  rtn = yn + zt + xr;
-  ltn = yn + zt + xl;
-  lbn = yn + zb + xl;
-  rbn = yn + zb + xr;
-
-  float fs = _frustum._ffar / _frustum._fnear;
-  Vertexf yf = o + (y * _frustum._ffar);
-
-  rtf = yf + ((zt + xr) * fs);
-  ltf = yf + ((zt + xl) * fs);
-  lbf = yf + ((zb + xl) * fs);
-  rbf = yf + ((zb + xr) * fs);
-
-  PTA_Vertexf coords=PTA_Vertexf::empty_array(0);
-  PTA_ushort vindex=PTA_ushort::empty_array(0);
-  PTA_Colorf colors=PTA_Colorf::empty_array(0);
-
-  // We just specify overall color
-  colors.push_back(color);
-
-  coords.push_back(rtn);
-  coords.push_back(ltn);
-  coords.push_back(lbn);
-  coords.push_back(rbn);
-  coords.push_back(rtf);
-  coords.push_back(ltf);
-  coords.push_back(lbf);
-  coords.push_back(rbf);
-  coords.push_back(o);
-
-  // Draw the near plane
-  vindex.push_back(0); vindex.push_back(1);
-  vindex.push_back(1); vindex.push_back(2);
-  vindex.push_back(2); vindex.push_back(3);
-  vindex.push_back(3); vindex.push_back(0);
-
-  // Draw the far plane
-  vindex.push_back(4); vindex.push_back(5);
-  vindex.push_back(5); vindex.push_back(6);
-  vindex.push_back(6); vindex.push_back(7);
-  vindex.push_back(7); vindex.push_back(4);
-
-  // Draw lines from eye to the corners
-  vindex.push_back(8); vindex.push_back(4);
-  vindex.push_back(8); vindex.push_back(5);
-  vindex.push_back(8); vindex.push_back(6);
-  vindex.push_back(8); vindex.push_back(7);
-
-  GeomLine* gline = new GeomLine;
-  gline->set_coords(coords, vindex);
-  gline->set_colors(colors, G_OVERALL);
-  gline->set_num_prims(12);
-
-  return gline;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PerspectiveProjection::make_bounds
-//       Access: Public, Virtual
-//  Description: Allocates and returns a new BoundingVolume that
-//               encloses the frustum used for this kind of
-//               projection, if possible.  If a suitable bounding
-//               volume cannot be created, returns NULL.
-////////////////////////////////////////////////////////////////////
-BoundingVolume *PerspectiveProjection::
-make_bounds(CoordinateSystem cs) const {
-  return new BoundingHexahedron(_frustum, false, cs);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PerspectiveProjection::extrude
-//       Access: Public, Virtual
-//  Description: Given a 2-d point in the range (-1,1) in both
-//               dimensions, where (0,0) is the center of the
-//               projection and (-1,-1) is the lower-left corner,
-//               compute the corresponding vector in space that maps
-//               to this point, if such a vector can be determined.
-//               Returns true if the vector is defined (in which case
-//               origin and direction are set to define the vector),
-//               or false otherwise.
-////////////////////////////////////////////////////////////////////
-bool PerspectiveProjection::
-extrude(const LPoint2f &point2d, LPoint3f &origin, LVector3f &direction,
-        CoordinateSystem cs) const {
-  if (point2d[0] < -1 || point2d[0] > 1 ||
-      point2d[1] < -1 || point2d[1] > 1) {
-    // The point is off the near plane.
-    return false;
-  }
-
-  // Scale the point from (-1,1) to the range of the frustum.
-
-  LPoint2f scaled(_frustum._l + 0.5f * (point2d[0] + 1.0f) *
-                  (_frustum._r - _frustum._l),
-                  _frustum._b + 0.5f * (point2d[1] + 1.0f) *
-                  (_frustum._t - _frustum._b));
-
-  LVector3f near_vector =
-    LVector3f::rfu(scaled[0], _frustum._fnear, scaled[1], cs);
-  LVector3f far_vector =
-    near_vector * _frustum._ffar / _frustum._fnear;
-
-  origin = LPoint3f::origin(cs) + near_vector;
-  direction = far_vector - near_vector;
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PerspectiveProjection::project
-//       Access: Public, Virtual
-//  Description: Given a 3-d point in space, determine the 2-d point
-//               this maps to, in the range (-1,1) in both dimensions,
-//               where (0,0) is the center of the projection and
-//               (-1,-1) is the lower-left corner.  Returns true if
-//               the 3-d point is in front of the projection and
-//               within the viewing frustum (in which case point2d is
-//               filled in), or false otherwise.
-////////////////////////////////////////////////////////////////////
-bool PerspectiveProjection::
-project(const LPoint3f &point3d, LPoint2f &point2d,
-        CoordinateSystem cs) const {
-  float f = point3d.dot(LVector3f::forward(cs));
-  if (f < _frustum._fnear || f > _frustum._ffar) {
-    // The point is outside the near or far clipping planes.
-    return false;
-  }
-
-  float r = point3d.dot(LVector3f::right(cs));
-  float u = point3d.dot(LVector3f::up(cs));
-
-  LPoint2f scaled(r * _frustum._fnear / f, u * _frustum._fnear / f);
-
-  if (scaled[0] < _frustum._l || scaled[0] > _frustum._r ||
-      scaled[1] < _frustum._b || scaled[1] > _frustum._t) {
-    // The point is outside of the edge planes.
-    return false;
-  }
-
-  point2d.set((scaled[0] - _frustum._l) * 2.0f /
-              (_frustum._r - _frustum._l) - 1.0f,
-              (scaled[1] - _frustum._b) * 2.0f /
-              (_frustum._t - _frustum._b) - 1.0f);
-  return true;
-}

+ 0 - 79
panda/src/gobj/perspectiveProjection.h

@@ -1,79 +0,0 @@
-// Filename: perspectiveProjection.h
-// Created by:  drose (18Feb99)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://www.panda3d.org/license.txt .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef PERSPECTIVEPROJECTION_H
-#define PERSPECTIVEPROJECTION_H
-
-#include <pandabase.h>
-
-#include "projection.h"
-#include <frustum.h>
-
-
-////////////////////////////////////////////////////////////////////
-//       Class : PerspectiveProjection
-// Description : A perspective-type projection, with a frustum.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA PerspectiveProjection : public Projection {
-PUBLISHED:
-  INLINE PerspectiveProjection(const Frustumf &frustum);
-
-public:
-  virtual Projection *make_copy() const;
-  virtual LMatrix4f get_projection_mat(CoordinateSystem cs = CS_default) const;
-
-  virtual Geom* make_geometry(const Colorf &color = Colorf(0.0f, 1.0f, 0.0f, 1.0f),
-                              CoordinateSystem cs = CS_default) const;
-
-  virtual BoundingVolume *make_bounds(CoordinateSystem cs = CS_default) const;
-
-  virtual bool extrude(const LPoint2f &point2d,
-                       LPoint3f &origin, LVector3f &direction,
-                       CoordinateSystem cs = CS_default) const;
-  virtual bool project(const LPoint3f &point3d, LPoint2f &point2d,
-                       CoordinateSystem cs) const;
-
-  INLINE const Frustumf &get_frustum() const;
-  INLINE void set_frustum(const Frustumf &frust);
-
-protected:
-  Frustumf _frustum;
-
-public:
-  virtual TypeHandle get_type() const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    Projection::init_type();
-    register_type(_type_handle, "PerspectiveProjection",
-                  Projection::get_class_type());
-  }
-
-private:
-  static TypeHandle _type_handle;
-};
-
-#include "perspectiveProjection.I"
-
-#endif
-
-

+ 0 - 81
panda/src/gobj/projection.cxx

@@ -1,81 +0,0 @@
-// Filename: projection.cxx
-// Created by:  drose (18Feb99)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://www.panda3d.org/license.txt .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "projection.h"
-
-TypeHandle Projection::_type_handle;
-
-////////////////////////////////////////////////////////////////////
-//     Function: Projection::make_geometry
-//       Access: Public, Virtual
-//  Description: Allocates and returns a new Geom that can be rendered
-//               to show a visible representation of the frustum used
-//               for this kind of projection, if it makes sense to do
-//               so.  If a visible representation cannot be created,
-//               returns NULL.
-////////////////////////////////////////////////////////////////////
-Geom *Projection::
-make_geometry(const Colorf &, CoordinateSystem) const {
-  return (Geom *)NULL;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Projection::make_bounds
-//       Access: Public, Virtual
-//  Description: Allocates and returns a new BoundingVolume that
-//               encloses the frustum used for this kind of
-//               projection, if possible.  If a suitable bounding
-//               volume cannot be created, returns NULL.
-////////////////////////////////////////////////////////////////////
-BoundingVolume *Projection::
-make_bounds(CoordinateSystem) const {
-  return (BoundingVolume *)NULL;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Projection::extrude
-//       Access: Public, Virtual
-//  Description: Given a 2-d point in the range (-1,1) in both
-//               dimensions, where (0,0) is the center of the
-//               projection and (-1,-1) is the lower-left corner,
-//               compute the corresponding vector in space that maps
-//               to this point, if such a vector can be determined.
-//               Returns true if the vector is defined (in which case
-//               origin and direction are set to define the vector),
-//               or false otherwise.
-////////////////////////////////////////////////////////////////////
-bool Projection::
-extrude(const LPoint2f &, LPoint3f &, LVector3f &, CoordinateSystem) const {
-  return false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Projection::project
-//       Access: Public, Virtual
-//  Description: Given a 3-d point in space, determine the 2-d point
-//               this maps to, in the range (-1,1) in both dimensions,
-//               where (0,0) is the center of the projection and
-//               (-1,-1) is the lower-left corner.  Returns true if
-//               the 3-d point is in front of the projection and
-//               within the viewing frustum (in which case point2d is
-//               filled in), or false otherwise.
-////////////////////////////////////////////////////////////////////
-bool Projection::
-project(const LPoint3f &, LPoint2f &, CoordinateSystem) const {
-  return false;
-}

+ 0 - 72
panda/src/gobj/projection.h

@@ -1,72 +0,0 @@
-// Filename: projection.h
-// Created by:  drose (18Feb99)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://www.panda3d.org/license.txt .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef PROJECTION_H
-#define PROJECTION_H
-
-#include <pandabase.h>
-
-#include <typedReferenceCount.h>
-#include <lmatrix.h>
-#include "geom.h"
-
-class BoundingVolume;
-
-////////////////////////////////////////////////////////////////////
-//       Class : Projection
-// Description : A base class for any number of different kinds of
-//               linear projections.  Presently, this includes
-//               perspective and orthographic projections.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA Projection : public TypedReferenceCount {
-PUBLISHED:
-  virtual Projection *make_copy() const=0;
-
-  virtual bool extrude(const LPoint2f &point2d,
-                       LPoint3f &origin, LVector3f &direction,
-                       CoordinateSystem cs = CS_default) const;
-  virtual bool project(const LPoint3f &point3d, LPoint2f &point2d,
-                       CoordinateSystem cs = CS_default) const;
-
-public:
-  virtual LMatrix4f get_projection_mat(CoordinateSystem cs = CS_default) const=0;
-  virtual Geom* make_geometry(const Colorf &color = Colorf(0.0, 1.0, 0.0, 1.0),
-                              CoordinateSystem cs = CS_default) const;
-
-  virtual BoundingVolume *make_bounds(CoordinateSystem cs = CS_default) const;
-
-public:
-  virtual TypeHandle get_type() const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    TypedReferenceCount::init_type();
-    register_type(_type_handle, "Projection",
-                  TypedReferenceCount::get_class_type());
-  }
-
-private:
-  static TypeHandle _type_handle;
-};
-
-#endif
-

+ 2 - 2
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -83,8 +83,8 @@ class Spotlight;
 class AmbientLight;
 
 class DisplayRegion;
-class Projection;
-class ProjectionNode;
+class Lens;
+class LensNode;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GraphicsStateGuardianBase

+ 0 - 1
panda/src/light/directionalLight.cxx

@@ -18,7 +18,6 @@
 #include <pandabase.h>
 #include "directionalLight.h"
 
-#include <perspectiveProjection.h>
 #include <indent.h>
 
 ////////////////////////////////////////////////////////////////////

+ 7 - 8
panda/src/light/spotlight.cxx

@@ -20,7 +20,7 @@
 #include "config_light.h"
 
 #include <renderRelation.h>
-#include <perspectiveProjection.h>
+#include <perspectiveLens.h>
 #include <texture.h>
 #include <geomNode.h>
 #include <geomTrifan.h>
@@ -39,7 +39,7 @@ TypeHandle Spotlight::_type_handle;
 //       Access:
 //  Description:
 ////////////////////////////////////////////////////////////////////
-Spotlight::Spotlight(const string& name) : ProjectionNode(name)
+Spotlight::Spotlight(const string& name) : LensNode(name)
 {
   set_exponent(1);
 
@@ -84,17 +84,16 @@ write(ostream &out, int indent_level) const {
 ////////////////////////////////////////////////////////////////////
 float Spotlight::get_cutoff_angle(void) const
 {
-  Projection* proj = ((ProjectionNode *)this)->get_projection();
-  Frustumf frustum;
+  Lens* proj = ((LensNode *)this)->get_lens();
   float cutoff = 0;
-  if (proj->get_type() == PerspectiveProjection::get_class_type()) {
-    frustum = ((PerspectiveProjection *)proj)->get_frustum();
-    cutoff = rad_2_deg(atan(frustum._t / frustum._fnear));
+  if (proj->get_type() == PerspectiveLens::get_class_type()) {
+    const LVecBase2f &fov = ((PerspectiveLens *)proj)->get_fov();
+    cutoff = fov[0];
   }
   else
     light_cat.error()
       << "Spotlight::get_cutoff_angle() - spotlight has a non "
-      << "perspective projection!" << endl;
+      << "perspective lens!" << endl;
   return cutoff;
 }
 

+ 4 - 4
panda/src/light/spotlight.h

@@ -29,7 +29,7 @@
 #include <namedNode.h>
 #include <frustum.h>
 #include "light.h"
-#include <projectionNode.h>
+#include <lensNode.h>
 
 ////////////////////////////////////////////////////////////////////
 // Defines
@@ -39,7 +39,7 @@
 //       Class : Spotlight
 // Description :
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA Spotlight : public Light, public ProjectionNode
+class EXPCL_PANDA Spotlight : public Light, public LensNode
 {
   PUBLISHED:
 
@@ -91,10 +91,10 @@ class EXPCL_PANDA Spotlight : public Light, public ProjectionNode
     }
     static void init_type( void ) {
       Light::init_type();
-      ProjectionNode::init_type();
+      LensNode::init_type();
       register_type( _type_handle, "Spotlight",
                            Light::get_class_type(),
-                           ProjectionNode::get_class_type() );
+                           LensNode::get_class_type() );
     }
     virtual TypeHandle get_type( void ) const {
       return get_class_type();

+ 16 - 0
panda/src/linmath/cmath.I

@@ -34,6 +34,10 @@ INLINE_LINMATH float ccos(float v) {
   return cosf(v);
 }
 
+INLINE_LINMATH float ctan(float v) {
+  return tanf(v);
+}
+
 INLINE_LINMATH void
 sincosf(float v, float *pSinResult, float *pCosResult) {
 
@@ -84,6 +88,10 @@ INLINE_LINMATH float cabs(float v) {
   return fabs(v);
 }
 
+INLINE_LINMATH float catan(float v) {
+  return atanf(v);
+}
+
 INLINE_LINMATH float catan2(float y, float x) {
   return atan2f(y, x);
 }
@@ -100,10 +108,18 @@ INLINE_LINMATH double ccos(double v) {
   return cos(v);
 }
 
+INLINE_LINMATH double ctan(double v) {
+  return tan(v);
+}
+
 INLINE_LINMATH double cabs(double v) {
   return fabs(v);
 }
 
+INLINE_LINMATH double catan(double v) {
+  return atan(v);
+}
+
 INLINE_LINMATH double catan2(double y, double x) {
   return atan2(y, x);
 }

+ 4 - 0
panda/src/linmath/cmath.h

@@ -32,14 +32,18 @@
 INLINE_LINMATH float csqrt(float v);
 INLINE_LINMATH float csin(float v);
 INLINE_LINMATH float ccos(float v);
+INLINE_LINMATH float ctan(float v);
 INLINE_LINMATH void  csincos(float v, float *pSinResult, float *pCosResult);  // does both at once (faster on x86)
 INLINE_LINMATH float cabs(float v);
+INLINE_LINMATH float catan(float v);
 INLINE_LINMATH float catan2(float y, float x);
 
 INLINE_LINMATH double csqrt(double v);
 INLINE_LINMATH double csin(double v);
 INLINE_LINMATH double ccos(double v);
+INLINE_LINMATH double ctan(double v);
 INLINE_LINMATH double cabs(double v);
+INLINE_LINMATH double catan(double v);
 INLINE_LINMATH double catan2(double y, double x);
 INLINE_LINMATH void   csincos(double v, double *pSinResult, double *pCosResult);  // does both at once (faster on x86)
 

+ 19 - 0
panda/src/mathutil/boundingHexahedron.cxx

@@ -60,6 +60,25 @@ BoundingHexahedron(const Frustumf &frustum, bool is_ortho,
   }
 }
 
+BoundingHexahedron::
+BoundingHexahedron(const LPoint3f &fll, const LPoint3f &flr,
+                   const LPoint3f &fur, const LPoint3f &ful,
+                   const LPoint3f &nll, const LPoint3f &nlr,
+                   const LPoint3f &nur, const LPoint3f &nul) {
+  _points[0] = fll;
+  _points[1] = flr;
+  _points[2] = fur;
+  _points[3] = ful;
+  _points[4] = nll;
+  _points[5] = nlr;
+  _points[6] = nur;
+  _points[7] = nul;
+
+  _flags = 0;
+  set_centroid();
+  set_planes();
+}
+
 BoundingVolume *BoundingHexahedron::
 make_copy() const {
   return new BoundingHexahedron(*this);

+ 4 - 0
panda/src/mathutil/boundingHexahedron.h

@@ -43,6 +43,10 @@ public:
   INLINE_MATHUTIL BoundingHexahedron();
   BoundingHexahedron(const Frustumf &frustum, bool is_ortho,
                      CoordinateSystem cs = CS_default);
+  BoundingHexahedron(const LPoint3f &fll, const LPoint3f &flr,
+                     const LPoint3f &fur, const LPoint3f &ful,
+                     const LPoint3f &nll, const LPoint3f &nlr,
+                     const LPoint3f &nur, const LPoint3f &nul);
   virtual BoundingVolume *make_copy() const;
 
   virtual LPoint3f get_min() const;

+ 3 - 3
panda/src/sgattrib/billboardTransition.cxx

@@ -23,7 +23,7 @@
 #include <graphicsStateGuardian.h>
 #include <displayRegion.h>
 #include <renderTraverser.h>
-#include <projectionNode.h>
+#include <lensNode.h>
 #include <look_at.h>
 #include <nodeTransitionWrapper.h>
 #include <wrt.h>
@@ -77,8 +77,8 @@ sub_render(NodeRelation *arc, const AllTransitionsWrapper &,
   // DisplayRegion may have some override in effect, so we ask the
   // DisplayRegion instead of the GSG.
   const DisplayRegion *dr = gsg->get_current_display_region();
-  ProjectionNode *camera = dr->get_cull_frustum();
-  nassertr(camera != (ProjectionNode *)NULL, true);
+  LensNode *camera = dr->get_cull_frustum();
+  nassertr(camera != (LensNode *)NULL, true);
 
   // And the relative coordinate space.
   LMatrix4f rel_mat;

+ 4 - 4
panda/src/sgraph/Sources.pp

@@ -12,20 +12,20 @@
      camera.I camera.h config_sgraph.h geomNode.I geomNode.h  \
      geomTransformer.I geomTransformer.h modelNode.I modelNode.h  \
      modelRoot.I modelRoot.h planeNode.I planeNode.h  \
-     projectionNode.I projectionNode.h renderTraverser.I  \
+     lensNode.I lensNode.h renderTraverser.I  \
      renderTraverser.h switchNode.I switchNode.h  
 
   #define INCLUDED_SOURCES  \
      camera.cxx config_sgraph.cxx geomNode.cxx geomTransformer.cxx  \
-     modelNode.cxx modelRoot.cxx planeNode.cxx projectionNode.cxx  \
+     modelNode.cxx modelRoot.cxx planeNode.cxx lensNode.cxx  \
      renderTraverser.cxx switchNode.cxx 
 
   #define INSTALL_HEADERS \
     camera.I camera.h config_sgraph.h \
     geomNode.I geomNode.h geomTransformer.I \
     geomTransformer.h modelNode.I modelNode.h modelRoot.I \
-    modelRoot.h planeNode.I planeNode.h projectionNode.I \
-    projectionNode.h renderTraverser.I renderTraverser.h \
+    modelRoot.h planeNode.I planeNode.h lensNode.I \
+    lensNode.h renderTraverser.I renderTraverser.h \
     switchNode.I switchNode.h
 
   #define IGATESCAN all

+ 6 - 104
panda/src/sgraph/camera.cxx

@@ -15,17 +15,12 @@
 // [email protected] .
 //
 ////////////////////////////////////////////////////////////////////
-#include <pandabase.h>
+#include "pandabase.h"
 #include "camera.h"
-#include <projection.h>
-#include <throw_event.h>
+#include "lens.h"
+#include "throw_event.h"
 
-
-////////////////////////////////////////////////////////////////////
-// Static variables
-////////////////////////////////////////////////////////////////////
 TypeHandle Camera::_type_handle;
-const std::string Camera::_CHANGE_CAM = "CamChange";
 
 
 ////////////////////////////////////////////////////////////////////
@@ -35,7 +30,7 @@ const std::string Camera::_CHANGE_CAM = "CamChange";
 ////////////////////////////////////////////////////////////////////
 Camera::
 Camera(const string &name) :
-  ProjectionNode(name),
+  LensNode(name),
   _active(true)
 {
 }
@@ -47,7 +42,7 @@ Camera(const string &name) :
 ////////////////////////////////////////////////////////////////////
 Camera::
 Camera(const Camera &copy) :
-  ProjectionNode(copy),
+  LensNode(copy),
   _active(copy._active),
   _scene(copy._scene)
 {
@@ -60,7 +55,7 @@ Camera(const Camera &copy) :
 ////////////////////////////////////////////////////////////////////
 void Camera::
 operator = (const Camera &copy) {
-  ProjectionNode::operator = (copy);
+  LensNode::operator = (copy);
   _active = copy._active;
   _scene = copy._scene;
 }
@@ -171,96 +166,3 @@ remove_display_region(DisplayRegion *display_region) {
     _display_regions.erase(dri);
   }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: Camera::set_*
-//       Access: Public
-//  Description: Overrides projection matrix functions.  The intention
-//               is to throw a camera update event for recalculation
-//               of various parameters used by Direct, rather than
-//               recalculating everything every frame "just in case".
-//               When fully implemented, there will be more specific
-//               information for each event, e.g. 
-//               throw_event(_CHANGE_FOV, get_name(), hfov, vfov)
-////////////////////////////////////////////////////////////////////
-void Camera::
-set_projection(const Projection &projection) {
-        ProjectionNode::set_projection(projection);
-        if(has_name()) {
-          throw_event(_CHANGE_CAM,get_name());
-        }
-        else
-          throw_event(_CHANGE_CAM,std::string(""));
-}
-
-void Camera::
-set_fov(float hfov) {
-        ProjectionNode::set_fov(hfov);
-        if(has_name())
-          throw_event(_CHANGE_CAM,get_name());
-        else
-          throw_event(_CHANGE_CAM,std::string(""));
-}
-
-void Camera::
-set_fov(float hfov, float vfov) {
-        ProjectionNode::set_fov(hfov, vfov);
-        if(has_name())
-          throw_event(_CHANGE_CAM,get_name());
-        else
-          throw_event(_CHANGE_CAM,std::string(""));
-}
-
-void Camera::
-set_hfov(float hfov) {
-        ProjectionNode::set_hfov(hfov);
-        if(has_name())
-          throw_event(_CHANGE_CAM,get_name());
-        else
-          throw_event(_CHANGE_CAM,std::string(""));
-}
-
-void Camera::
-set_vfov(float vfov) {
-        ProjectionNode::set_vfov(vfov);
-        if(has_name())
-          throw_event(_CHANGE_CAM,get_name());
-        else
-          throw_event(_CHANGE_CAM,std::string(""));
-}
-
-void Camera::
-set_aspect(float aspect) {
-        ProjectionNode::set_aspect(aspect);
-        if(has_name())
-          throw_event(_CHANGE_CAM,get_name());
-        else
-          throw_event(_CHANGE_CAM,std::string(""));
-}
-
-void Camera::
-set_near_far(float cnear, float cfar) {
-        ProjectionNode::set_near_far(cnear,cfar);
-        if(has_name())
-          throw_event(_CHANGE_CAM,get_name());
-        else
-          throw_event(_CHANGE_CAM,std::string(""));
-}
-
-void Camera::
-set_near(float cnear) {
-        ProjectionNode::set_near(cnear);
-        if(has_name())
-          throw_event(_CHANGE_CAM,get_name());
-        else
-          throw_event(_CHANGE_CAM,std::string(""));
-}
-
-void Camera::
-set_far(float cfar) {
-        ProjectionNode::set_far(cfar);
-        if(has_name())
-          throw_event(_CHANGE_CAM,get_name());
-        else
-          throw_event(_CHANGE_CAM,std::string(""));
-}

+ 6 - 22
panda/src/sgraph/camera.h

@@ -21,24 +21,19 @@
 ////////////////////////////////////////////////////////////////////
 // Includes
 ////////////////////////////////////////////////////////////////////
-#include <pandabase.h>
-
-#include "projectionNode.h"
-
-#include <pt_Node.h>
+#include "pandabase.h"
 
+#include "lensNode.h"
+#include "pt_Node.h"
 #include "pvector.h"
 
-////////////////////////////////////////////////////////////////////
-// Defines
-////////////////////////////////////////////////////////////////////
 class DisplayRegion;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : Camera
 // Description :
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA Camera : public ProjectionNode {
+class EXPCL_PANDA Camera : public LensNode {
 PUBLISHED:
   Camera(const string &name = "");
 
@@ -64,17 +59,6 @@ PUBLISHED:
   int get_num_drs() const;
   DisplayRegion *get_dr(int index) const;
 
-  void set_projection(const Projection &projection);
-
-  void set_fov(float hfov);
-  void set_fov(float hfov, float vfov);
-  void set_hfov(float hfov);
-  void set_vfov(float vfov);
-  void set_aspect(float aspect);
-  void set_near_far(float cnear, float cfar);
-  void set_near(float cnear);
-  void set_far(float cfar);
-
 private:
   void add_display_region(DisplayRegion *display_region);
   void remove_display_region(DisplayRegion *display_region);
@@ -92,9 +76,9 @@ public:
     return _type_handle;
   }
   static void init_type() {
-    ProjectionNode::init_type();
+    LensNode::init_type();
     register_type(_type_handle, "Camera",
-                  ProjectionNode::get_class_type());
+                  LensNode::get_class_type());
   }
   virtual TypeHandle get_type() const {
     return get_class_type();

+ 2 - 2
panda/src/sgraph/config_sgraph.cxx

@@ -23,7 +23,7 @@
 #include "planeNode.h"
 #include "modelNode.h"
 #include "modelRoot.h"
-#include "projectionNode.h"
+#include "lensNode.h"
 #include "switchNode.h"
 
 #include <dconfig.h>
@@ -60,7 +60,7 @@ init_libsgraph() {
   PlaneNode::init_type();
   ModelNode::init_type();
   ModelRoot::init_type();
-  ProjectionNode::init_type();
+  LensNode::init_type();
   SwitchNode::init_type();
 
   //Registration of writeable object's creation

+ 1 - 1
panda/src/sgraph/geomTransformer.cxx

@@ -56,7 +56,7 @@ transform_vertices(Geom *geom, const LMatrix4f &mat) {
 
   geom->get_coords(coords, index);
 
-  if (coords != NULL) {
+  if (!coords.empty()) {
     // Look up the Geom's coords in our table--have we already
     // transformed this array?
     SourceVertices sv;

+ 88 - 0
panda/src/sgraph/lensNode.I

@@ -0,0 +1,88 @@
+// Filename: lensNode.I
+// Created by:  drose (23May00)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////
+//     Function: LensNode::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE LensNode::
+LensNode(const string &name) :
+  NamedNode(name)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LensNode::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE LensNode::
+LensNode(const LensNode &copy) :
+  NamedNode(copy),
+  _lens(copy._lens)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LensNode::Copy Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void LensNode::
+operator = (const LensNode &copy) {
+  NamedNode::operator = (copy);
+  _lens = copy._lens;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: copy_lens
+//       Access: Public
+//  Description: Sets up the LensNode using a copy of the
+//               indicated Lens.  If the original Lens is
+//               changed or destroyed, this LensNode is not
+//               affected.
+////////////////////////////////////////////////////////////////////
+INLINE void LensNode::
+copy_lens(const Lens &lens) {
+  _lens = lens.make_copy();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: set_lens
+//       Access: Public
+//  Description: Sets up the LensNode using this particular Lens
+//               pointer.  If the lens is subsequently modified, the
+//               LensNode properties immediately reflect the change.
+////////////////////////////////////////////////////////////////////
+INLINE void LensNode::
+set_lens(Lens *lens) {
+  _lens = lens;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: get_lens
+//       Access: Public
+//  Description: Returns a pointer to the particular Lens
+//               associated with this LensNode, or NULL if there is
+//               not yet a Lens associated.
+////////////////////////////////////////////////////////////////////
+INLINE Lens *LensNode::
+get_lens() {
+  return _lens;
+}

+ 85 - 0
panda/src/sgraph/lensNode.cxx

@@ -0,0 +1,85 @@
+// Filename: lensNode.cxx
+// Created by:  mike (09Jan97)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+#include "lensNode.h"
+#include "geometricBoundingVolume.h"
+
+#include <algorithm>
+
+////////////////////////////////////////////////////////////////////
+// Static variables
+////////////////////////////////////////////////////////////////////
+TypeHandle LensNode::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: LensNode::make_copy
+//       Access: Public, Virtual
+//  Description: Returns a newly-allocated Node that is a shallow copy
+//               of this one.  It will be a different Node pointer,
+//               but its internal data may or may not be shared with
+//               that of the original Node.
+////////////////////////////////////////////////////////////////////
+Node *LensNode::
+make_copy() const {
+  return new LensNode(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LensNode::is_in_view
+//       Access: Public
+//  Description: Returns true if the given point is within the bounds
+//               of the lens of the LensNode (i.e. if the camera can
+//               see the point).
+////////////////////////////////////////////////////////////////////
+bool LensNode::
+is_in_view(const LPoint3f &pos) {
+  PT(BoundingVolume) bv = _lens->make_bounds();
+  if (bv == NULL)
+    return false;
+  GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bv);
+  int ret = gbv->contains(pos);
+  return (ret != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LensNode::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void LensNode::
+output(ostream &out) const {
+  NamedNode::output(out);
+  if (_lens != (Lens *)NULL) {
+    out << " (";
+    _lens->output(out);
+    out << ")";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LensNode::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void LensNode::
+write(ostream &out, int indent_level) const {
+  NamedNode::write(out, indent_level);
+  if (_lens != (Lens *)NULL) {
+    _lens->write(out, indent_level + 2);
+  }
+}
+

+ 80 - 0
panda/src/sgraph/lensNode.h

@@ -0,0 +1,80 @@
+// Filename: lensNode.h
+// Created by:  mike (09Jan97)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+#ifndef LENSNODE_H
+#define LENSNODE_H
+//
+////////////////////////////////////////////////////////////////////
+// Includes
+////////////////////////////////////////////////////////////////////
+#include "pandabase.h"
+
+#include "namedNode.h"
+#include "lens.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : LensNode
+// Description : A node that contains a Lens.  The most important
+//               example of this kind of node is a Camera, but other
+//               kinds of nodes also contain a lens (for instance, a
+//               Spotlight).
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA LensNode : public NamedNode {
+PUBLISHED:
+  INLINE LensNode(const string &name = "");
+
+public:
+  INLINE LensNode(const LensNode &copy);
+  INLINE void operator = (const LensNode &copy);
+
+  virtual void output(ostream &out) const;
+  virtual void write(ostream &out, int indent_level = 0) const;
+
+  virtual Node *make_copy() const;
+
+PUBLISHED:
+  INLINE void copy_lens(const Lens &lens);
+  INLINE void set_lens(Lens *lens);
+  INLINE Lens *get_lens();
+
+  bool is_in_view(const LPoint3f &pos);
+
+protected:
+  PT(Lens) _lens;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    NamedNode::init_type();
+    register_type( _type_handle, "LensNode",
+                   NamedNode::get_class_type() );
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+
+  static TypeHandle                       _type_handle;
+};
+
+#include "lensNode.I"
+
+#endif

+ 0 - 367
panda/src/sgraph/projectionNode.cxx

@@ -1,367 +0,0 @@
-// Filename: projectionNode.cxx
-// Created by:  mike (09Jan97)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://www.panda3d.org/license.txt .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-#include "projectionNode.h"
-#include <frustum.h>
-#include <perspectiveProjection.h>
-#include <geometricBoundingVolume.h>
-
-#include <algorithm>
-
-////////////////////////////////////////////////////////////////////
-// Static variables
-////////////////////////////////////////////////////////////////////
-TypeHandle ProjectionNode::_type_handle;
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::make_copy
-//       Access: Public, Virtual
-//  Description: Returns a newly-allocated Node that is a shallow copy
-//               of this one.  It will be a different Node pointer,
-//               but its internal data may or may not be shared with
-//               that of the original Node.
-////////////////////////////////////////////////////////////////////
-Node *ProjectionNode::
-make_copy() const {
-  return new ProjectionNode(*this);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: set_projection
-//       Access: Public
-//  Description: Sets up the ProjectionNode using a copy of the
-//               indicated Projection.  If the original Projection is
-//               changed or destroyed, this ProjectionNode is not
-//               affected.
-////////////////////////////////////////////////////////////////////
-void ProjectionNode::
-set_projection(const Projection &projection) {
-  _projection = projection.make_copy();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: share_projection
-//       Access: Public
-//  Description: This is similar to set_projection(), but the
-//               Projection is assigned by pointer.  If the original
-//               Projection is changed, this ProjectionNode is
-//               immediately affected.
-////////////////////////////////////////////////////////////////////
-void ProjectionNode::
-share_projection(Projection *projection) {
-  _projection = projection;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: get_projection
-//       Access: Public
-//  Description: Returns a pointer to the particular Projection
-//               associated with this ProjectionNode.
-////////////////////////////////////////////////////////////////////
-Projection *ProjectionNode::
-get_projection() {
-  if (_projection == (Projection *)NULL) {
-    // If we have no projection yet, give us a default Projection.
-    Frustumf f;
-    _projection = new PerspectiveProjection(f);
-  }
-
-  return _projection;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::is_in_view
-//       Access: Public
-//  Description: Returns true if the given point is within the bounds
-//               of the projection of the ProjectionNode (i.e. if the
-//               camera can see the point).
-////////////////////////////////////////////////////////////////////
-bool ProjectionNode::
-is_in_view(const LPoint3f &pos) {
-  BoundingVolume *bv = _projection->make_bounds();
-  if (bv == NULL)
-    return false;
-  GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bv);
-  int ret = gbv->contains(pos);
-  delete bv;
-  return (ret != 0);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::get_perspective_params
-//       Access: Public
-//  Description: Gets the viewing parameters of the ProjectionNode,
-//               assuming it represents a perspective frustum.
-////////////////////////////////////////////////////////////////////
-void ProjectionNode::
-get_perspective_params(float &yfov, float &aspect, float &cnear,
-                       float &cfar) const {
-  if (_projection->get_type() == PerspectiveProjection::get_class_type()) {
-    PerspectiveProjection *proj = DCAST(PerspectiveProjection, _projection);
-    proj->get_frustum().get_perspective_params(yfov, aspect, cnear, cfar);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::get_perspective_params
-//       Access: Public
-//  Description: Gets the viewing parameters of the ProjectionNode,
-//               assuming it represents a perspective frustum.
-////////////////////////////////////////////////////////////////////
-void ProjectionNode::
-get_perspective_params(float &xfov, float &yfov, float &aspect, float &cnear,
-                       float &cfar) const {
-  if (_projection->get_type() == PerspectiveProjection::get_class_type()) {
-    PerspectiveProjection *proj = DCAST(PerspectiveProjection, _projection);
-    proj->get_frustum().get_perspective_params(xfov, yfov, aspect, cnear,
-                                               cfar);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::get_hfov
-//       Access: Public
-//  Description: Gets the horizontal field of view of the
-//               ProjectionNode, assuming it represents a perspective
-//               frustum.
-////////////////////////////////////////////////////////////////////
-float ProjectionNode::
-get_hfov(void) const {
-  float xfov=0.0f, yfov=0.0f, aspect, cnear, cfar;
-  get_perspective_params(xfov, yfov, aspect, cnear, cfar);
-  return xfov;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::get_vfov
-//       Access: Public
-//  Description: Gets the vertical field of view of the
-//               ProjectionNode, assuming it represents a perspective
-//               frustum.
-////////////////////////////////////////////////////////////////////
-float ProjectionNode::
-get_vfov(void) const {
-  float xfov=0.0f, yfov=0.0f, aspect, cnear, cfar;
-  get_perspective_params(xfov, yfov, aspect, cnear, cfar);
-  return yfov;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::get_aspect
-//       Access: Public
-//  Description: Gets the aspect ratio of the horizontal field of view
-//               to the vertical field of view, assuming we have a
-//               perspective frustum.
-////////////////////////////////////////////////////////////////////
-float ProjectionNode::
-get_aspect(void) const {
-  float yfov, aspect=0.0f, cnear, cfar;
-  get_perspective_params(yfov, aspect, cnear, cfar);
-  return aspect;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::get_near_far
-//       Access: Public
-//  Description: Gets the near and far clipping planes, assuming we
-//               have a perspective frustum.
-////////////////////////////////////////////////////////////////////
-void ProjectionNode::
-get_near_far(float &cnear, float &cfar) const {
-  if (_projection->get_type() == PerspectiveProjection::get_class_type()) {
-    PerspectiveProjection *proj = DCAST(PerspectiveProjection, _projection);
-    Frustumf frust = proj->get_frustum();
-    cnear = frust._fnear;
-    cfar = frust._ffar;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::get_near
-//       Access: Public
-//  Description: Gets the near clipping plane, assuming we have a
-//               perspective frustum.
-////////////////////////////////////////////////////////////////////
-float ProjectionNode::
-get_near(void) const {
-  float cnear, cfar;
-  get_near_far(cnear, cfar);
-  return cnear;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::get_far
-//       Access: Public
-//  Description: Gets the far clipping plane, assuming we have a
-//               perspective frustum.
-////////////////////////////////////////////////////////////////////
-float ProjectionNode::
-get_far(void) const {
-  float cnear, cfar;
-  get_near_far(cnear, cfar);
-  return cfar;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::set_fov
-//       Access: Public
-//  Description: Sets the field-of-view of the ProjectionNode,
-//               assuming it represents a perspective frustum.
-////////////////////////////////////////////////////////////////////
-void ProjectionNode::
-set_fov(float hfov) {
-  if (_projection->get_type() == PerspectiveProjection::get_class_type()) {
-    PerspectiveProjection *proj = DCAST(PerspectiveProjection, _projection);
-    float tfov, ufov, aspect, cnear, cfar;
-    Frustumf frust = proj->get_frustum();
-    frust.get_perspective_params(tfov, ufov, aspect, cnear, cfar);
-    frust.make_perspective_hfov(hfov, aspect, cnear, cfar);
-    proj->set_frustum(frust);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::set_fov
-//       Access: Public
-//  Description: Sets the field-of-view of the ProjectionNode,
-//               assuming it represents a perspective frustum.
-////////////////////////////////////////////////////////////////////
-void ProjectionNode::
-set_fov(float hfov, float vfov) {
-  if (_projection->get_type() == PerspectiveProjection::get_class_type()) {
-    PerspectiveProjection *proj = DCAST(PerspectiveProjection, _projection);
-    float tfov, ufov, aspect, cnear, cfar;
-    Frustumf frust = proj->get_frustum();
-    frust.get_perspective_params(tfov, ufov, aspect, cnear, cfar);
-    frust.make_perspective(hfov, vfov, cnear, cfar);
-    proj->set_frustum(frust);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::set_hfov
-//       Access: Public
-//  Description: Sets the horizontal field-of-view of the ProjectionNode,
-//               assuming it represents a perspective frustum.
-////////////////////////////////////////////////////////////////////
-void ProjectionNode::
-set_hfov(float hfov) {
-  if (_projection->get_type() == PerspectiveProjection::get_class_type()) {
-    PerspectiveProjection *proj = DCAST(PerspectiveProjection, _projection);
-    float tfov, ufov, aspect, cnear, cfar;
-    Frustumf frust = proj->get_frustum();
-    frust.get_perspective_params(tfov, ufov, aspect, cnear, cfar);
-    frust.make_perspective(hfov, ufov, cnear, cfar);
-    proj->set_frustum(frust);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::set_vfov
-//       Access: Public
-//  Description: Sets the vertical field-of-view of the ProjectionNode,
-//               assuming it represents a perspective frustum.
-////////////////////////////////////////////////////////////////////
-void ProjectionNode::
-set_vfov(float vfov) {
-  if (_projection->get_type() == PerspectiveProjection::get_class_type()) {
-    PerspectiveProjection *proj = DCAST(PerspectiveProjection, _projection);
-    float tfov, ufov, aspect, cnear, cfar;
-    Frustumf frust = proj->get_frustum();
-    frust.get_perspective_params(tfov, ufov, aspect, cnear, cfar);
-    frust.make_perspective(tfov, vfov, cnear, cfar);
-    proj->set_frustum(frust);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::set_aspect
-//       Access: Public
-//  Description: Sets the aspect ratio of the ProjectionNode,
-//               assuming it represents a perspective frustum.
-////////////////////////////////////////////////////////////////////
-void ProjectionNode::
-set_aspect(float aspect) {
-  if (_projection->get_type() == PerspectiveProjection::get_class_type()) {
-    PerspectiveProjection *proj = DCAST(PerspectiveProjection, _projection);
-    float xfov, yfov, taspect, cnear, cfar;
-    Frustumf frust = proj->get_frustum();
-    frust.get_perspective_params(xfov, yfov, taspect, cnear, cfar);
-    // I don't know what to do when the aspect changes.  I have arbitrarilly
-    // decided to preserved the horizontal FoV.  The vertical will be
-    // recomputed based on the new aspect and the horizontal.
-    frust.make_perspective_hfov(xfov, aspect, cnear, cfar);
-    proj->set_frustum(frust);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::set_near_far
-//       Access: Public
-//  Description: Sets the near and far planes of the ProjectionNode,
-//               assuming it represents a perspective frustum.
-////////////////////////////////////////////////////////////////////
-void ProjectionNode::
-set_near_far(float cnear, float cfar) {
-  if (_projection->get_type() == PerspectiveProjection::get_class_type()) {
-    PerspectiveProjection *proj = DCAST(PerspectiveProjection, _projection);
-    float xfov, yfov, aspect, tnear, tfar;
-    Frustumf frust = proj->get_frustum();
-    frust.get_perspective_params(xfov, yfov, aspect, tnear, tfar);
-    frust.make_perspective(xfov, yfov, cnear, cfar);
-    proj->set_frustum(frust);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::set_near
-//       Access: Public
-//  Description: Sets the near clipping plane of the ProjectionNode,
-//               assuming it represents a perspective frustum.
-////////////////////////////////////////////////////////////////////
-void ProjectionNode::
-set_near(float cnear) {
-  float cfar = get_far();
-  set_near_far(cnear, cfar);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ProjectionNode::set_far
-//       Access: Public
-//  Description: Sets the far clipping plane of the ProjectionNode,
-//               assuming it represents a perspective frustum.
-////////////////////////////////////////////////////////////////////
-void ProjectionNode::
-set_far(float cfar) {
-  float cnear = get_near();
-  set_near_far(cnear, cfar);
-}
-
-void ProjectionNode::
-output(ostream &out) const {
-  if (_projection->get_type() == PerspectiveProjection::get_class_type()) {
-    PerspectiveProjection *proj = DCAST(PerspectiveProjection, _projection);
-    float xfov,yfov,aspect_ratio,cnear,cfar;
-    proj->get_frustum().get_perspective_params(xfov, yfov, aspect_ratio, cnear, cfar);
-
-    out << "X-FOV: " << xfov << " deg, Y-FOV: " << yfov << " deg" 
-        << "Aspect ratio: " << aspect_ratio << ", Near plane: " << cnear << ", Far plane: " << cfar << endl;
-  }
-
-  out << "Projection Matrix: " << _projection->get_projection_mat(CS_default) << endl;
-}
-

+ 0 - 97
panda/src/sgraph/projectionNode.h

@@ -1,97 +0,0 @@
-// Filename: projectionNode.h
-// Created by:  mike (09Jan97)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://www.panda3d.org/license.txt .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-#ifndef PROJECTIONNODE_H
-#define PROJECTIONNODE_H
-//
-////////////////////////////////////////////////////////////////////
-// Includes
-////////////////////////////////////////////////////////////////////
-#include <pandabase.h>
-
-#include <namedNode.h>
-#include <projection.h>
-
-////////////////////////////////////////////////////////////////////
-// Defines
-////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////
-//       Class : ProjectionNode
-// Description : A node that has a frustum
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA ProjectionNode : public NamedNode {
-PUBLISHED:
-  INLINE ProjectionNode(const string &name = "");
-
-public:
-  INLINE ProjectionNode(const ProjectionNode &copy);
-  INLINE void operator = (const ProjectionNode &copy);
-  void output(ostream &out) const;
-  virtual Node *make_copy() const;
-
-PUBLISHED:
-  void set_projection(const Projection &projection);
-  void share_projection(Projection *projection);
-  Projection *get_projection();
-
-  bool is_in_view(const LPoint3f &pos);
-
-  void get_perspective_params(float &yfov, float &aspect, float &cnear,
-                              float &cfar) const;
-  void get_perspective_params(float &xfov, float &yfov, float &aspect,
-                              float &cnear, float &cfar) const;
-  float get_hfov(void) const;
-  float get_vfov(void) const;
-  void set_fov(float hfov);
-  void set_fov(float hfov, float vfov);
-  void set_hfov(float hfov);
-  void set_vfov(float vfov);
-  float get_aspect(void) const;
-  void set_aspect(float aspect);
-  void get_near_far(float &cnear, float &cfar) const;
-  void set_near_far(float cnear, float cfar);
-  float get_near(void) const;
-  void set_near(float cnear);
-  float get_far(void) const;
-  void set_far(float cfar);
-
-protected:
-  PT(Projection) _projection;
-
-public:
-  static TypeHandle get_class_type( void ) {
-    return _type_handle;
-  }
-  static void init_type( void ) {
-    NamedNode::init_type();
-    register_type( _type_handle, "ProjectionNode",
-                   NamedNode::get_class_type() );
-  }
-  virtual TypeHandle get_type( void ) const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-private:
-
-  static TypeHandle                       _type_handle;
-};
-
-#include "projectionNode.I"
-
-#endif

+ 1 - 1
panda/src/sgraph/sgraph_composite2.cxx

@@ -1,7 +1,7 @@
 
 #include "config_sgraph.cxx"
 #include "camera.cxx"
-#include "projectionNode.cxx"
+#include "lensNode.cxx"
 #include "renderTraverser.cxx"
 #include "switchNode.cxx"
 

+ 3 - 3
panda/src/sgraphutil/directRenderTraverser.cxx

@@ -26,8 +26,8 @@
 #include <graphicsStateGuardian.h>
 #include <displayRegion.h>
 #include <geometricBoundingVolume.h>
-#include <projectionNode.h>
-#include <projection.h>
+#include <lensNode.h>
+#include <lens.h>
 #include <colorTransition.h>
 #include <renderModeTransition.h>
 #include <textureTransition.h>
@@ -101,7 +101,7 @@ traverse(Node *root,
     LMatrix4f rel_from_camera;
     NodeTransitionWrapper ntw(TransformTransition::get_class_type());
     const DisplayRegion *dr = _gsg->get_current_display_region();
-    ProjectionNode *camera = dr->get_cull_frustum();
+    LensNode *camera = dr->get_cull_frustum();
     wrt(camera, root, begin(), end(), ntw, get_graph_type());
     const TransformTransition *tt;
     if (get_transition_into(tt, ntw)) {

+ 21 - 20
panda/src/sgraphutil/frustumCullTraverser.I

@@ -48,29 +48,30 @@ FrustumCullTraverser(ArcChain &arc_chain, Node *root,
     // DisplayRegion may have some override in effect, so we ask the
     // DisplayRegion instead of the GSG.
     const DisplayRegion *dr = _gsg->get_current_display_region();
-    ProjectionNode *camera = dr->get_cull_frustum();
-    if (camera != (const ProjectionNode *)NULL) {
-      const Projection *proj = camera->get_projection();
-      nassertv(proj != (const Projection *)NULL);
-      BoundingVolume *bv = proj->make_bounds();
-
-      if (bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
+    LensNode *camera = dr->get_cull_frustum();
+    if (camera != (const LensNode *)NULL) {
+      const Lens *lens = camera->get_lens();
+      nassertv(lens != (const Lens *)NULL);
+      PT(BoundingVolume) bv = lens->make_bounds();
+
+      if (bv != (BoundingVolume *)NULL &&
+          bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
         _view_frustum = DCAST(GeometricBoundingVolume, bv);
-      } else {
-        delete bv;
       }
     }
 
-    local_frustum = DCAST(GeometricBoundingVolume, _view_frustum->make_copy());
-    local_frustum->xform(rel_from_camera);
-    GraphicsStateGuardian::_frustum_cull_volumes_pcollector.add_level(1);
-    GraphicsStateGuardian::_frustum_cull_transforms_pcollector.add_level(1);
-
-    if (sgraphutil_cat.is_spam()) {
-      sgraphutil_cat.spam()
-        << "Beginning frustum cull, frustum is: " << *local_frustum << "\n"
-        << "Transform is:\n";
-      rel_from_camera.write(sgraphutil_cat.spam(false), 2);
+    if (_view_frustum != (GeometricBoundingVolume *)NULL) {
+      local_frustum = DCAST(GeometricBoundingVolume, _view_frustum->make_copy());
+      local_frustum->xform(rel_from_camera);
+      GraphicsStateGuardian::_frustum_cull_volumes_pcollector.add_level(1);
+      GraphicsStateGuardian::_frustum_cull_transforms_pcollector.add_level(1);
+      
+      if (sgraphutil_cat.is_spam()) {
+        sgraphutil_cat.spam()
+          << "Beginning frustum cull, frustum is: " << *local_frustum << "\n"
+          << "Transform is:\n";
+        rel_from_camera.write(sgraphutil_cat.spam(false), 2);
+      }
     }
   }
 
@@ -202,7 +203,7 @@ traverse(NodeRelation *arc, TransitionWrapper render_state,
 
           NodeTransitionWrapper ntw(TransformTransition::get_class_type());
           const DisplayRegion *dr = _gsg->get_current_display_region();
-          ProjectionNode *camera = dr->get_cull_frustum();
+          LensNode *camera = dr->get_cull_frustum();
           wrt(camera,
               arc->get_child(), _arc_chain.begin(), _arc_chain.end(),
               ntw, _graph_type);

+ 3 - 3
panda/src/shader/shader.I

@@ -36,7 +36,7 @@ set_viz(Shader::Visualize* v) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE int FrustumShader::
-add_frustum(ProjectionNode* frust) {
+add_frustum(LensNode* frust) {
   make_dirty();
   _frusta.push_back(frust);
   return (_frusta.size());
@@ -48,9 +48,9 @@ add_frustum(ProjectionNode* frust) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE int FrustumShader::
-remove_frustum(ProjectionNode* frust) {
+remove_frustum(LensNode* frust) {
   make_dirty();
-  ProjectionVector::iterator i;
+  LensVector::iterator i;
   for (i = _frusta.begin(); i != _frusta.end(); ++i) {
     if ((*i) == frust) {
       _frusta.erase(i);

+ 5 - 5
panda/src/shader/shader.h

@@ -25,7 +25,7 @@
 
 #include <configurable.h>
 #include <namedNode.h>
-#include <projectionNode.h>
+#include <lensNode.h>
 #include <typedReferenceCount.h>
 #include <graphicsStateGuardian.h>
 #include <allAttributesWrapper.h>
@@ -120,14 +120,14 @@ public:
   virtual ~FrustumShader(void) { }
 
   INLINE int get_num_frusta(void) const { return _frusta.size(); }
-  INLINE int add_frustum(ProjectionNode* frust);
-  INLINE int remove_frustum(ProjectionNode* frust);
+  INLINE int add_frustum(LensNode* frust);
+  INLINE int remove_frustum(LensNode* frust);
 
-  typedef pvector<ProjectionNode *> ProjectionVector;
+  typedef pvector<LensNode *> LensVector;
 
 protected:
 
-  ProjectionVector                      _frusta;
+  LensVector                      _frusta;
 
 public:
 

+ 1 - 1
panda/src/shader/spheretexHighlighter.cxx

@@ -122,7 +122,7 @@ pre_apply(Node *node, const AllAttributesWrapper &init_state,
 
   // Figure out where the highlight is relative to the object's center and
   // the light
-  const ProjectionNode* projnode = gsg->get_current_projection_node();
+  const LensNode* projnode = gsg->get_current_camera();
   LVector3f model_pos = get_rel_pos(node, projnode);
   LVector3f norm_model_pos = normalize(model_pos);
   LPoint3f light_pos = get_rel_pos(light, projnode);

+ 11 - 10
panda/src/shader/spheretexReflector.cxx

@@ -25,7 +25,7 @@
 #include <displayRegion.h>
 #include <graphicsWindow.h>
 #include <renderBuffer.h>
-#include <perspectiveProjection.h>
+#include <perspectiveLens.h>
 #include <look_at.h>
 #include <compose_matrix.h>
 #include <cullFaceTransition.h>
@@ -116,7 +116,7 @@ pre_apply(Node *node, const AllAttributesWrapper &init_state,
   state.clear_attribute(TransformTransition::get_class_type());
 
   // Get the current camera from the gsg
-  const ProjectionNode* camera = gsg->get_current_projection_node();
+  const LensNode* camera = gsg->get_current_camera();
 
   // Save the clear color.
   Colorf clear_color = gsg->get_color_clear_value();
@@ -158,15 +158,16 @@ pre_apply(Node *node, const AllAttributesWrapper &init_state,
     arc->set_transition(new TransformTransition(mat));
   }
 
-  // Build a ProjectionNode that represents a wide-angle view from the
+  // Build a LensNode that represents a wide-angle view from the
   // reflecting object towards the camera.
-  Frustumf frust;
-  frust.make_perspective_hfov(150.0f, 1.0f, _fnear, _ffar);
-  PerspectiveProjection projection(frust);
-  ProjectionNode* projnode = new ProjectionNode;
-  projnode->set_projection(projection);
-
-  // How shall we rotate the ProjectionNode?
+  PT(Lens) *lens = new PerspectiveLens;
+  lens->set_fov(150.0f);
+  lens->set_near(_fnear);
+  lens->set_far(_ffar);
+  LensNode *projnode = new LensNode;
+  projnode->set_lens(lens);
+
+  // How shall we rotate the LensNode?
   LMatrix4f r_mat;
 
   // Get camera pos in the coordinate space of the reflecting object

+ 3 - 3
panda/src/switchnode/LODNode.cxx

@@ -16,7 +16,7 @@
 //
 ////////////////////////////////////////////////////////////////////
 #include "LODNode.h"
-#include "projectionNode.h"
+#include "lensNode.h"
 #include "config_switchnode.h"
 
 #include "graphicsStateGuardian.h"
@@ -92,8 +92,8 @@ compute_switch(RenderTraverser *trav) {
   // DisplayRegion may have some override in effect, so we ask the
   // DisplayRegion instead of the GSG.
   const DisplayRegion *dr = gsg->get_current_display_region();
-  ProjectionNode *camera = dr->get_cull_frustum();
-  if (camera != (ProjectionNode *)NULL) {
+  LensNode *camera = dr->get_cull_frustum();
+  if (camera != (LensNode *)NULL) {
     LPoint3f camera_pos(0, 0, 0);
 
     // Get the LOD center in camera space

+ 0 - 117
panda/src/testbed/demo.cxx

@@ -44,8 +44,6 @@
 #include "renderRelation.h"
 #include "camera.h"
 #include "frustum.h"
-#include "orthoProjection.h"
-#include "perspectiveProjection.h"
 #include "textNode.h"
 #include "colorMatrixTransition.h"
 #include "alphaTransformTransition.h"
@@ -102,121 +100,6 @@ RenderRelation *sky_arc = (RenderRelation *)NULL;
 RenderRelation *flare_arc = (RenderRelation *)NULL;
 
 
-/*
-void
-setup_panda2d() {
-  static bool already_setup = false;
-  if (already_setup) {
-    nout << "Already have 2-d layer set up.\n";
-    return;
-  }
-  already_setup = true;
-  nout << "Setting up 2-d layer.\n";
-
-  render2d_top = new NamedNode("render2d_top");
-  render2d = new NamedNode("render2d");
-  render2d_arc = new RenderRelation(render2d_top, render2d);
-
-  // Set up some overrides to turn off certain properties which we
-  // probably won't need for 2-d objects.
-  render2d_arc->set_transition(new DepthTestTransition(DepthTestProperty::M_none), 1);
-  render2d_arc->set_transition(new DepthWriteTransition(DepthWriteTransition::off()), 1);
-  render2d_arc->set_transition(new LightTransition(LightTransition::all_off()), 1);
-  render2d_arc->set_transition(new MaterialTransition(MaterialTransition::off()), 1);
-  render2d_arc->set_transition(new CullFaceTransition(CullFaceProperty::M_cull_none), 1);
-
-  // Create a 2-d camera.
-  PT(Camera) cam2d = new Camera("cam2d");
-  new RenderRelation(render2d, cam2d);
-  cam2d->set_scene(render2d_top);
-
-  Frustumf frustum2d;
-  frustum2d.make_ortho_2D();
-  cam2d->set_projection(OrthoProjection(frustum2d));
-
-  // Now create a new layer.
-  GraphicsChannel *chan = main_win->get_channel(0);
-  nassertv(chan != (GraphicsChannel *)NULL);
-
-  GraphicsLayer *layer = chan->make_layer();
-  nassertv(layer != (GraphicsLayer *)NULL);
-
-  DisplayRegion *dr = layer->make_display_region();
-  nassertv(dr != (DisplayRegion *)NULL);
-  dr->set_camera(cam2d);
-
-
-  // Put some interesting things in the 2-d scene graph.
-  PT_Node font = loader.load_sync("ttf-comic");
-
-  if (font != (NamedNode *)NULL) {
-    label2d = new TextNode("label2d");
-    new RenderRelation(render2d, label2d);
-
-    LMatrix4f mat =
-      LMatrix4f::scale_mat(0.1) *
-      LMatrix4f::translate_mat(0.0, 0.0, 0.8);
-
-    label2d->set_transform(mat);
-    label2d->set_font(font.p());
-    label2d->set_card_color(0.5, 0.5, 0.5, 0.5);
-    label2d->set_card_as_margin(0.5, 0.5, 0.2, 0.2);
-    label2d->set_frame_color(1.0, 1.0, 1.0, 1.0);
-    label2d->set_frame_as_margin(0.5, 0.5, 0.2, 0.2);
-    label2d->set_align(TM_ALIGN_CENTER);
-    label2d->set_text_color(0.2, 0.5, 1.0, 1.0);
-    label2d->set_text("Now presenting Panda 2-D!");
-
-    MouseWatcherRegion *region =
-      new MouseWatcherRegion("label2d", label2d->get_card_transformed());
-    region->set_suppress_below(true);
-    mouse_watcher->add_region(region);
-
-  } else {
-    nout << "Couldn't load font ttf-comic\n";
-  }
-
-  PT_Node p2egg = loader.load_sync("panda2d");
-  if (p2egg != (NamedNode *)NULL) {
-    new RenderRelation(render2d, p2egg);
-  } else {
-    nout << "Couldn't find panda2d.egg\n";
-  }
-
-  // Load up a mouse cursor for fun.
-  PT_Node lilsmiley = loader.load_sync("lilsmiley");
-  if (lilsmiley != (NamedNode *)NULL) {
-    NamedNode *n2 = new NamedNode("cursor");
-    RenderRelation *s1_arc = new RenderRelation(render2d, n2);
-    RenderRelation *s2_arc = new RenderRelation(n2, lilsmiley);
-
-    // Make up a scale to make it 32x32 pixels (it starts out 1x1
-    // units).
-    LMatrix4f scale_mat = LMatrix4f::scale_mat(32.0 / main_win->get_width(), 1.0, 32.0 / main_win->get_height());
-    s2_arc->set_transition(new TransformTransition(scale_mat));
-    mouse_watcher->set_geometry(s1_arc);
-  } else {
-    nout << "Couldn't find lilsmiley.egg\n";
-  }
-}
-
-static void
-event_in_label2d(CPT_Event) {
-  // The mouse moved over the label.
-  nassertv(!label2d.is_null());
-
-  label2d->set_card_color(0.8, 0.2, 1.0, 1.0);
-}
-
-static void
-event_out_label2d(CPT_Event) {
-  // The mouse moved out from the label.
-  nassertv(!label2d.is_null());
-
-  label2d->set_card_color(0.5, 0.5, 0.5, 0.5);
-}
-*/
-
 static void
 clear_highlight() {
   if (selected_node.has_arcs()) {

+ 4 - 4
panda/src/testbed/herc.cxx

@@ -63,7 +63,7 @@ Configure(shader_test);
 
 ConfigureFn(shader_test) {}
 
-PT(ProjectionNode) tex_proj;
+PT(LensNode) tex_proj;
 PT(Trackball) tex_proj_trackball;
 PT(ProjtexShader) proj_shader;
 PT(ProjtexShadower) proj_shadow;
@@ -405,7 +405,7 @@ void herc_keys(EventHandler &eh) {
   tex->set_name("smiley.rgba");
 
   // Put the texture projector into the scene graph
-  tex_proj = new ProjectionNode("texture_projector");
+  tex_proj = new LensNode("texture_projector");
   RenderRelation* proj_arc = new RenderRelation(render, tex_proj);
 
   // Create a trackball to spin this around.
@@ -430,8 +430,8 @@ void herc_keys(EventHandler &eh) {
   proj_shader->add_frustum(tex_proj);
 
   // Create a wireframe representation of the texture projector frustum
-  GeomLine* proj_geom =
-        (GeomLine *)tex_proj->get_projection()->make_geometry();
+  PT(Geom) proj_geom =
+    tex_proj->get_lens()->make_geometry();
   proj_geom_node = new GeomNode("proj_geometry");
   proj_geom_node->add_geom(proj_geom);
 

+ 5 - 5
panda/src/testbed/min_herc.cxx

@@ -59,7 +59,7 @@
 //Math/Matrix/Vector/Transformation stuff
 #include <transform2sg.h>
 #include <look_at.h>
-#include <perspectiveProjection.h>
+#include <perspectiveLens.h>
 #include <get_rel_pos.h>
 
 //Control/IO
@@ -75,7 +75,7 @@ Configure(min_herc);
 ConfigureFn(min_herc) {
 }
 
-PT(ProjectionNode) tex_proj;
+PT(LensNode) tex_proj;
 PT(Trackball) tex_proj_trackball;
 PT(ProjtexShader) proj_shader;
 PT(ProjtexShadower) proj_shadow;
@@ -350,7 +350,7 @@ void herc_keys(EventHandler &eh) {
   tex->set_wrapv(Texture::WM_clamp);
 
   // Put the texture projector into the scene graph
-  tex_proj = new ProjectionNode("texture_projector");
+  tex_proj = new LensNode("texture_projector");
   RenderRelation* proj_arc = new RenderRelation(render, tex_proj);
 
   // Create a trackball to spin this around.
@@ -375,8 +375,8 @@ void herc_keys(EventHandler &eh) {
   proj_shader->add_frustum(tex_proj);
 
   // Create a wireframe representation of the texture projector frustum
-  GeomLine* proj_geom =
-        (GeomLine *)tex_proj->get_projection()->make_geometry();
+  PT(Geom) proj_geom =
+    tex_proj->get_lens()->make_geometry();
   proj_geom_node = new GeomNode("proj_geometry");
   proj_geom_node->add_geom(proj_geom);
 

+ 12 - 11
panda/src/testbed/min_shader.cxx

@@ -62,7 +62,7 @@
 //Math/Matrix/Vector/Transformation stuff
 #include <transform2sg.h>
 #include <look_at.h>
-#include <perspectiveProjection.h>
+#include <perspectiveLens.h>
 #include <geomLine.h>
 
 Configure(min_shader);
@@ -70,7 +70,7 @@ ConfigureFn(min_shader) {
 }
 
 //--------Projective texture stuff--------
-PT(ProjectionNode) tex_proj;
+PT(LensNode) tex_proj;
 PT(Trackball) tex_proj_trackball;
 PT(ProjtexShader) proj_shader;
 //--------Spotlight stuff-----------------
@@ -551,7 +551,7 @@ void setup_projtex(void)
   // Create a projected texture shader
 
   // Put the texture projector into the scene graph
-  tex_proj = new ProjectionNode("texture_projector");
+  tex_proj = new LensNode("texture_projector");
   RenderRelation* proj_arc = new RenderRelation(render, tex_proj);
 
   // Create a trackball to spin this around.
@@ -579,8 +579,8 @@ void setup_projtex(void)
 #define DISPLAY_TEXPROJFRUST
 #ifdef DISPLAY_TEXPROJFRUST
   // Display a wireframe representation of the texture projector frustum
-  GeomLine* proj_geom =
-        (GeomLine *)tex_proj->get_projection()->make_geometry();
+  PT(Geom) proj_geom =
+    tex_proj->get_lens()->make_geometry();
   GeomNode* proj_geom_node = new GeomNode("proj_geometry");
   proj_geom_node->add_geom(proj_geom);
   RenderRelation *prr = new RenderRelation(tex_proj, proj_geom_node);
@@ -599,10 +599,11 @@ void setup_spotlight(void)
   // Create a projected texture spotlight shader
   tex_proj_spot = new Spotlight("tex_proj_spotlight");
   //Push out the far clipping plane of the spotlight frustum
-  Frustumf f;
-  f.make_perspective(45.0f, 45.0f, f._fnear, 13);
-  PerspectiveProjection pp(f);
-  tex_proj_spot->set_projection(pp);
+  PT(Lens) lens = new PerspectiveLens;
+  lens->set_fov(45.0f);
+  lens->set_near(f._fnear);
+  lens->set_far(13.0f);
+  tex_proj_spot->set_lens(lens);
 
   spot_arc = new RenderRelation(render, tex_proj_spot, 10);
 
@@ -632,8 +633,8 @@ void setup_spotlight(void)
 #ifdef DISPLAY_TEXPROJSPOTFRUST
   // Display a wireframe representation of the spotlight frustum
   Colorf color_red(1., 0., 0., 1.);
-  GeomLine* frust_geom =
-        (GeomLine *)tex_proj_spot->get_projection()->make_geometry(color_red);
+  PT(Geom) frust_geom =
+    tex_proj_spot->get_lens()->make_geometry();
   GeomNode* frust_geom_node = new GeomNode("frustum_geometry");
   frust_geom_node->add_geom(frust_geom);
   RenderRelation *rr = new RenderRelation(tex_proj_spot, frust_geom_node);

+ 10 - 9
panda/src/testbed/panda.cxx

@@ -26,7 +26,7 @@
 #include <directionalLight.h>
 #include <renderRelation.h>
 #include <frustum.h>
-#include <perspectiveProjection.h>
+#include <perspectiveLens.h>
 #include <shaderTransition.h>
 #include <texture.h>
 #include <texturePool.h>
@@ -72,7 +72,7 @@ PT(RenderRelation) hide_ball_arc;
 bool follow_ball;
 PT(PlanarSlider) ball_slider;
 
-PT(ProjectionNode) tex_proj;
+PT(LensNode) tex_proj;
 PT(ProjtexShader) proj_shader;
 PT(GeomNode) proj_geom_node;
 PT(Trackball) tex_proj_trackball;
@@ -329,7 +329,7 @@ void setup_shaders(void) {
   // Projected texture shader
   Texture* tex = TexturePool::load_texture("smiley.rgba");
   assert(tex != (Texture*)0L);
-  tex_proj = new ProjectionNode("texture_projector");
+  tex_proj = new LensNode("texture_projector");
   RenderRelation* proj_arc = new RenderRelation(root, tex_proj);
   tex_proj_trackball = new Trackball("tex_proj_trackball");
   tex_proj_trackball->set_invert(false);
@@ -346,8 +346,8 @@ void setup_shaders(void) {
   proj_arc->set_transition(new TransformTransition(proj_mat));
   proj_shader = new ProjtexShader(tex);
   proj_shader->add_frustum(tex_proj);
-  GeomLine* proj_geom =
-    (GeomLine *)tex_proj->get_projection()->make_geometry();
+  PT(Geom) proj_geom =
+    tex_proj->get_lens()->make_geometry();
   proj_geom_node = new GeomNode("proj_geometry");
   proj_geom_node->add_geom(proj_geom);
   proj_shader->set_priority(150);
@@ -356,10 +356,11 @@ void setup_shaders(void) {
 
   // projected texture spotlight shader
   tex_proj_spot = new Spotlight("tex_proj_spotlight");
-  Frustumf f;
-  f.make_perspective(45.0f, 45.0f, f._fnear, 13);
-  PerspectiveProjection pp(f);
-  tex_proj_spot->set_projection(pp);
+  PT(Lens) lens = new PerspectiveLens;
+  lens->set_fov(45.0f);
+  lens->set_near(f._fnear);
+  lens->set_far(13.0f);
+  tex_proj_spot->set_lens(lens);
   RenderRelation* spot_arc = new RenderRelation(root, tex_proj_spot, 10);
   tex_spot_trackball = new Trackball("tex_spot_trackball");
   tex_spot_trackball->set_invert(false);

+ 6 - 6
panda/src/testbed/shader_test.cxx

@@ -62,7 +62,7 @@ Configure(shader_test);
 ConfigureFn(shader_test) {
 }
 
-PT(ProjectionNode) tex_proj;
+PT(LensNode) tex_proj;
 PT(Trackball) tex_proj_trackball;
 PT(ProjtexShader) proj_shader;
 PT(ProjtexShadower) proj_shadow;
@@ -536,7 +536,7 @@ void shader_keys(EventHandler &eh) {
   tex->set_name("smiley.rgba");
 
   // Put the texture projector into the scene graph
-  tex_proj = new ProjectionNode("texture_projector");
+  tex_proj = new LensNode("texture_projector");
   RenderRelation* proj_arc = new RenderRelation(render, tex_proj);
 
   // Create a trackball to spin this around.
@@ -563,8 +563,8 @@ void shader_keys(EventHandler &eh) {
 #define DISPLAY_TEXPROJFRUST
 #ifdef DISPLAY_TEXPROJFRUST
   // Display a wireframe representation of the texture projector frustum
-  GeomLine* proj_geom =
-        (GeomLine *)tex_proj->get_projection()->make_geometry();
+  PT(Geom) proj_geom =
+        tex_proj->get_lens()->make_geometry();
   GeomNode* proj_geom_node = new GeomNode("proj_geometry");
   //JMC: Removed _drawable_vector.push_back call and added add_geom
   //call
@@ -603,8 +603,8 @@ void shader_keys(EventHandler &eh) {
 #ifdef DISPLAY_TEXPROJSPOTFRUST
   // Display a wireframe representation of the spotlight frustum
   Colorf color_red(1., 0., 0., 1.);
-  GeomLine* frust_geom =
-        (GeomLine *)tex_proj_spot->get_projection()->make_geometry(color_red);
+  PT(Geom) frust_geom =
+        tex_proj_spot->get_lens()->make_geometry(color_red);
   GeomNode* frust_geom_node = new GeomNode("frustum_geometry");
   //JMC: Removed _drawable_vector.push_back call and added add_geom
   //call