Browse Source

new distort library, separate out pandafx

David Rose 24 years ago
parent
commit
c5ec803f6f

+ 1 - 1
panda/metalibs/panda/Sources.pp

@@ -15,7 +15,7 @@
     gsgmisc light linmath mathutil net \
     parametrics pnm \
     pnmimagetypes pnmimage sgattrib sgmanip sgraph sgraphutil \
-    switchnode text tform tiff lerp loader putil effects \
+    switchnode text tform tiff lerp loader putil \
     audio pgui pandabase 
 
 

+ 16 - 0
panda/metalibs/pandafx/Sources.pp

@@ -0,0 +1,16 @@
+// DIR_TYPE "metalib" indicates we are building a shared library that
+// consists mostly of references to other shared libraries.  Under
+// Windows, this directly produces a DLL (as opposed to the regular
+// src libraries, which don't produce anything but a pile of OBJ files
+// under Windows).
+
+#define DIR_TYPE metalib
+#define BUILDING_DLL BUILDING_PANDAFX
+
+#define COMPONENT_LIBS \
+    distort effects
+
+#begin metalib_target
+  #define TARGET pandafx
+  #define SOURCES pandafx.cxx  
+#end metalib_target

+ 21 - 0
panda/metalibs/pandafx/pandafx.cxx

@@ -0,0 +1,21 @@
+// Filename: pandafx.cxx
+// Created by:  drose (11Dec01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "pandafx.h"
+
+#include <config_distort.h>
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libpandafx
+//  Description: Initializes the library.  This must be called at
+//               least once before any of the functions or classes in
+//               this library can be used.  Normally it will be
+//               called by the static initializers and need not be
+//               called explicitly, but special cases exist.
+////////////////////////////////////////////////////////////////////
+void
+init_libpandafx() {
+  init_libdistort();
+}

+ 13 - 0
panda/metalibs/pandafx/pandafx.h

@@ -0,0 +1,13 @@
+// Filename: pandafx.h
+// Created by:  drose (11Dec01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef PANDAFX_H
+#define PANDAFX_H
+
+#include <pandabase.h>
+
+EXPCL_PANDAFX void init_libpandafx();
+
+#endif

+ 20 - 0
panda/src/distort/Sources.pp

@@ -0,0 +1,20 @@
+#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
+                   dtoolutil:c dtoolbase:c dtool:m
+
+#begin lib_target
+  #define TARGET distort
+  #define LOCAL_LIBS \
+    sgraphutil sgraph sgattrib gobj linmath
+
+  #define SOURCES \
+    config_distort.cxx config_distort.h \
+    cylindricalLens.cxx cylindricalLens.h cylindricalLens.I \
+    fisheyeLens.cxx fisheyeLens.h fisheyeLens.I \
+    projectionScreen.cxx projectionScreen.h projectionScreen.I
+
+  #define INSTALL_HEADERS
+
+  #define IGATESCAN all
+
+#end lib_target
+

+ 52 - 0
panda/src/distort/config_distort.cxx

@@ -0,0 +1,52 @@
+// Filename: config_distort.cxx
+// Created by:  drose (11Dec01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "config_distort.h"
+#include "cylindricalLens.h"
+#include "fisheyeLens.h"
+#include "projectionScreen.h"
+
+#include "dconfig.h"
+
+Configure(config_distort);
+NotifyCategoryDef(distort, "");
+
+ConfigureFn(config_distort) {
+  init_libdistort();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libdistort
+//  Description: Initializes the library.  This must be called at
+//               least once before any of the functions or classes in
+//               this library can be used.  Normally it will be
+//               called by the static initializers and need not be
+//               called explicitly, but special cases exist.
+////////////////////////////////////////////////////////////////////
+void
+init_libdistort() {
+  static bool initialized = false;
+  if (initialized) {
+    return;
+  }
+  initialized = true;
+
+  CylindricalLens::init_type();
+  FisheyeLens::init_type();
+  ProjectionScreen::init_type();
+}

+ 29 - 0
panda/src/distort/config_distort.h

@@ -0,0 +1,29 @@
+// Filename: config_distort.h
+// Created by:  drose (11Dec01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 CONFIG_DISTORT_H
+#define CONFIG_DISTORT_H
+
+#include "pandabase.h"
+#include "notifyCategoryProxy.h"
+
+NotifyCategoryDecl(distort, EXPCL_PANDAFX, EXPTP_PANDAFX);
+
+extern EXPCL_PANDAFX void init_libdistort();
+
+#endif /* CONFIG_DISTORT_H */

+ 46 - 0
panda/src/distort/cylindricalLens.I

@@ -0,0 +1,46 @@
+// Filename: cylindricalLens.I
+// Created by:  drose (12Dec01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: CylindricalLens::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE CylindricalLens::
+CylindricalLens() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CylindricalLens::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE CylindricalLens::
+CylindricalLens(const CylindricalLens &copy) : Lens(copy) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CylindricalLens::Copy Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void CylindricalLens::
+operator = (const CylindricalLens &copy) {
+  Lens::operator = (copy);
+}
+

+ 190 - 0
panda/src/distort/cylindricalLens.cxx

@@ -0,0 +1,190 @@
+// Filename: cylindricalLens.cxx
+// Created by:  drose (12Dec01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "cylindricalLens.h"
+#include "deg_2_rad.h"
+
+TypeHandle CylindricalLens::_type_handle;
+
+// This is the focal-length constant for fisheye lenses.  See
+// fisheyeLens.cxx.
+static const float k = 60.0f;
+// focal_length = film_size * k / fov;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CylindricalLens::make_copy
+//       Access: Public, Virtual
+//  Description: Allocates a new Lens just like this one.
+////////////////////////////////////////////////////////////////////
+PT(Lens) CylindricalLens::
+make_copy() const {
+  return new CylindricalLens(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CylindricalLens::extrude_impl
+//       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 CylindricalLens::
+extrude_impl(const LPoint3f &point2d, LPoint3f &near_point, LPoint3f &far_point) const {
+  // Undo the shifting from film offsets, etc.  This puts the point
+  // into the range [-film_size/2, film_size/2] in x and y.
+  LPoint3f f = point2d * get_film_mat_inv();
+
+  float focal_length = get_focal_length();
+  float angle = f[0] * k / focal_length;
+  float sinAngle, cosAngle;
+  csincos(deg_2_rad(angle), &sinAngle, &cosAngle);
+
+  // Define a unit vector (well, a unit vector in the XY plane, at
+  // least) that reprents the vector corresponding to this point.
+  LPoint3f v(sinAngle, cosAngle, f[1] / focal_length);
+
+  // And we'll need to account for the lens's rotations, etc. at the
+  // end of the day.
+  const LMatrix4f &lens_mat = get_lens_mat();
+
+  near_point = (v * get_near()) * lens_mat;
+  far_point = (v * get_far()) * lens_mat;
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CylindricalLens::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 CylindricalLens::
+project_impl(const LPoint3f &point3d, LPoint3f &point2d) const {
+  // First, account for any rotations, etc. on the lens.
+  LPoint3f p = point3d * get_lens_mat_inv();
+
+  // To compute the x position on the frame, we only need to consider
+  // the angle of the vector about the Z axis.  Project the vector
+  // into the XY plane to do this.
+  LVector2f xy(p[0], p[1]);
+
+  // The perspective distance is the length of this vector in the XY
+  // plane.
+  float pdist = xy.length();
+  if (pdist == 0.0f) {
+    point2d.set(0.0f, 0.0f, 0.0f);
+    return false;
+  }
+
+  float focal_length = get_focal_length();
+
+  point2d.set
+    (
+     // The x position is the angle about the Z axis.
+     rad_2_deg(catan2(xy[0], xy[1])) * focal_length / k,
+     // The y position is the Z height divided by the perspective
+     // distance.
+     p[2] * focal_length / pdist,
+     // Z is the perspective distance scaled into the range (1, -1).
+     (get_near() - pdist) / (get_far() - get_near())
+     );
+
+  // Now we have to transform the point according to the film
+  // adjustments.
+  point2d = point2d * get_film_mat();
+
+  return
+    point2d[0] >= -1.0f && point2d[0] <= 1.0f && 
+    point2d[1] >= -1.0f && point2d[1] <= 1.0f;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CylindricalLens::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 CylindricalLens::
+fov_to_film(float fov, float focal_length, bool horiz) const {
+  if (horiz) {
+    return focal_length * fov / k;
+  } else {
+    return (ctan(deg_2_rad(fov * 0.5f)) * focal_length) * 2.0f;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CylindricalLens::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 CylindricalLens::
+fov_to_focal_length(float fov, float film_size, bool horiz) const {
+  if (horiz) {
+    return film_size * k / fov;
+  } else {
+    return film_size * 0.5f / ctan(deg_2_rad(fov * 0.5f));
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CylindricalLens::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 CylindricalLens::
+film_to_fov(float film_size, float focal_length, bool horiz) const {
+  if (horiz) {
+    return film_size * k / focal_length;
+  } else {
+    return rad_2_deg(catan(film_size * 0.5f / focal_length)) * 2.0f;
+  }
+}

+ 84 - 0
panda/src/distort/cylindricalLens.h

@@ -0,0 +1,84 @@
+// Filename: cylindricalLens.h
+// Created by:  drose (12Dec01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 CYLINDRICALLENS_H
+#define CYLINDRICALLENS_H
+
+#include "pandabase.h"
+
+#include "lens.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : CylindricalLens
+// Description : A cylindrical lens.  This is the kind of lens
+//               generally used for extremely wide panoramic shots.
+//               It behaves like a normal perspective lens in the
+//               vertical direction, but it is non-linear in the
+//               horizontal dimension: a point on the film corresponds
+//               to a point in space in linear proportion to its angle
+//               to the camera, not to its straight-line distance from
+//               the center.
+//
+//               This allows up to 360 degree lenses in the horizontal
+//               dimension, with relatively little distortion.  The
+//               distortion is not very apparent between two
+//               relatively nearby points on the film, but it becomes
+//               increasingly evident as you compare points widely
+//               spaced on the film.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAFX CylindricalLens : public Lens {
+PUBLISHED:
+  INLINE CylindricalLens();
+
+public:
+  INLINE CylindricalLens(const CylindricalLens &copy);
+  INLINE void operator = (const CylindricalLens &copy);
+
+public:
+  virtual PT(Lens) make_copy() const;
+
+protected:
+  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 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 {
+    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, "CylindricalLens",
+                  Lens::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "cylindricalLens.I"
+
+#endif

+ 46 - 0
panda/src/distort/fisheyeLens.I

@@ -0,0 +1,46 @@
+// Filename: fisheyeLens.I
+// Created by:  drose (12Dec01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: FisheyeLens::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE FisheyeLens::
+FisheyeLens() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FisheyeLens::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE FisheyeLens::
+FisheyeLens(const FisheyeLens &copy) : Lens(copy) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FisheyeLens::Copy Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void FisheyeLens::
+operator = (const FisheyeLens &copy) {
+  Lens::operator = (copy);
+}
+

+ 228 - 0
panda/src/distort/fisheyeLens.cxx

@@ -0,0 +1,228 @@
+// Filename: fisheyeLens.cxx
+// Created by:  drose (12Dec01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "fisheyeLens.h"
+#include "deg_2_rad.h"
+
+TypeHandle FisheyeLens::_type_handle;
+
+// This is the focal-length constant for fisheye lenses.  The focal
+// length of a fisheye lens relates to its fov by the equation:
+
+//   w = Fd/k
+
+// Where w is the width of the negative, F is the focal length, and d
+// is the total field of view in degrees.
+
+// k is chosen to make the focal lengths for a fisheye lens roughly
+// correspond to the equivalent field of view for a conventional,
+// perspective lens.  It was determined empirically by simple
+// examination of a couple of actual lenses for 35mm film.  I don't
+// know how well this extends to other lenses and other negative
+// sizes.
+
+static const float k = 60.0f;
+// focal_length = film_size * k / fov;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: FisheyeLens::make_copy
+//       Access: Public, Virtual
+//  Description: Allocates a new Lens just like this one.
+////////////////////////////////////////////////////////////////////
+PT(Lens) FisheyeLens::
+make_copy() const {
+  return new FisheyeLens(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FisheyeLens::extrude_impl
+//       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 FisheyeLens::
+extrude_impl(const LPoint3f &point2d, LPoint3f &near_point, LPoint3f &far_point) const {
+  // Undo the shifting from film offsets, etc.  This puts the point
+  // into the range [-film_size/2, film_size/2] in x and y.
+  LPoint3f f = point2d * get_film_mat_inv();
+
+  // First, get the vector from the center of the film to the point,
+  // and normalize it.
+  LVector2f v2(f[0], f[1]);
+
+  LPoint3f v;
+
+  float r = v2.length();
+  if (r == 0.0f) {
+    // Special case: directly forward.
+    v.set(0.0f, 1.0f, 0.0f);
+
+  } else {
+    v2 /= r;
+
+    // Now get the point r units around the circle in the YZ plane.
+    float focal_length = get_focal_length();
+    float angle = r * k / focal_length;
+    float sinAngle, cosAngle;
+    csincos(deg_2_rad(angle), &sinAngle, &cosAngle);
+
+    LVector3f p(0.0, cosAngle, sinAngle);
+
+    // And rotate this point around the Y axis.
+    v.set(p[0]*v2[1] + p[2]*v2[0],
+          p[1],
+          p[2]*v2[1] - p[0]*v2[0]);
+  }
+
+  // And we'll need to account for the lens's rotations, etc. at the
+  // end of the day.
+  const LMatrix4f &lens_mat = get_lens_mat();
+
+  near_point = (v * get_near()) * lens_mat;
+  far_point = (v * get_far()) * lens_mat;
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FisheyeLens::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 FisheyeLens::
+project_impl(const LPoint3f &point3d, LPoint3f &point2d) const {
+  // First, account for any rotations, etc. on the lens.
+  LVector3f v2 = point3d * get_lens_mat_inv();
+
+  // A fisheye lens projection has the property that the distance from
+  // the center point to any other point on the projection is
+  // proportional to the actual distance on the sphere along the great
+  // circle.  Also, the angle to the point on the projection is equal
+  // to the angle to the point on the sphere.
+
+  // First, get the straight-line distance from the lens, and use it
+  // to normalize the vector.
+  float dist = v2.length();
+  v2 /= dist;
+
+  // Now, project the point into the XZ plane and measure its angle
+  // to the Z axis.  This is the same angle it will have to the
+  // vertical axis on the film.
+  LVector2f y(v2[0], v2[2]);
+  y.normalize();
+
+  if (y == LVector2f(0.0f, 0.0f)) {
+    // Special case.  This point is either directly ahead or directly
+    // behind.
+    point2d.set(0.0f, 0.0f, 
+                (get_near() - dist) / (get_far() - get_near()));
+    return v2[1] >= 0.0f;
+  }
+
+  // Now bring the vector into the YZ plane by rotating about the Y
+  // axis.
+  LVector2f x(v2[1], v2[0]*y[0]+v2[2]*y[1]);
+
+  // Now the angle of x to the forward vector represents the distance
+  // along the great circle to the point.
+  float r = 90.0f - rad_2_deg(catan2(x[0], x[1]));
+
+  float focal_length = get_focal_length();
+  float factor = r * focal_length / k;
+
+  point2d.set
+    (y[0] * factor,
+     y[1] * factor,
+     // Z is the distance scaled into the range (1, -1).
+     (get_near() - dist) / (get_far() - get_near())
+     );
+
+  // Now we have to transform the point according to the film
+  // adjustments.
+  point2d = point2d * get_film_mat();
+
+  return
+    point2d[0] >= -1.0f && point2d[0] <= 1.0f && 
+    point2d[1] >= -1.0f && point2d[1] <= 1.0f;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FisheyeLens::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 FisheyeLens::
+fov_to_film(float fov, float focal_length, bool) const {
+  return focal_length * fov / k;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FisheyeLens::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 FisheyeLens::
+fov_to_focal_length(float fov, float film_size, bool) const {
+  return film_size * k / fov;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FisheyeLens::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 FisheyeLens::
+film_to_fov(float film_size, float focal_length, bool) const {
+  return film_size * k / focal_length;
+}
+

+ 74 - 0
panda/src/distort/fisheyeLens.h

@@ -0,0 +1,74 @@
+// Filename: fisheyeLens.h
+// Created by:  drose (12Dec01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 FISHEYELENS_H
+#define FISHEYELENS_H
+
+#include "pandabase.h"
+
+#include "lens.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : FisheyeLens
+// Description : A fisheye lens.  This nonlinear lens introduces a
+//               spherical distortion to the image, which is minimal
+//               at small angles from the lens, and increases at
+//               larger angles from the lens.  The field of view may
+//               extend to 360 degrees.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAFX FisheyeLens : public Lens {
+PUBLISHED:
+  INLINE FisheyeLens();
+
+public:
+  INLINE FisheyeLens(const FisheyeLens &copy);
+  INLINE void operator = (const FisheyeLens &copy);
+
+public:
+  virtual PT(Lens) make_copy() const;
+
+protected:
+  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 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 {
+    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, "FisheyeLens",
+                  Lens::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "fisheyeLens.I"
+
+#endif

+ 133 - 0
panda/src/distort/projectionScreen.I

@@ -0,0 +1,133 @@
+// Filename: projectionScreen.I
+// Created by:  drose (11Dec01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: ProjectionScreen::set_projector
+//       Access: Published
+//  Description: Specifies the LensNode that is to serve as the
+//               projector for this screen.  The relative position of
+//               the LensNode to the ProjectionScreen, as well as the
+//               properties of the lens associated with the LensNode,
+//               determines the UV's that will be assigned to the
+//               geometry within the ProjectionScreen.
+////////////////////////////////////////////////////////////////////
+INLINE void ProjectionScreen::
+set_projector(LensNode *projector) {
+  _projector = projector;
+  _stale = true;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::get_projector
+//       Access: Published
+//  Description: Returns the LensNode that is to serve as the
+//               projector for this screen, or NULL if no LensNode is
+//               associated.
+////////////////////////////////////////////////////////////////////
+INLINE LensNode *ProjectionScreen::
+get_projector() const {
+  return _projector;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::set_vignette_on
+//       Access: Published
+//  Description: Specifies whether vertex-based vignetting should be
+//               on.  When this is enabled, vertex color will be set
+//               on the screen vertices to color the screen two
+//               distinct colors, usually white and black, for the
+//               parts of the screen in front of and outside the lens'
+//               frustum, respectively.  When this is not enabled, the
+//               screen color will be left alone.
+//
+//               This effect generally looks terrible, but it does
+//               at least make the boundaries of the lens clear.
+////////////////////////////////////////////////////////////////////
+INLINE void ProjectionScreen::
+set_vignette_on(bool vignette_on) {
+  _vignette_on = vignette_on;
+  _stale = true;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::get_vignette_on
+//       Access: Published
+//  Description: Returns true if vertex-based vignetting is on, false
+//               otherwise.  See set_vignette_on().
+////////////////////////////////////////////////////////////////////
+INLINE bool ProjectionScreen::
+get_vignette_on() const {
+  return _vignette_on;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::set_vignette_color
+//       Access: Published
+//  Description: Specifies the color the screen will be painted at the
+//               portions outside of the lens' frustum; i.e. where the
+//               lens can't see it or illuminate it.  This color is
+//               only used if the vignette_on flag is true; see
+//               set_vignette_on().
+////////////////////////////////////////////////////////////////////
+INLINE void ProjectionScreen::
+set_vignette_color(const Colorf &vignette_color) {
+  _vignette_color = vignette_color;
+  _stale = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::get_vignette_color
+//       Access: Published
+//  Description: Returns the color the screen will be painted at the
+//               portions outside of the lens' frustum.  See
+//               set_vignette_color().
+////////////////////////////////////////////////////////////////////
+INLINE const Colorf &ProjectionScreen::
+get_vignette_color() const {
+  return _vignette_color;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::set_frame_color
+//       Access: Published
+//  Description: Specifies the color the screen will be painted at the
+//               portions outside of the lens' frustum; i.e. where the
+//               lens can't see it or illuminate it.  This color is
+//               only used if the vignette_on flag is true; see
+//               set_vignette_on().
+////////////////////////////////////////////////////////////////////
+INLINE void ProjectionScreen::
+set_frame_color(const Colorf &frame_color) {
+  _frame_color = frame_color;
+  _stale = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::get_frame_color
+//       Access: Published
+//  Description: Returns the color the screen will be painted at the
+//               portions outside of the lens' frustum.  See
+//               set_frame_color().
+////////////////////////////////////////////////////////////////////
+INLINE const Colorf &ProjectionScreen::
+get_frame_color() const {
+  return _frame_color;
+}

+ 376 - 0
panda/src/distort/projectionScreen.cxx

@@ -0,0 +1,376 @@
+// Filename: projectionScreen.cxx
+// Created by:  drose (11Dec01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "projectionScreen.h"
+#include "geomNode.h"
+#include "geom.h"
+#include "geomTristrip.h"
+#include "renderRelation.h"
+#include "transformTransition.h"
+#include "get_rel_pos.h"
+
+TypeHandle ProjectionScreen::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ProjectionScreen::
+ProjectionScreen(const string &name) : NamedNode(name)
+{
+  _vignette_on = false;
+  _vignette_color.set(0.0f, 0.0f, 0.0f, 1.0f);
+  _frame_color.set(1.0f, 1.0f, 1.0f, 1.0f);
+  _computed_rel_top_mat = false;
+  _stale = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ProjectionScreen::
+~ProjectionScreen() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ProjectionScreen::
+ProjectionScreen(const ProjectionScreen &copy) :
+  NamedNode(copy),
+  _projector(copy._projector),
+  _vignette_on(copy._vignette_on),
+  _vignette_color(copy._vignette_color),
+  _frame_color(copy._frame_color)
+{
+  _computed_rel_top_mat = false;
+  _stale = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void ProjectionScreen::
+operator = (const ProjectionScreen &copy) {
+  NamedNode::operator = (copy);
+  _projector = copy._projector;
+  _vignette_on = copy._vignette_on;
+  _vignette_color = copy._vignette_color;
+  _frame_color = copy._frame_color;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::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 *ProjectionScreen::
+make_copy() const {
+  return new ProjectionScreen(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::app_traverse
+//       Access: Public, Virtual
+//  Description: This is called by the App traversal by virtue of the
+//               ProjectionScreen node's being present in the scene graph.
+////////////////////////////////////////////////////////////////////
+void ProjectionScreen::
+app_traverse(const ArcChain &) {
+  recompute_if_stale();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::generate_screen
+//       Access: Published
+//  Description: Synthesizes a polygon mesh based on the projection
+//               area of the indicated projector.  This generates a
+//               new GeomNode and automatically parents it to the
+//               ProjectionScreen; the new GeomNode is also returned
+//               for reference.
+//
+//               The specified projector need not be the same as the
+//               projector given to the ProjectionScreen with
+//               set_projector() (although this is often what you
+//               want).
+//
+//               num_x_verts and num_y_verts specify the number of
+//               vertices to make in the grid across the horizontal
+//               and vertical dimension of the projector,
+//               respectively; distance represents the approximate
+//               distance of the screen from the lens center.
+////////////////////////////////////////////////////////////////////
+GeomNode *ProjectionScreen::
+generate_screen(LensNode *projector, const string &screen_name,
+                int num_x_verts, int num_y_verts, float distance) {
+  nassertr(projector != (LensNode *)NULL, NULL);
+  nassertr(projector->get_lens() != NULL, NULL);
+
+  // First, get the relative coordinate space of the projector.
+  LMatrix4f rel_mat;
+  get_rel_mat(projector, this, rel_mat);
+
+  // Now compute all the vertices for the screen.  These are arranged
+  // in order from left to right and bottom to top.
+  int num_verts = num_x_verts * num_y_verts;
+  Lens *lens = projector->get_lens();
+  float t = (distance - lens->get_near()) / (lens->get_far() - lens->get_near());
+
+  PTA_Vertexf coords;
+  coords.reserve(num_verts);
+  float x_scale = 2.0f / (num_x_verts - 1);
+  float y_scale = 2.0f / (num_y_verts - 1);
+  for (int yi = 0; yi < num_y_verts; yi++) {
+    for (int xi = 0; xi < num_x_verts; xi++) {
+      LPoint2f film = LPoint2f((float)xi * x_scale - 1.0f,
+                               (float)yi * y_scale - 1.0f);
+      LPoint3f near_point, far_point;
+      lens->extrude(film, near_point, far_point);
+      
+      LPoint3f point = near_point + t * (far_point - near_point);
+      point = point * rel_mat;
+      
+      coords.push_back(point);
+    }
+  }
+  nassertr((int)coords.size() == num_verts, NULL);
+
+  // Now synthesize a triangle mesh.  We run triangle strips
+  // horizontally across the grid.
+  int num_tstrips = (num_y_verts-1);
+  int tstrip_length = 2*(num_x_verts-1)+2;
+
+  PTA_int lengths;
+  PTA_ushort vindex;
+
+  // Set the lengths array.  we are creating num_tstrips t-strips,
+  // each of which has tstrip_length vertices.
+  lengths.reserve(num_tstrips);
+  int n;
+  for (n = 0; n < num_tstrips; n++) {
+    lengths.push_back(tstrip_length);
+  }
+  nassertr((int)lengths.size() == num_tstrips, NULL);
+
+  // Now fill up the index array into the vertices.  This lays out the
+  // order of the vertices in each t-strip.
+  vindex.reserve(num_tstrips * tstrip_length);
+  n = 0;
+  int ti, si;
+  for (ti = 1; ti < num_y_verts; ti++) {
+    vindex.push_back(ti * num_x_verts);
+    for (si = 1; si < num_x_verts; si++) {
+      vindex.push_back((ti - 1) * num_x_verts + (si-1));
+      vindex.push_back(ti * num_x_verts + si);
+    }
+    vindex.push_back((ti - 1) * num_x_verts + (num_x_verts-1));
+  }
+  nassertr((int)vindex.size() == num_tstrips * tstrip_length, NULL);
+
+  GeomTristrip *geom = new GeomTristrip;
+  geom->set_num_prims(num_tstrips);
+  geom->set_lengths(lengths);
+
+  geom->set_coords(coords, G_PER_VERTEX, vindex);
+
+  // Make it white.
+  PTA_Colorf colors;
+  colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
+  geom->set_colors(colors, G_OVERALL);
+
+  // Now create a GeomNode to hold this mesh.
+  GeomNode *geom_node = new GeomNode(screen_name);
+  geom_node->add_geom(geom);
+
+  // And parent it to ourselves.
+  new RenderRelation(this, geom_node);
+  _stale = true;
+
+  return geom_node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::recompute
+//       Access: Published
+//  Description: Recomputes all the UV's for geometry below the
+//               ProjectionScreen node, as if the texture were
+//               projected from the associated projector.
+//
+//               This function is normally called automatically
+//               whenever the relevant properties change, so it should
+//               not normally need to be called directly by the user.
+//               However, it does no harm to call this if there is any
+//               doubt.
+////////////////////////////////////////////////////////////////////
+void ProjectionScreen::
+recompute() {
+  if (_projector != (LensNode *)NULL && 
+      _projector->get_lens() != (Lens *)NULL) {
+    _colors.clear();
+    _colors.push_back(_vignette_color);
+    _colors.push_back(_frame_color);
+
+    recompute_node(this, _rel_top_mat, _computed_rel_top_mat);
+    // Make sure this flag is set to false for next time.
+    _computed_rel_top_mat = false;
+
+    _projector_lens_change = _projector->get_lens()->get_last_change();
+    _stale = false;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::recompute_if_stale
+//       Access: Private
+//  Description: Calls recompute() only if the relative transform
+//               between the ProjectionScreen and the projector has
+//               changed, or if any other relevant property has
+//               changed.
+////////////////////////////////////////////////////////////////////
+void ProjectionScreen::
+recompute_if_stale() {
+  if (_projector != (LensNode *)NULL && 
+      _projector->get_lens() != (Lens *)NULL) {
+    UpdateSeq lens_change = _projector->get_lens()->get_last_change();
+    if (_stale || lens_change != _projector_lens_change) {
+      recompute();
+
+    } else {
+      // Get the relative transform to ensure it hasn't changed.
+      LMatrix4f top_mat;
+      get_rel_mat(this, _projector, top_mat);
+      if (!_rel_top_mat.almost_equal(top_mat)) {
+        _rel_top_mat = top_mat;
+        _computed_rel_top_mat = true;
+        recompute();
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::recompute_node
+//       Access: Private
+//  Description: Recurses over all geometry at the indicated node and
+//               below, looking for GeomNodes that want to have new
+//               UV's computed.  When a new transform space is
+//               encountered, a new relative matrix is computed.
+////////////////////////////////////////////////////////////////////
+void ProjectionScreen::
+recompute_node(Node *node, LMatrix4f &rel_mat, bool &computed_rel_mat) {
+  if (node->is_of_type(GeomNode::get_class_type())) {
+    recompute_geom_node(DCAST(GeomNode, node), rel_mat, computed_rel_mat);
+  }
+
+  // Now recurse on children.
+  int num_children = node->get_num_children(RenderRelation::get_class_type());
+  for (int i = 0; i < num_children; i++) {
+    NodeRelation *arc = node->get_child(RenderRelation::get_class_type(), i);
+
+    if (arc->has_transition(TransformTransition::get_class_type())) {
+      // This arc has a transform; therefore, we must recompute the
+      // relative matrix from this point.
+      LMatrix4f new_rel_mat;
+      bool computed_new_rel_mat = false;
+      recompute_node(arc->get_child(), new_rel_mat, computed_new_rel_mat);
+    } else {
+      // This arc has no transform, so we can use the same transform
+      // space from before.
+      recompute_node(arc->get_child(), rel_mat, computed_rel_mat);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::recompute_geom_node
+//       Access: Private
+//  Description: Recomputes the UV's just for the indicated GeomNode.
+////////////////////////////////////////////////////////////////////
+void ProjectionScreen::
+recompute_geom_node(GeomNode *node, LMatrix4f &rel_mat, bool &computed_rel_mat) {
+  if (!computed_rel_mat) {
+    // All right, time to compute the matrix.
+    get_rel_mat(node, _projector, rel_mat);
+    computed_rel_mat = true;
+  }
+
+  int num_geoms = node->get_num_geoms();
+  for (int i = 0; i < num_geoms; i++) {
+    dDrawable *drawable = node->get_geom(i);
+    if (drawable->is_of_type(Geom::get_class_type())) {
+      recompute_geom(DCAST(Geom, drawable), rel_mat);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::recompute_geom
+//       Access: Private
+//  Description: Recomputes the UV's just for the indicated Geom.
+////////////////////////////////////////////////////////////////////
+void ProjectionScreen::
+recompute_geom(Geom *geom, const LMatrix4f &rel_mat) {
+  static const LMatrix3f LensToUv
+    (0.5f, 0.0f, 0.0f,
+     0.0f, 0.5f, 0.0f,
+     0.5f, 0.5f, 1.0f);
+
+  PTA_TexCoordf uvs;
+  PTA_ushort color_index;
+  Lens *lens = _projector->get_lens();
+  nassertv(lens != (Lens *)NULL);
+
+  // Iterate through all the vertices in the Geom.
+  int num_vertices = geom->get_num_vertices();
+  Geom::VertexIterator vi = geom->make_vertex_iterator();
+
+  for (int i = 0; i < num_vertices; i++) {
+    const Vertexf &vert = geom->get_next_vertex(vi);
+
+    // For each vertex, project to the film plane.
+    LPoint2f film(0.0, 0.0);
+    bool good = lens->project(vert * rel_mat, film);
+
+    // Now the lens gives us coordinates in the range [-1, 1].
+    // Rescale these to [0, 1].
+    uvs.push_back(film * LensToUv);
+
+    // If we have vignette color in effect, color the vertex according
+    // to whether it fell in front of the lens or not.
+    if (_vignette_on) {
+      color_index.push_back(good ? 1 : 0);
+    }
+  }
+
+  // Now set the UV's.
+  geom->set_texcoords(uvs, G_PER_VERTEX);
+
+  if (_vignette_on) {
+    geom->set_colors(_colors, G_PER_VERTEX, color_index);
+  }
+}

+ 114 - 0
panda/src/distort/projectionScreen.h

@@ -0,0 +1,114 @@
+// Filename: projectionScreen.h
+// Created by:  drose (11Dec01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 PROJECTIONSCREEN_H
+#define PROJECTIONSCREEN_H
+
+#include "pandabase.h"
+
+#include "namedNode.h"
+#include "lensNode.h"
+
+class GeomNode;
+class Geom;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ProjectionScreen
+// Description : A ProjectionScreen implements a simple system for
+//               projective texturing.  The ProjectionScreen node is
+//               the parent of a hierarchy of geometry that is
+//               considered a "screen"; the ProjectionScreen will
+//               automatically recompute all the UV's on its
+//               subordinate geometry according to the relative
+//               position and lens parameters of the indicated
+//               LensNode.
+//
+//               This does not take advantage of any hardware-assisted
+//               projective texturing; nor does it presently support
+//               multitexturing.  However, it does support any kind of
+//               lens, linear or nonlinear, that might be defined
+//               using the Lens interface, including fisheye and
+//               cylindrical lenses.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAFX ProjectionScreen : public NamedNode {
+PUBLISHED:
+  ProjectionScreen(const string &name = "");
+  virtual ~ProjectionScreen();
+
+public:
+  ProjectionScreen(const ProjectionScreen &copy);
+  void operator = (const ProjectionScreen &copy);
+
+  virtual Node *make_copy() const;
+  virtual void app_traverse(const ArcChain &chain);
+
+PUBLISHED:
+  INLINE void set_projector(LensNode *projector);
+  INLINE LensNode *get_projector() const;
+
+  GeomNode *generate_screen(LensNode *projector, const string &screen_name,
+                            int num_x_verts, int num_y_verts, float distance);
+
+  INLINE void set_vignette_on(bool vignette_on);
+  INLINE bool get_vignette_on() const;
+
+  INLINE void set_vignette_color(const Colorf &vignette_color);
+  INLINE const Colorf &get_vignette_color() const;
+  INLINE void set_frame_color(const Colorf &frame_color);
+  INLINE const Colorf &get_frame_color() const;
+
+  void recompute();
+
+private:
+  void recompute_if_stale();
+  void recompute_node(Node *node, LMatrix4f &rel_mat, bool &computed_rel_mat);
+  void recompute_geom_node(GeomNode *node, LMatrix4f &rel_mat, bool &computed_rel_mat);
+  void recompute_geom(Geom *geom, const LMatrix4f &rel_mat);
+
+  PT(LensNode) _projector;
+  bool _vignette_on;
+  Colorf _vignette_color;
+  Colorf _frame_color;
+
+  PTA_Colorf _colors;
+  LMatrix4f _rel_top_mat;
+  bool _computed_rel_top_mat;
+  bool _stale;
+  UpdateSeq _projector_lens_change;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    NamedNode::init_type();
+    register_type(_type_handle, "ProjectionScreen",
+                  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 "projectionScreen.I"
+
+#endif

+ 2 - 0
panda/src/effects/Sources.pp

@@ -14,5 +14,7 @@
   #define INSTALL_HEADERS \
     config_effects.h lensFlareNode.I lensFlareNode.h
 
+  #define IGATESCAN all
+
 #end lib_target
 

+ 13 - 0
panda/src/effects/config_effects.cxx

@@ -25,6 +25,19 @@ Configure(config_effects);
 NotifyCategoryDef(effects, "");
 
 ConfigureFn(config_effects) {
+  init_libeffects();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libeffects
+//  Description: Initializes the library.  This must be called at
+//               least once before any of the functions or classes in
+//               this library can be used.  Normally it will be
+//               called by the static initializers and need not be
+//               called explicitly, but special cases exist.
+////////////////////////////////////////////////////////////////////
+void
+init_libeffects() {
   LensFlareNode::init_type();
 
   //Registration of writeable object's creation

+ 3 - 1
panda/src/effects/config_effects.h

@@ -23,6 +23,8 @@
 #include <pandabase.h>
 #include <notifyCategoryProxy.h>
 
-NotifyCategoryDecl(effects, EXPCL_PANDA, EXPTP_PANDA);
+NotifyCategoryDecl(effects, EXPCL_PANDAFX, EXPTP_PANDAFX);
+
+extern EXPCL_PANDAFX void init_libeffects();
 
 #endif /* CONFIG_EFFECTS_H */

+ 1 - 2
panda/src/effects/lensFlareNode.h

@@ -32,7 +32,7 @@
 class GraphicsStateGuardian;
 class ClockObject;
 
-class EXPCL_PANDA LensFlareNode : public Node
+class EXPCL_PANDAFX LensFlareNode : public Node
 {
 PUBLISHED:
   INLINE LensFlareNode(void);
@@ -41,7 +41,6 @@ PUBLISHED:
                  PTA_float angle_scales, PTA_Colorf colors);
   void add_blind(PT(Texture) blind);
 
-  INLINE void set_angle_scale(float scale);
   INLINE void set_texel_scale(float texel_to_world);
   INLINE void set_global_scale(float scale);
 

+ 1 - 1
panda/src/gobj/imageBuffer.h

@@ -47,10 +47,10 @@ PUBLISHED:
   ImageBuffer( void ) : dDrawable() { }
   virtual ~ImageBuffer( void ) { }
 
+public:
   virtual bool read( const string& name ) = 0;
   virtual bool write( const string& name = "" ) const = 0;
 
-public:
   virtual void config( void ) { WritableConfigurable::config(); }
 
   virtual void copy(GraphicsStateGuardianBase *, const DisplayRegion *)=0;

+ 12 - 11
panda/src/gobj/lens.I

@@ -70,16 +70,16 @@ extrude(const LPoint3f &point2d, LPoint3f &near_point, LPoint3f &far_point) cons
 //
 //               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.
+//               is filled in), or false otherwise (in which case
+//               point2d will be filled in with something, which may
+//               or may not be meaningful).
 ////////////////////////////////////////////////////////////////////
 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;
+  bool okflag = project_impl(point3d, result);
+  point2d.set(result[0], result[1]);
+  return okflag;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -90,14 +90,15 @@ project(const LPoint3f &point3d, LPoint2f &point2d) const {
 //               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.
+//               The z coordinate will also be set 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.
+//               is filled in), or false otherwise (in which case
+//               point2d will be filled in with something, which may
+//               or may not be meaningful).
 ////////////////////////////////////////////////////////////////////
 INLINE bool Lens::
 project(const LPoint3f &point3d, LPoint3f &point2d) const {

+ 11 - 7
panda/src/gobj/lens.cxx

@@ -1034,7 +1034,7 @@ get_lens_mat_inv() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: Lens::extrude
+//     Function: Lens::extrude_impl
 //       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
@@ -1080,14 +1080,15 @@ extrude_impl(const LPoint3f &point2d, LPoint3f &near_point, LPoint3f &far_point)
 //               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.
+//               The z coordinate will also be set 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.
+//               is filled in), or false otherwise (in which case
+//               point2d will be filled in with something, which may
+//               or may not be meaningful).
 ////////////////////////////////////////////////////////////////////
 bool Lens::
 project_impl(const LPoint3f &point3d, LPoint3f &point2d) const {
@@ -1095,10 +1096,13 @@ project_impl(const LPoint3f &point3d, LPoint3f &point2d) const {
   LVecBase4f full(point3d[0], point3d[1], point3d[2], 1.0f);
   full = projection_mat.xform(full);
   if (full[3] == 0.0f) {
+    point2d.set(0.0f, 0.0f, 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 && 
+  return
+    full[3] > 0.0f &&
+    point2d[0] >= -1.0f && point2d[0] <= 1.0f && 
     point2d[1] >= -1.0f && point2d[1] <= 1.0f;
 }
 

+ 2 - 2
panda/src/gobj/perspectiveLens.cxx

@@ -58,8 +58,8 @@ compute_projection_mat() {
   }
 
   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);
+  float a = (get_far() + get_near()) / (get_far() - get_near());
+  float b = -2.0f * get_far() * get_near() / (get_far() - get_near());
 
   LMatrix4f canonical;
   switch (cs) {

+ 32 - 21
panda/src/pandabase/pandasymbols.h

@@ -31,12 +31,12 @@
   #define EXPTP_PANDA extern
 #endif
 
-#ifdef BUILDING_PANDAEXPRESS
-  #define EXPCL_PANDAEXPRESS __declspec(dllexport)
-  #define EXPTP_PANDAEXPRESS
+#ifdef BUILDING_PANDADX
+  #define EXPCL_PANDADX __declspec(dllexport)
+  #define EXPTP_PANDADX
 #else
-  #define EXPCL_PANDAEXPRESS __declspec(dllimport)
-  #define EXPTP_PANDAEXPRESS extern
+  #define EXPCL_PANDADX __declspec(dllimport)
+  #define EXPTP_PANDADX extern
 #endif
 
 #ifdef BUILDING_PANDAEGG
@@ -47,12 +47,20 @@
   #define EXPTP_PANDAEGG extern
 #endif
 
-#ifdef BUILDING_PANDAPHYSICS
-  #define EXPCL_PANDAPHYSICS __declspec(dllexport)
-  #define EXPTP_PANDAPHYSICS
+#ifdef BUILDING_PANDAEXPRESS
+  #define EXPCL_PANDAEXPRESS __declspec(dllexport)
+  #define EXPTP_PANDAEXPRESS
 #else
-  #define EXPCL_PANDAPHYSICS __declspec(dllimport)
-  #define EXPTP_PANDAPHYSICS extern
+  #define EXPCL_PANDAEXPRESS __declspec(dllimport)
+  #define EXPTP_PANDAEXPRESS extern
+#endif
+
+#ifdef BUILDING_PANDAFX
+  #define EXPCL_PANDAFX __declspec(dllexport)
+  #define EXPTP_PANDAFX
+#else
+  #define EXPCL_PANDAFX __declspec(dllimport)
+  #define EXPTP_PANDAFX extern
 #endif
 
 #ifdef BUILDING_PANDAGL
@@ -71,12 +79,12 @@
   #define EXPTP_PANDAGLUT extern
 #endif
 
-#ifdef BUILDING_PANDADX
-  #define EXPCL_PANDADX __declspec(dllexport)
-  #define EXPTP_PANDADX
+#ifdef BUILDING_PANDAPHYSICS
+  #define EXPCL_PANDAPHYSICS __declspec(dllexport)
+  #define EXPTP_PANDAPHYSICS
 #else
-  #define EXPCL_PANDADX __declspec(dllimport)
-  #define EXPTP_PANDADX extern
+  #define EXPCL_PANDAPHYSICS __declspec(dllimport)
+  #define EXPTP_PANDAPHYSICS extern
 #endif
 
 #ifdef BUILDING_PANDARIB
@@ -116,14 +124,17 @@
 #define EXPCL_PANDA
 #define EXPTP_PANDA
 
-#define EXPCL_PANDAEXPRESS
-#define EXPTP_PANDAEXPRESS
+#define EXPCL_PANDADX
+#define EXPTP_PANDADX
 
 #define EXPCL_PANDAEGG
 #define EXPTP_PANDAEGG
 
-#define EXPCL_PANDAPHYSICS
-#define EXPTP_PANDAPHYSICS
+#define EXPCL_PANDAEXPRESS
+#define EXPTP_PANDAEXPRESS
+
+#define EXPCL_PANDAFX
+#define EXPTP_PANDAFX
 
 #define EXPCL_PANDAGL
 #define EXPTP_PANDAGL
@@ -131,8 +142,8 @@
 #define EXPCL_PANDAGLUT
 #define EXPTP_PANDAGLUT
 
-#define EXPCL_PANDADX
-#define EXPTP_PANDADX
+#define EXPCL_PANDAPHYSICS
+#define EXPTP_PANDAPHYSICS
 
 #define EXPCL_PANDARIB
 #define EXPTP_PANDARIB