Browse Source

added pos to images

David Rose 24 years ago
parent
commit
0fc8c767da
33 changed files with 1365 additions and 167 deletions
  1. 13 4
      pandaapp/src/stitch/stitchImageProgram.cxx
  2. 1 1
      pandaapp/src/stitch/stitchImageProgram.h
  3. 12 3
      pandaapp/src/stitchbase/Sources.pp
  4. 2 0
      pandaapp/src/stitchbase/config_stitch.cxx
  5. 1 1
      pandaapp/src/stitchbase/config_stitch.h
  6. 1 1
      pandaapp/src/stitchbase/layeredImage.h
  7. 111 0
      pandaapp/src/stitchbase/stitchCommand.cxx
  8. 20 6
      pandaapp/src/stitchbase/stitchCommand.h
  9. 1 1
      pandaapp/src/stitchbase/stitchCommandReader.h
  10. 182 0
      pandaapp/src/stitchbase/stitchCylindricalScreen.cxx
  11. 63 0
      pandaapp/src/stitchbase/stitchCylindricalScreen.h
  12. 69 0
      pandaapp/src/stitchbase/stitchFlatScreen.cxx
  13. 46 0
      pandaapp/src/stitchbase/stitchFlatScreen.h
  14. 127 31
      pandaapp/src/stitchbase/stitchImage.cxx
  15. 15 3
      pandaapp/src/stitchbase/stitchImage.h
  16. 4 2
      pandaapp/src/stitchbase/stitchImageCommandOutput.cxx
  17. 24 0
      pandaapp/src/stitchbase/stitchImageOutputter.cxx
  18. 25 2
      pandaapp/src/stitchbase/stitchImageOutputter.h
  19. 50 32
      pandaapp/src/stitchbase/stitchImageRasterizer.cxx
  20. 1 1
      pandaapp/src/stitchbase/stitchImageRasterizer.h
  21. 28 0
      pandaapp/src/stitchbase/stitchLexer.lxx
  22. 1 1
      pandaapp/src/stitchbase/stitchLexerDefs.h
  23. 127 0
      pandaapp/src/stitchbase/stitchMultiScreen.cxx
  24. 59 0
      pandaapp/src/stitchbase/stitchMultiScreen.h
  25. 40 50
      pandaapp/src/stitchbase/stitchParser.h
  26. 67 7
      pandaapp/src/stitchbase/stitchParser.yxx
  27. 1 1
      pandaapp/src/stitchbase/stitchParserDefs.h
  28. 2 0
      pandaapp/src/stitchbase/stitchPoint.h
  29. 134 0
      pandaapp/src/stitchbase/stitchScreen.cxx
  30. 82 0
      pandaapp/src/stitchbase/stitchScreen.h
  31. 5 0
      pandaapp/src/stitchbase/triangleRasterizer.cxx
  32. 51 19
      pandaapp/src/stitchviewer/stitchImageVisualizer.cxx
  33. 0 1
      pandaapp/src/stitchviewer/stitchImageVisualizer.h

+ 13 - 4
pandaapp/src/stitch/stitchImageProgram.cxx

@@ -35,9 +35,18 @@ StitchImageProgram() {
      "algorithm (no graphics hardware is used).");
 
   add_option
-    ("f", "", 0,
-     "Apply a very simple filter in an attempt to smooth the results.",
-     &StitchImageProgram::dispatch_none, &_filter_output);
+    ("f", "factor", 0,
+     "Scale the output images internally by the indicated factor in each "
+     "dimension while generating them, and then reduce them to their final "
+     "size on output.  This provides a simple mechanism for filtering "
+     "the result.  The default is 1.0, or unfiltered, which runs relatively "
+     "quickly but can give highly aliased results; specifying a larger number "
+     "increases quality but also increases runtime and memory requirements "
+     "roughly by the square of factor.  Usually 2 or 3 provide satisfactory "
+     "results.",
+     &StitchImageProgram::dispatch_double, NULL, &_filter_factor);
+
+  _filter_factor = 1.0;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -48,7 +57,7 @@ StitchImageProgram() {
 void StitchImageProgram::
 run() {
   StitchImageRasterizer outputter;
-  outputter._filter_output = _filter_output;
+  outputter._filter_factor = _filter_factor;
   _command_file.process(outputter);
 }
 

+ 1 - 1
pandaapp/src/stitch/stitchImageProgram.h

@@ -36,7 +36,7 @@ public:
   void run();
 
 private:
-  bool _filter_output;
+  double _filter_factor;
 };
 
 #endif

+ 12 - 3
pandaapp/src/stitchbase/Sources.pp

@@ -3,7 +3,7 @@
 
 #begin ss_lib_target
   #define TARGET stitchbase
-  #define LOCAL_LIBS
+  #define LOCAL_LIBS pandaappbase
   #define OTHER_LIBS \
     progbase \
     putil:c express:c mathutil:c linmath:c pnmimage:c pnm:c panda:m
@@ -24,7 +24,11 @@
     stitchPerspectiveLens.h stitchPoint.cxx stitchPoint.h stitcher.cxx \
     stitcher.h triangle.cxx triangle.h triangleRasterizer.cxx \
     triangleRasterizer.h \
-    stitchParserDefs.h stitchParser.yxx stitchLexerDefs.h stitchLexer.lxx
+    stitchParserDefs.h stitchParser.yxx stitchLexerDefs.h stitchLexer.lxx \
+    stitchCylindricalScreen.cxx stitchCylindricalScreen.h \
+    stitchFlatScreen.cxx stitchFlatScreen.h \
+    stitchMultiScreen.cxx stitchMultiScreen.h \
+    stitchScreen.cxx stitchScreen.h
 
   #define INSTALL_HEADERS \
     config_stitch.h fixedPoint.h layeredImage.h morphGrid.h stitchCommand.h \
@@ -33,6 +37,11 @@
     stitchImageOutputter.h stitchImageRasterizer.h stitchLens.h \
     stitchLexerDefs.h stitchPSphereLens.h stitchParser.h \
     stitchParserDefs.h stitchPerspectiveLens.h stitchPoint.h \
-    stitcher.h triangle.h triangleRasterizer.h
+    stitcher.h triangle.h triangleRasterizer.h \
+    stitchCylindricalScreen.h \
+    stitchFlatScreen.h \
+    stitchMultiScreen.h \
+    stitchScreen.h
+
 
 #end ss_lib_target

+ 2 - 0
pandaapp/src/stitchbase/config_stitch.cxx

@@ -17,12 +17,14 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "config_stitch.h"
+#include "stitchScreen.h"
 
 #include <dconfig.h>
 
 Configure(config_stitch);
 
 ConfigureFn(config_stitch) {
+  StitchScreen::init_type();
 }
 
 string chan_cfg = config_stitch.GetString("chan-config", "single");

+ 1 - 1
pandaapp/src/stitchbase/config_stitch.h

@@ -19,7 +19,7 @@
 #ifndef CONFIG_STITCH_H
 #define CONFIG_STITCH_H
 
-#include <pandatoolbase.h>
+#include "pandaappbase.h"
 
 extern string chan_cfg;
 

+ 1 - 1
pandaapp/src/stitchbase/layeredImage.h

@@ -19,7 +19,7 @@
 #ifndef LAYEREDIMAGE_H
 #define LAYEREDIMAGE_H
 
-#include <pandatoolbase.h>
+#include "pandaappbase.h"
 
 #include <luse.h>
 #include <filename.h>

+ 111 - 0
pandaapp/src/stitchbase/stitchCommand.cxx

@@ -24,6 +24,8 @@
 #include "stitchCylindricalLens.h"
 #include "stitchPSphereLens.h"
 #include "stitchImageOutputter.h"
+#include "stitchCylindricalScreen.h"
+#include "stitchFlatScreen.h"
 #include "stitcher.h"
 
 #include <indent.h>
@@ -121,6 +123,22 @@ operator << (ostream &out, StitchCommand::Command c) {
     return out << "hpr";
     break;
 
+  case StitchCommand::C_pos:
+    return out << "pos";
+    break;
+
+  case StitchCommand::C_radius:
+    return out << "radius";
+    break;
+
+  case StitchCommand::C_angle:
+    return out << "angle";
+    break;
+
+  case StitchCommand::C_height:
+    return out << "height";
+    break;
+
   case StitchCommand::C_layers:
     return out << "layers";
     break;
@@ -129,6 +147,10 @@ operator << (ostream &out, StitchCommand::Command c) {
     return out << "stitch";
     break;
 
+  case StitchCommand::C_screen:
+    return out << "screen";
+    break;
+
   case StitchCommand::C_using:
     return out << "using";
     break;
@@ -289,6 +311,36 @@ get_str() const {
   return _str;
 }
 
+bool StitchCommand::
+has_name() const {
+  return (_params & P_name) != 0;
+}
+
+bool StitchCommand::
+has_number() const {
+  return (_params & P_number) != 0;
+}
+
+bool StitchCommand::
+has_point2d() const {
+  return (_params & P_point2d) != 0;
+}
+
+bool StitchCommand::
+has_point3d() const {
+  return (_params & P_point3d) != 0;
+}
+
+bool StitchCommand::
+has_color() const {
+  return (_params & P_color) != 0;
+}
+
+bool StitchCommand::
+has_str() const {
+  return (_params & P_str) != 0;
+}
+
 void StitchCommand::
 process(StitchImageOutputter &outputter, Stitcher *stitcher,
         StitchFile &file) {
@@ -322,6 +374,10 @@ process(StitchImageOutputter &outputter, Stitcher *stitcher,
     }
     outputter.add_stitcher(new_stitcher);
 
+  } else if (_command == C_screen) {
+    PT(StitchScreen) screen = create_screen();
+    outputter.add_screen(screen);
+
   } else if (_command == C_point3d) {
     if (stitcher != NULL) {
       stitcher->add_point(_name, get_vector3d());
@@ -636,6 +692,10 @@ create_image() {
       image->set_hpr((*ci)->get_point3d());
       break;
 
+    case C_pos:
+      image->set_pos((*ci)->get_point3d());
+      break;
+
     case C_layers:
       image->_layered_type = StitchImage::LT_separate;
       break;
@@ -652,3 +712,54 @@ create_image() {
   return image;
 }
 
+
+PT(StitchScreen) StitchCommand::
+create_screen() {
+  PT(StitchScreen) screen;
+
+  StitchCommand *cmd;
+  if (find_command(C_cylindrical) != NULL) {
+    StitchCylindricalScreen *cscreen = new StitchCylindricalScreen();
+    screen = cscreen;
+
+    cmd = find_command(C_radius);
+    if (cmd != NULL) {
+      cscreen->set_radius(cmd->get_number());
+    }
+    cmd = find_command(C_height);
+    if (cmd != NULL) {
+      LPoint2d p = cmd->get_point2d();
+      cscreen->set_height(p[0], p[1]);
+    }
+    cmd = find_command(C_angle);
+    if (cmd != NULL) {
+      LPoint2d p = cmd->get_point2d();
+      cscreen->set_angle(p[0], p[1]);
+    }
+    
+  } else {
+    screen = new StitchFlatScreen();
+  }
+
+  screen->set_name(get_name());
+
+  // Also look for pos and hpr and stuff.
+  Commands::const_iterator ci;
+  for (ci = _nested.begin(); ci != _nested.end(); ++ci) {
+    switch ((*ci)->_command) {
+    case C_hpr:
+      screen->set_hpr((*ci)->get_point3d());
+      break;
+
+    case C_pos:
+      screen->set_pos((*ci)->get_point3d());
+      break;
+
+    default:
+      break;
+    }
+  }
+
+  return screen;
+}
+

+ 20 - 6
pandaapp/src/stitchbase/stitchCommand.h

@@ -19,15 +19,16 @@
 #ifndef STITCHCOMMAND_H
 #define STITCHCOMMAND_H
 
-#include <pandatoolbase.h>
+#include "pandaappbase.h"
+#include "stitchScreen.h"
 
-#include <luse.h>
-
-#include <vector>
-#include <map>
+#include "luse.h"
+#include "pointerTo.h"
+#include "pvector.h"
 
 class StitchLens;
 class StitchImage;
+class StitchScreen;
 class StitchImageOutputter;
 class StitchFile;
 class Stitcher;
@@ -58,8 +59,13 @@ public:
     C_grid,
     C_untextured_color,
     C_hpr,
+    C_pos,
+    C_radius,
+    C_angle,
+    C_height,
     C_layers,
     C_stitch,
+    C_screen,
     C_using,
     C_user_command,
   };
@@ -90,6 +96,13 @@ public:
   Colord get_color() const;
   string get_str() const;
 
+  bool has_name() const;
+  bool has_number() const;
+  bool has_point2d() const;
+  bool has_point3d() const;
+  bool has_color() const;
+  bool has_str() const;
+
   StitchCommand *find_definition(const string &name);
 
   void process(StitchImageOutputter &outputter, Stitcher *stitcher,
@@ -110,6 +123,7 @@ private:
   LVecBase2d find_parameter(Command command, const LVecBase2d &dflt);
 
   StitchImage *create_image();
+  PT(StitchScreen) create_screen();
 
 
   StitchCommand *_parent;
@@ -139,7 +153,7 @@ private:
   // This will only get filled in by make_lens().
   StitchLens *_lens;
 
-  typedef vector<StitchCommand *> Commands;
+  typedef pvector<StitchCommand *> Commands;
   Commands _using;
   Commands _nested;
 };

+ 1 - 1
pandaapp/src/stitchbase/stitchCommandReader.h

@@ -19,7 +19,7 @@
 #ifndef STITCHCOMMANDREADER_H
 #define STITCHCOMMANDREADER_H
 
-#include <pandatoolbase.h>
+#include "pandaappbase.h"
 
 #include "stitchFile.h"
 

+ 182 - 0
pandaapp/src/stitchbase/stitchCylindricalScreen.cxx

@@ -0,0 +1,182 @@
+// Filename: stitchCylindricalScreen.cxx
+// Created by:  drose (16Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "stitchCylindricalScreen.h"
+#include "deg_2_rad.h"
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchCylindricalScreen::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+StitchCylindricalScreen::
+StitchCylindricalScreen() {
+  // The full-circle range is -pi to pi; we round up here to ensure we
+  // get the full circle.
+  _start_angle = -4.0;
+  _end_angle = 4.0;
+
+  _bottom = -1.0;
+  _top = 1.0;
+  _radius = 1.0;
+  _flags = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchCylindricalScreen::set_angle
+//       Access: Public
+//  Description: Sets the angular range of the screen.  The range is
+//               in degrees, from -180 to 180, where 0 degrees is
+//               directly ahead, -90 is to the left, and +90 is to the
+//               right.
+//
+//               If this is unset, the default is a full-circle
+//               cylinder.
+////////////////////////////////////////////////////////////////////
+void StitchCylindricalScreen::
+set_angle(double start, double end) {
+  // We store the angles in radians.
+  _start_angle = deg_2_rad(start);
+  _end_angle = deg_2_rad(end);
+  _flags |= F_angle;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchCylindricalScreen::set_height
+//       Access: Public
+//  Description: Sets the bottom and top limits of the screen.  These
+//               are the heights above (or below) the XY plane for the
+//               bottom edge and top edge of the screen.
+//
+//               If this is unset, the default is an infinitely tall
+//               cylinder.
+////////////////////////////////////////////////////////////////////
+void StitchCylindricalScreen::
+set_height(double bottom, double top) {
+  _bottom = bottom;
+  _top = top;
+  _flags |= F_height;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchCylindricalScreen::set_radius
+//       Access: Public
+//  Description: Sets the radius of the screen.  The default is 1.0.
+////////////////////////////////////////////////////////////////////
+void StitchCylindricalScreen::
+set_radius(double radius) {
+  _radius = radius;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchCylindricalScreen::compute_intersect
+//       Access: Protected, Virtual
+//  Description: Computes the intersection point for the ray beginning
+//               at the indicated origin point and continuing in the
+//               indicated direction, to infinity.  The return value
+//               is a number >= 0.0 that indicates the parametric
+//               intersection point along the ray with the screen
+//               geometry, or a number < 0.0 if there is no
+//               intersection with the screen.
+////////////////////////////////////////////////////////////////////
+double StitchCylindricalScreen::
+compute_intersect(const LPoint3d &origin, const LVector3d &direction) const {
+  LPoint3d p = origin * _inv_transform;
+  LVector3d d = direction * _inv_transform;
+
+  // The cylinder is always centered on the origin with its axis
+  // parallel to the Z axis.  Project our ray into the XY plane and
+  // determine the point of intersection with the circular
+  // cross-section.
+
+  double Px = p[0];
+  double Py = p[1];
+  double Dx = d[0];
+  double Dy = d[1];
+
+  // Now use the quadratic equation to solve for the intersection of
+  // the line passing thing p2 and (p2+d2), and the circle centered at
+  // the origin with the radius _radius.
+
+  double a = Dx * Dx + Dy * Dy;
+  double b = 2 * (Px * Dx + Py * Dy);
+  double c = Px * Px + Py * Py - _radius * _radius;
+
+  // If the radical is negative, there is no intersection with the
+  // circle.
+  double radical = b * b - 4.0 * a * c;
+  if (radical < 0.0) {
+    return -1.0;
+  }
+
+  // There are two possible intersection points.  We have to consider
+  // both, and if both are valid, we return the closer.
+  double sqrt_radical = sqrt(radical);
+  double t1 = (-b + sqrt_radical) / (2.0 * a);
+  double t2 = (-b - sqrt_radical) / (2.0 * a);
+
+  validate_point(t1, p, d);
+  validate_point(t2, p, d);
+
+  if (t1 >= 0.0) {
+    if (t2 >= 0.0) {
+      return min(t1, t2);
+    } else {
+      return t1;
+    }
+  } else {
+    return t2;
+  }
+}
+
+// Check that the given intersection point defines a point in front of
+// the ray and on the surface of the cylindrical screen.  If it is off
+// the screen, resets t to -1; otherwise, leaves it alone.
+void StitchCylindricalScreen::
+validate_point(double &t,
+               const LPoint3d &origin, 
+               const LVector3d &direction) const {
+  // Only test points that are in front of the ray anyway.
+  if (t >= 0.0) {
+    // Now get the 3-d point of intersection.
+    LPoint3d p = origin + direction * t;
+
+    // If this is above the top of the cylinder, or below the bottom
+    // of it, there's no intersection.
+    if ((_flags & F_height) != 0) {
+      if (p[2] < _bottom || p[2] > _top) {
+        t = -1.0;
+        return;
+      }
+    }
+
+    if ((_flags & F_angle) != 0) {
+      // Project the point into the XY plane and get the angle from
+      // the Y axis, in radians.
+      double angle = atan2(p[0], p[1]);
+
+      // If the angle is outside of the range of the screen, reject it
+      // also.
+      if (angle < _start_angle || angle > _end_angle) {
+        t = -1.0;
+        return;
+      }
+    }
+  }
+}

+ 63 - 0
pandaapp/src/stitchbase/stitchCylindricalScreen.h

@@ -0,0 +1,63 @@
+// Filename: stitchCylindricalScreen.h
+// Created by:  drose (16Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 STITCHCYLINDRICALSCREEN_H
+#define STITCHCYLINDRICALSCREEN_H
+
+#include "stitchScreen.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : StitchCylindricalScreen
+// Description : A cylindrical screen shape, axis-aligned with the Z
+//               axis (which is normally the up axis), and with an
+//               arbitrary height and radius.  The screen may also
+//               consist of only a portion of the cylinder, specified
+//               by an angle limit.
+////////////////////////////////////////////////////////////////////
+class StitchCylindricalScreen : public StitchScreen {
+public:
+  StitchCylindricalScreen();
+
+  void set_angle(double start, double end);
+  void set_height(double bottom, double top);
+  void set_radius(double radius);
+
+protected:
+  virtual double compute_intersect(const LPoint3d &origin, 
+                                   const LVector3d &direction) const;
+
+  void validate_point(double &t,
+                      const LPoint3d &origin, 
+                      const LVector3d &direction) const;
+
+private:
+  double _start_angle, _end_angle;
+  double _bottom, _top;
+  double _radius;
+
+  enum {
+    F_angle   = 0x001,
+    F_height  = 0x002
+  };
+
+  int _flags;
+};
+
+#endif
+
+

+ 69 - 0
pandaapp/src/stitchbase/stitchFlatScreen.cxx

@@ -0,0 +1,69 @@
+// Filename: stitchFlatScreen.cxx
+// Created by:  drose (16Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "stitchFlatScreen.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchFlatScreen::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+StitchFlatScreen::
+StitchFlatScreen() :
+  _plane(LVector3d::back(), LPoint3d::origin() + LVector3d::forward())
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchFlatScreen::set_plane
+//       Access: Public
+//  Description: Specifies the plane that defines the screen.  This
+//               plane may, of course, be transformed by whatever
+//               transform matrix is specified via set_transform(),
+//               etc.
+//
+//               The default plane is one unit along the forward axis,
+//               facing back toward the origin.
+////////////////////////////////////////////////////////////////////
+void StitchFlatScreen::
+set_plane(const Planed &plane) {
+  _plane = plane;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchFlatScreen::compute_intersect
+//       Access: Protected, Virtual
+//  Description: Computes the intersection point for the ray beginning
+//               at the indicated origin point and continuing in the
+//               indicated direction, to infinity.  The return value
+//               is a number >= 0.0 that indicates the parametric
+//               intersection point along the ray with the screen
+//               geometry, or a number < 0.0 if there is no
+//               intersection with the screen.
+////////////////////////////////////////////////////////////////////
+double StitchFlatScreen::
+compute_intersect(const LPoint3d &origin, const LVector3d &direction) const {
+  LPoint3d p = origin * _inv_transform;
+  LVector3d d = direction * _inv_transform;
+
+  double t;
+  if (!_plane.intersects_line(t, p, d)) {
+    t = -1.0;
+  }
+  return t;
+}

+ 46 - 0
pandaapp/src/stitchbase/stitchFlatScreen.h

@@ -0,0 +1,46 @@
+// Filename: stitchFlatScreen.h
+// Created by:  drose (16Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 STITCHFLATSCREEN_H
+#define STITCHFLATSCREEN_H
+
+#include "stitchScreen.h"
+#include "plane.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : StitchFlatScreen
+// Description : A simple flat screen.  This is really an infinite
+//               plane.
+////////////////////////////////////////////////////////////////////
+class StitchFlatScreen : public StitchScreen {
+public:
+  StitchFlatScreen();
+
+  void set_plane(const Planed &plane);
+
+protected:
+  virtual double compute_intersect(const LPoint3d &origin, 
+                                   const LVector3d &direction) const;
+
+private:
+  Planed _plane;
+};
+
+#endif
+
+

+ 127 - 31
pandaapp/src/stitchbase/stitchImage.cxx

@@ -20,8 +20,8 @@
 #include "stitchLens.h"
 #include "layeredImage.h"
 
-#include <compose_matrix.h>
-#include <rotate_to.h>
+#include "compose_matrix.h"
+#include "rotate_to.h"
 
 StitchImage::
 StitchImage(const string &name, const string &filename,
@@ -32,13 +32,15 @@ StitchImage(const string &name, const string &filename,
   _size_pixels(size_pixels),
   _pixels_per_mm(pixels_per_mm),
   _film_offset_mm(film_offset_mm),
-  _rotate(LMatrix3d::ident_mat()),
-  _inv_rotate(LMatrix3d::ident_mat()),
+  _transform(LMatrix4d::ident_mat()),
+  _inv_transform(LMatrix4d::ident_mat()),
   _filename(filename),
   _name(name)
 {
   _size_mm.set((_size_pixels[0] - 1.0) / _pixels_per_mm[0],
                (_size_pixels[1] - 1.0) / _pixels_per_mm[1]);
+  _orig_size_pixels = _size_pixels;
+  _orig_pixels_per_mm = _pixels_per_mm;
 
   // There are several coordinate systems to talk about points on the
   // image.
@@ -55,16 +57,6 @@ StitchImage(const string &name, const string &filename,
   // film_offset_mm-size_mm at the lower-left, to
   // film_offset_mm+size_mm at the upper-right.
 
-  LVector2d pixels_per_uv(_size_pixels[0] - 1.0, _size_pixels[1] - 1.0);
-
-  _pixels_to_uv =
-    LMatrix3d::translate_mat(LVector2d(0.0, -pixels_per_uv[1])) *
-    LMatrix3d::scale_mat(1.0 / pixels_per_uv[0], -1.0 / pixels_per_uv[1]);
-
-  _uv_to_pixels =
-    LMatrix3d::scale_mat(pixels_per_uv[0], -pixels_per_uv[1]) *
-    LMatrix3d::translate_mat(LVector2d(0.0, pixels_per_uv[1]));
-
   /*
   nout << "_pixels_to_uv * _uv_to_pixels is\n"
        << _pixels_to_uv * _uv_to_pixels << "\n"
@@ -88,8 +80,7 @@ StitchImage(const string &name, const string &filename,
     LMatrix3d::scale_mat(1.0 / mm_per_uv[0], 1.0 / mm_per_uv[1]) *
     LMatrix3d::translate_mat(LVector2d(0.5, 0.5) + _film_offset_mm);
 
-  _pixels_to_mm = _pixels_to_uv * _uv_to_mm;
-  _mm_to_pixels = _mm_to_uv * _uv_to_pixels;
+  setup_pixel_scales();
 
   _show_points = false;
   setup_grid(2, 2);
@@ -98,6 +89,9 @@ StitchImage(const string &name, const string &filename,
   _untextured_color.set(1.0, 1.0, 1.0, 1.0);
   _index = 0;
   _hpr_set = false;
+  _pos_set = false;
+  _hpr.set(0.0, 0.0, 0.0);
+  _pos.set(0.0, 0.0, 0.0);
   _layered_type = LT_flat;
   _layer_index = 0;
   _layered_image = NULL;
@@ -194,6 +188,7 @@ close_layer(bool nonempty) {
         _layer_index++;
         sprintf(buff, _filename.c_str(), _layer_index);
         nout << "Writing layer " << _layer_name << " as " << buff << "\n";
+        resize_data();
         result = _data->write(buff);
       }
     }
@@ -204,6 +199,7 @@ close_layer(bool nonempty) {
       result = false;
     } else {
       if (nonempty) {
+        resize_data();
         _layered_image->add_layer(_layer_name, LVector2d(0.0, 0.0),
                                   _data);
         _data = NULL;
@@ -232,6 +228,7 @@ close_output_file() {
       result = false;
     } else {
       nout << "Writing " << _filename << "\n";
+      resize_data();
       result = _data->write(_filename);
     }
   }
@@ -242,25 +239,51 @@ close_output_file() {
 
 void StitchImage::
 clear_transform() {
-  _rotate = LMatrix3d::ident_mat();
-  _inv_rotate = LMatrix3d::ident_mat();
+  _transform = LMatrix3d::ident_mat();
+  _inv_transform = LMatrix3d::ident_mat();
+  _hpr_set = false;
+  _pos_set = false;
+  _hpr.set(0.0, 0.0, 0.0);
+  _pos.set(0.0, 0.0, 0.0);
   _morph.clear();
 }
 
 void StitchImage::
-set_transform(const LMatrix3d &rot) {
-  _rotate = rot;
-  _inv_rotate = invert(rot);
+set_transform(const LMatrix4d &trans) {
+  _transform = trans;
+  _inv_transform = invert(trans);
+  LVecBase3d scale;
+  decompose_matrix(_transform, scale, _hpr, _pos);
+  _hpr_set = false;
+  _pos_set = false;
 }
 
 void StitchImage::
 set_hpr(const LVecBase3d &hpr) {
-  compose_matrix(_rotate, LVecBase3d(1.0, 1.0, 1.0), hpr);
-  _inv_rotate = invert(_rotate);
+  compose_matrix(_transform, LVecBase3d(1.0, 1.0, 1.0), hpr, _pos);
+  _inv_transform.invert_from(_transform);
   _hpr_set = true;
   _hpr = hpr;
 }
 
+void StitchImage::
+set_pos(const LPoint3d &pos) {
+  compose_matrix(_transform, LVecBase3d(1.0, 1.0, 1.0), _hpr, pos);
+  _inv_transform.invert_from(_transform);
+  _pos_set = true;
+  _pos = pos;
+}
+
+const LVecBase3d &StitchImage::
+get_hpr() const {
+  return _hpr;
+}
+
+const LPoint3d &StitchImage::
+get_pos() const {
+  return _pos;
+}
+
 void StitchImage::
 show_points(double radius, const Colord &color) {
   _show_points = true;
@@ -314,12 +337,12 @@ get_size_mm() const {
 LVector3d StitchImage::
 extrude(const LPoint2d &point_uv) const {
   LPoint2d p = _morph.morph_out(point_uv);
-  return _lens->extrude(p * _uv_to_mm, _size_mm[0]) * _rotate;
+  return _lens->extrude(p * _uv_to_mm, _size_mm[0]) * _transform;
 }
 
 LPoint2d StitchImage::
 project(const LVector3d &vec) const {
-  LPoint2d m = _lens->project(vec * _inv_rotate, _size_mm[0]);
+  LPoint2d m = _lens->project(vec * _inv_transform, _size_mm[0]);
   return _morph.morph_in(m * _mm_to_uv);
 }
 
@@ -342,7 +365,7 @@ draw_triangle(TriangleRasterizer &rast, const RasterizerVertex *v0,
 void StitchImage::
 pick_up_singularity(TriangleRasterizer &rast, StitchImage *input) {
   _lens->pick_up_singularity(rast, _mm_to_pixels, _pixels_to_mm,
-                             _rotate, _size_mm[0], input);
+                             _transform.get_upper_3(), _size_mm[0], input);
 }
 
 void StitchImage::
@@ -350,6 +373,26 @@ add_point(const string &name, const LPoint2d &pixel) {
   _points[name] = pixel * _pixels_to_uv;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: StitchImage::set_output_scale_factor
+//       Access: Private
+//  Description: Sets up the image to inflate its output image by the
+//               given factor in each dimension during rasterization,
+//               and then reduce it back to its original size just
+//               before writing it out, as a poor man's pixel filter.
+//
+//               This may only be called before open_output_file() has
+//               been called.
+////////////////////////////////////////////////////////////////////
+void StitchImage::
+set_output_scale_factor(double factor) {
+  assert(_data == (PNMImage *)NULL);
+
+  _size_pixels = _orig_size_pixels * factor;
+  _pixels_per_mm = _orig_pixels_per_mm * factor;
+  setup_pixel_scales();
+}
+
 
 void StitchImage::
 output(ostream &out) const {
@@ -357,12 +400,65 @@ output(ostream &out) const {
       << get_size_pixels() << " pixels, or " << get_size_mm()
       << " mm\n";
 
-  LVecBase3d scale, hpr;
-  if (decompose_matrix(_rotate, scale, hpr)) {
-    out << "rotate " << hpr << "\n";
+  LVecBase3d scale, hpr, trans;
+  if (decompose_matrix(_transform, scale, hpr, trans)) {
+    if (!scale.almost_equal(LVecBase3d(1.0, 1.0, 1.0))) {
+      out << "scale " << scale << "\n";
+    }
+    out << "hpr " << hpr << "\n";
+    if (!trans.almost_equal(LVecBase3d::zero())) {
+      out << "translate " << trans << "\n";
+    }
   } else {
-    out << "Invalid rotation transform:\n";
-    _rotate.write(out);
+    out << "Invalid transform:\n";
+    _transform.write(out);
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: StitchImage::setup_pixel_scales
+//       Access: Private
+//  Description: Sets up the pixel-based transform matrices, according
+//               to _pixel_size and _pixels_per_mm.
+////////////////////////////////////////////////////////////////////
+void StitchImage::
+setup_pixel_scales() {
+  LVector2d pixels_per_uv(_size_pixels[0] - 1.0, _size_pixels[1] - 1.0);
+
+  _pixels_to_uv =
+    LMatrix3d::translate_mat(LVector2d(0.0, -pixels_per_uv[1])) *
+    LMatrix3d::scale_mat(1.0 / pixels_per_uv[0], -1.0 / pixels_per_uv[1]);
+
+  _uv_to_pixels =
+    LMatrix3d::scale_mat(pixels_per_uv[0], -pixels_per_uv[1]) *
+    LMatrix3d::translate_mat(LVector2d(0.0, pixels_per_uv[1]));
+
+  _pixels_to_mm = _pixels_to_uv * _uv_to_mm;
+  _mm_to_pixels = _mm_to_uv * _uv_to_pixels;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchImage::resize_data
+//       Access: Private
+//  Description: Resizes the image generated in _data back to
+//               _orig_size_pixels, if it has been generated larger,
+//               int preparation to writing it out.
+////////////////////////////////////////////////////////////////////
+void StitchImage::
+resize_data() {
+  assert(_data != (PNMImage *)NULL);
+  if (_orig_size_pixels == _size_pixels) {
+    return;
+  }
+
+  PNMImage *small = 
+    new PNMImage(_orig_size_pixels[0], _orig_size_pixels[1], 
+                 _data->get_color_type());
+
+  cerr << "Filtering to " << small->get_x_size() << " by " 
+       << small->get_y_size() << "\n";
+
+  small->box_filter_from(1.0, *_data);
+  delete _data;
+  _data = small;
+}

+ 15 - 3
pandaapp/src/stitchbase/stitchImage.h

@@ -19,7 +19,7 @@
 #ifndef STITCHIMAGE_H
 #define STITCHIMAGE_H
 
-#include <pandatoolbase.h>
+#include "pandaappbase.h"
 
 #include "stitchPoint.h"
 #include "morphGrid.h"
@@ -67,8 +67,11 @@ public:
   bool close_output_file();
 
   void clear_transform();
-  void set_transform(const LMatrix3d &rot);
+  void set_transform(const LMatrix4d &transform);
   void set_hpr(const LVecBase3d &hpr);
+  void set_pos(const LPoint3d &pos);
+  const LVecBase3d &get_hpr() const;
+  const LPoint3d &get_pos() const;
 
   void show_points(double radius, const Colord &color);
   void setup_grid(int x_verts, int y_verts);
@@ -106,6 +109,7 @@ public:
                            StitchImage *input);
 
   void add_point(const string &name, const LPoint2d &pixel);
+  void set_output_scale_factor(double factor);
 
   void output(ostream &out) const;
 
@@ -119,6 +123,8 @@ public:
   LMatrix3d _pixels_to_uv, _uv_to_pixels;
   bool _hpr_set;
   LVecBase3d _hpr;
+  bool _pos_set;
+  LPoint3d _pos;
 
   enum LayeredType {
     LT_flat,        // One flat image--no layers.
@@ -134,7 +140,7 @@ public:
 
   typedef map<string, LPoint2d> Points;
   Points _points;
-  LMatrix3d _rotate, _inv_rotate;
+  LMatrix4d _transform, _inv_transform;
   MorphGrid _morph;
 
   // This index number is filled in by the Stitcher.  It allows us to
@@ -142,6 +148,10 @@ public:
   // file.
   int _index;
 
+private:
+  void setup_pixel_scales();
+  void resize_data();
+
 private:
   Filename _filename;
   string _name;
@@ -150,6 +160,8 @@ private:
   int _layer_index;
   string _layer_name;
   LayeredImage *_layered_image;
+  LVecBase2d _orig_size_pixels;
+  LVecBase2d _orig_pixels_per_mm;
 };
 
 inline ostream &operator << (ostream &out, const StitchImage &i) {

+ 4 - 2
pandaapp/src/stitchbase/stitchImageCommandOutput.cxx

@@ -96,9 +96,11 @@ fill_image_cmd(StitchCommand *image_cmd, StitchImage *image) {
 
   image->_lens->make_lens_command(image_cmd);
 
-  LVecBase3d scale, hpr;
-  if (decompose_matrix(image->_rotate, scale, hpr)) {
+  LVecBase3d scale, hpr, trans;
+  if (decompose_matrix(image->_transform, scale, hpr, trans)) {
     cmd = new StitchCommand(image_cmd, StitchCommand::C_hpr);
     cmd->set_point3d(hpr);
+
+    //**** Do something with translate here.
   }
 }

+ 24 - 0
pandaapp/src/stitchbase/stitchImageOutputter.cxx

@@ -19,10 +19,34 @@
 #include "stitchImageOutputter.h"
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: StitchImageOutputter::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
 StitchImageOutputter::
 StitchImageOutputter() {
+  _screen = new StitchMultiScreen;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: StitchImageOutputter::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
 StitchImageOutputter::
 ~StitchImageOutputter() {
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchImageOutputter::add_screen
+//       Access: Public
+//  Description: Adds a screen to the list of screens projected onto.
+//               If there are no screens, the default is to project
+//               the images to infinity; otherwise, the screens are
+//               used.
+////////////////////////////////////////////////////////////////////
+void StitchImageOutputter::
+add_screen(StitchScreen *screen) {
+  _screen->add_screen(screen);
+}

+ 25 - 2
pandaapp/src/stitchbase/stitchImageOutputter.h

@@ -19,11 +19,30 @@
 #ifndef STITCHIMAGEOUTPUTTER_H
 #define STITCHIMAGEOUTPUTTER_H
 
+#include "pandaappbase.h"
+
+#include "stitchMultiScreen.h"
+#include "luse.h"
+#include "pointerTo.h"
+
 class StitchImage;
 class Stitcher;
 
-#include <luse.h>
-
+////////////////////////////////////////////////////////////////////
+//       Class : StitchImageOutputter
+// Description : This is an abstract base class defining the interface
+//               to accept a number of input images and process them,
+//               possibly stitching them together based on their
+//               points in common, and then generating a number of
+//               output images.
+//
+//               This is the highest level of interaction with this
+//               module; it corresponds to the action performed by a
+//               stitch-image, stitch-viewer, or stitch-command
+//               program (and the distinction between the three
+//               programs is primarily a question of which
+//               specialization of StitchImageOutputter they use).
+////////////////////////////////////////////////////////////////////
 class StitchImageOutputter {
 public:
   StitchImageOutputter();
@@ -32,8 +51,12 @@ public:
   virtual void add_input_image(StitchImage *image)=0;
   virtual void add_output_image(StitchImage *image)=0;
   virtual void add_stitcher(Stitcher *stitcher)=0;
+  void add_screen(StitchScreen *screen);
 
   virtual void execute()=0;
+
+protected:
+  PT(StitchMultiScreen) _screen;
 };
 
 #endif

+ 50 - 32
pandaapp/src/stitchbase/stitchImageRasterizer.cxx

@@ -25,7 +25,7 @@
 
 StitchImageRasterizer::
 StitchImageRasterizer() {
-  _filter_output = true;
+  _filter_factor = 1.0;
 }
 
 
@@ -36,6 +36,7 @@ add_input_image(StitchImage *image) {
 
 void StitchImageRasterizer::
 add_output_image(StitchImage *image) {
+  image->set_output_scale_factor(_filter_factor);
   _output_images.push_back(image);
 }
 
@@ -119,7 +120,7 @@ draw_image(StitchImage *output, StitchImage *input) {
   TriangleRasterizer rast;
   rast._output = output->_data;
   rast._input = input;
-  rast._filter_output = _filter_output;
+  rast._filter_output = false;
   rast._untextured_color = input->_untextured_color;
 
   int x_verts = input->get_x_verts();
@@ -128,37 +129,54 @@ draw_image(StitchImage *output, StitchImage *input) {
   // Build up the table of verts.
   typedef vector<RasterizerVertex> VRow;
   typedef vector<VRow> VTable;
-  VTable _table(x_verts, VRow());
+  VTable table(x_verts, VRow());
 
   int xi, yi;
   for (xi = 0; xi < x_verts; xi++) {
-    _table[xi] = VRow(y_verts, RasterizerVertex());
+    table[xi] = VRow(y_verts, RasterizerVertex());
 
     for (yi = 0; yi < y_verts; yi++) {
       LVector3d space = input->get_grid_vector(xi, yi);
       double alpha = input->get_grid_alpha(xi, yi);
-      LPoint2d to = output->project(space);
-      LPoint2d from = input->get_grid_uv(xi, yi);
-
-      _table[xi][yi]._p = to * output->_uv_to_pixels;
-      _table[xi][yi]._uv = from;
-      _table[xi][yi]._space = space * output->_inv_rotate;
-      _table[xi][yi]._alpha = alpha;
-
-      _table[xi][yi]._space = normalize(_table[xi][yi]._space);
-
-      // We assign one bit for each quadrant the vertex may be out of
-      // bounds.  If all three vertices of a triangle are out in the
-      // same quadrant, then the entire triangle is out of bounds.
-      _table[xi][yi]._visibility =
-        ((to[0] < 0.0) |
-         ((to[0] > 1.0) << 1) |
-         ((to[1] < 0.0) << 2) |
-         ((to[1] > 1.0) << 3) |
-         ((from[0] < 0.0) << 4) |
-         ((from[0] > 1.0) << 5) |
-         ((from[1] < 0.0) << 6) |
-         ((from[1] > 1.0) << 7));
+      LPoint3d point;
+      if (!_screen->intersect(point, input->get_pos(), space)) {
+        // No intersection with the screen.  What should we do now?
+        LPoint2d from = input->get_grid_uv(xi, yi);
+
+        table[xi][yi]._p.set(0.0, 0.0);
+        table[xi][yi]._uv = from;
+        table[xi][yi]._space = point * output->_inv_transform;
+        table[xi][yi]._alpha = alpha;
+        
+        table[xi][yi]._space = normalize(table[xi][yi]._space);
+
+        // Tag any triangle including this vertex as totally invalid.
+        table[xi][yi]._visibility = -1;
+
+      } else {
+        LPoint2d to = output->project(point - output->get_pos());
+        LPoint2d from = input->get_grid_uv(xi, yi);
+        
+        table[xi][yi]._p = to * output->_uv_to_pixels;
+        table[xi][yi]._uv = from;
+        table[xi][yi]._space = point * output->_inv_transform;
+        table[xi][yi]._alpha = alpha;
+        
+        table[xi][yi]._space = normalize(table[xi][yi]._space);
+
+        // We assign one bit for each quadrant the vertex may be out of
+        // bounds.  If all three vertices of a triangle are out in the
+        // same quadrant, then the entire triangle is out of bounds.
+        table[xi][yi]._visibility =
+          ((to[0] < 0.0) |
+           ((to[0] > 1.0) << 1) |
+           ((to[1] < 0.0) << 2) |
+           ((to[1] > 1.0) << 3) |
+           ((from[0] < 0.0) << 4) |
+           ((from[0] > 1.0) << 5) |
+           ((from[1] < 0.0) << 6) |
+           ((from[1] > 1.0) << 7));
+      }
     }
   }
 
@@ -168,13 +186,13 @@ draw_image(StitchImage *output, StitchImage *input) {
   for (yi = 0; yi < y_verts - 1; yi++) {
     for (xi = 0; xi < x_verts - 1; xi++) {
       output->draw_triangle(rast,
-                            &_table[xi][yi],
-                            &_table[xi][yi + 1],
-                            &_table[xi + 1][yi + 1]);
+                            &table[xi][yi],
+                            &table[xi][yi + 1],
+                            &table[xi + 1][yi + 1]);
       output->draw_triangle(rast,
-                            &_table[xi][yi],
-                            &_table[xi + 1][yi + 1],
-                            &_table[xi + 1][yi]);
+                            &table[xi][yi],
+                            &table[xi + 1][yi + 1],
+                            &table[xi + 1][yi]);
     }
   }
   output->pick_up_singularity(rast, input);

+ 1 - 1
pandaapp/src/stitchbase/stitchImageRasterizer.h

@@ -36,7 +36,7 @@ public:
 
   virtual void execute();
 
-  bool _filter_output;
+  double _filter_factor;
 
 protected:
   void draw_points(StitchImage *output, StitchImage *input,

+ 28 - 0
pandaapp/src/stitchbase/stitchLexer.lxx

@@ -284,6 +284,22 @@ NUMERIC         ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
   return NUMBER; 
 }
 
+{NUMERIC}['] { 
+  // An integer or floating-point number followed by feet symbol.
+  accept(); 
+  stitchyylval.number = atof(stitchyytext); 
+  stitchyylval.str = yytext;
+  return NUMBER_FEET; 
+}
+
+{NUMERIC}["] { 
+  // An integer or floating-point number followed by inches symbol.
+  accept(); 
+  stitchyylval.number = atof(stitchyytext); 
+  stitchyylval.str = yytext;
+  return NUMBER_INCHES; 
+}
+
 ["] {
   // Quoted string.
   accept();
@@ -339,10 +355,20 @@ NUMERIC         ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
     return KW_UNTEXTURED_COLOR;
   } else if (cmp_nocase_uh(str, "hpr") == 0) {
     return KW_HPR;
+  } else if (cmp_nocase_uh(str, "pos") == 0) {
+    return KW_POS;
+  } else if (cmp_nocase_uh(str, "radius") == 0) {
+    return KW_RADIUS;
+  } else if (cmp_nocase_uh(str, "angle") == 0) {
+    return KW_ANGLE;
+  } else if (cmp_nocase_uh(str, "height") == 0) {
+    return KW_HEIGHT;
   } else if (cmp_nocase_uh(str, "layers") == 0) {
     return KW_LAYERS;
   } else if (cmp_nocase_uh(str, "stitch") == 0) {
     return KW_STITCH;
+  } else if (cmp_nocase_uh(str, "screen") == 0) {
+    return KW_SCREEN;
   } else if (cmp_nocase_uh(str, "points") == 0) {
     return KW_POINTS;
   } else if (cmp_nocase_uh(str, "using") == 0) {
@@ -353,6 +379,8 @@ NUMERIC         ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
     return KW_MM;
   } else if (cmp_nocase_uh(str, "cm") == 0) {
     return KW_CM;
+  } else if (cmp_nocase_uh(str, "ft") == 0) {
+    return KW_FT;
   } else if (cmp_nocase_uh(str, "p") == 0) {
     return KW_P;
   }

+ 1 - 1
pandaapp/src/stitchbase/stitchLexerDefs.h

@@ -19,7 +19,7 @@
 #ifndef STITCHLEXERDEFS_H
 #define STITCHLEXERDEFS_H
 
-#include <pandatoolbase.h>
+#include "pandaappbase.h"
 
 void stitch_init_lexer(istream &in, const string &filename);
 int stitch_error_count();

+ 127 - 0
pandaapp/src/stitchbase/stitchMultiScreen.cxx

@@ -0,0 +1,127 @@
+// Filename: stitchMultiScreen.cxx
+// Created by:  drose (16Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "stitchMultiScreen.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchMultiScreen::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+StitchMultiScreen::
+StitchMultiScreen() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchMultiScreen::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+StitchMultiScreen::
+~StitchMultiScreen() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchMultiScreen::add_screen
+//       Access: Public
+//  Description: Adds a new screen to the set of screens in the set.
+////////////////////////////////////////////////////////////////////
+void StitchMultiScreen::
+add_screen(StitchScreen *screen) {
+  _screens.insert(screen);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchMultiScreen::clear_screens
+//       Access: Public
+//  Description: Empties the set of screens from the set.
+////////////////////////////////////////////////////////////////////
+void StitchMultiScreen::
+clear_screens() {
+  _screens.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchMultiScreen::is_empty
+//       Access: Public
+//  Description: Returns true if there are no screens in the set, or
+//               false if there is at least one.
+////////////////////////////////////////////////////////////////////
+bool StitchMultiScreen::
+is_empty() const {
+  return _screens.empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchMultiScreen::intersect
+//       Access: Public, Virtual
+//  Description: Determines the intersection point of a ray starting
+//               at the indicated origin, and continuing infinitely in
+//               the indicated direction, with the screen.
+//
+//               If there is no intersection, leaves result undefined
+//               and returns false.  If there is an intersection, sets
+//               result to the intersection point and returns true.
+////////////////////////////////////////////////////////////////////
+bool StitchMultiScreen::
+intersect(LPoint3d &result, 
+          const LPoint3d &origin,
+          const LVector3d &direction) const {
+  if (_screens.empty()) {
+    // If we have no screens, the direction is the same as the result.
+    // This acts as if we have an infinitely large screen at infinity.
+    result = direction;
+    return true;
+  }
+
+  return StitchScreen::intersect(result, origin, direction);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchMultiScreen::compute_intersect
+//       Access: Protected, Virtual
+//  Description: Computes the intersection point for the ray beginning
+//               at the indicated origin point and continuing in the
+//               indicated direction, to infinity.  The return value
+//               is a number >= 0.0 that indicates the parametric
+//               intersection point along the ray with the screen
+//               geometry, or a number < 0.0 if there is no
+//               intersection with the screen.
+////////////////////////////////////////////////////////////////////
+double StitchMultiScreen::
+compute_intersect(const LPoint3d &origin, const LVector3d &direction) const {
+  LPoint3d p = origin * _inv_transform;
+  LVector3d d = direction * _inv_transform;
+  double best = -1.0;
+
+  // Walk through all of our screens and find the closest valid
+  // intersection point.
+  Screens::const_iterator si;
+  for (si = _screens.begin(); si != _screens.end(); ++si) {
+    double t = (*si)->compute_intersect(p, d);
+    if (t >= 0.0) {
+      if (best >= 0.0) {
+        best = min(best, t);
+      } else {
+        best = t;
+      }
+    }
+  }
+
+  return best;
+}

+ 59 - 0
pandaapp/src/stitchbase/stitchMultiScreen.h

@@ -0,0 +1,59 @@
+// Filename: stitchMultiScreen.h
+// Created by:  drose (16Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 STITCHMULTISCREEN_H
+#define STITCHMULTISCREEN_H
+
+#include "stitchScreen.h"
+#include "pset.h"
+#include "pointerTo.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : StitchMultiScreen
+// Description : A composite of one or more simple screens.
+//
+//               If there is at least one screen in the set, the
+//               StitchMultiScreen behaves like the intersection of
+//               all of the screens.  If there are no screens, it
+//               behaves like an infinitely large screen at infinity.
+////////////////////////////////////////////////////////////////////
+class StitchMultiScreen : public StitchScreen {
+public:
+  StitchMultiScreen();
+  virtual ~StitchMultiScreen();
+
+  void add_screen(StitchScreen *screen);
+  void clear_screens();
+  bool is_empty() const;
+
+  virtual bool intersect(LPoint3d &result,
+                         const LPoint3d &origin, 
+                         const LVector3d &direction) const;
+
+protected:
+  virtual double compute_intersect(const LPoint3d &origin, 
+                                   const LVector3d &direction) const;
+
+private:
+  typedef pset< PT(StitchScreen) > Screens;
+  Screens _screens;
+};
+
+#endif
+
+

+ 40 - 50
pandaapp/src/stitchbase/stitchParser.h

@@ -1,53 +1,43 @@
-// Filename: stitchParser.h
-// Created by:  
-//
-////////////////////////////////////////////////////////////////////
-//
-// 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] .
-//
-////////////////////////////////////////////////////////////////////
-
-#define NUMBER  257
-#define IDENTIFIER      258
-#define STRING  259
-#define KW_DEFINE       260
-#define KW_LENS 261
-#define KW_INPUT_IMAGE  262
-#define KW_OUTPUT_IMAGE 263
-#define KW_PERSPECTIVE  264
-#define KW_FISHEYE      265
-#define KW_CYLINDRICAL  266
-#define KW_PSPHERE      267
-#define KW_FOCAL_LENGTH 268
-#define KW_FOV  269
-#define KW_SINGULARITY_TOLERANCE        270
-#define KW_RESOLUTION   271
-#define KW_FILENAME     272
-#define KW_POINT        273
-#define KW_SHOW_POINTS  274
-#define KW_IMAGE_SIZE   275
-#define KW_FILM_SIZE    276
-#define KW_FILM_OFFSET  277
-#define KW_GRID 278
-#define KW_UNTEXTURED_COLOR     279
-#define KW_HPR  280
-#define KW_LAYERS       281
-#define KW_STITCH       282
-#define KW_POINTS       283
-#define KW_USING        284
-#define KW_IN   285
-#define KW_MM   286
-#define KW_CM   287
-#define KW_P    288
+#define	NUMBER	257
+#define	NUMBER_FEET	258
+#define	NUMBER_INCHES	259
+#define	IDENTIFIER	260
+#define	STRING	261
+#define	KW_DEFINE	262
+#define	KW_LENS	263
+#define	KW_INPUT_IMAGE	264
+#define	KW_OUTPUT_IMAGE	265
+#define	KW_PERSPECTIVE	266
+#define	KW_FISHEYE	267
+#define	KW_CYLINDRICAL	268
+#define	KW_PSPHERE	269
+#define	KW_FOCAL_LENGTH	270
+#define	KW_FOV	271
+#define	KW_SINGULARITY_TOLERANCE	272
+#define	KW_RESOLUTION	273
+#define	KW_FILENAME	274
+#define	KW_POINT	275
+#define	KW_SHOW_POINTS	276
+#define	KW_IMAGE_SIZE	277
+#define	KW_FILM_SIZE	278
+#define	KW_FILM_OFFSET	279
+#define	KW_GRID	280
+#define	KW_UNTEXTURED_COLOR	281
+#define	KW_HPR	282
+#define	KW_POS	283
+#define	KW_RADIUS	284
+#define	KW_ANGLE	285
+#define	KW_HEIGHT	286
+#define	KW_LAYERS	287
+#define	KW_STITCH	288
+#define	KW_SCREEN	289
+#define	KW_POINTS	290
+#define	KW_USING	291
+#define	KW_IN	292
+#define	KW_MM	293
+#define	KW_FT	294
+#define	KW_CM	295
+#define	KW_P	296
 
 
 extern YYSTYPE stitchyylval;

+ 67 - 7
pandaapp/src/stitchbase/stitchParser.yxx

@@ -29,7 +29,7 @@ stitch_init_parser(istream &in, const string &filename,
 
 %}
 
-%token <number> NUMBER
+%token <number> NUMBER NUMBER_FEET NUMBER_INCHES
 %token <str> IDENTIFIER
 %token <str> STRING
 
@@ -54,12 +54,18 @@ stitch_init_parser(istream &in, const string &filename,
 %token KW_GRID
 %token KW_UNTEXTURED_COLOR
 %token KW_HPR
+%token KW_POS
+%token KW_RADIUS
+%token KW_ANGLE
+%token KW_HEIGHT
 %token KW_LAYERS
 %token KW_STITCH
+%token KW_SCREEN
 %token KW_POINTS
 %token KW_USING
 %token KW_IN
 %token KW_MM
+%token KW_FT
 %token KW_CM
 %token KW_P
 
@@ -74,6 +80,7 @@ stitch_init_parser(istream &in, const string &filename,
 %type <vec> vec2
 %type <vec> vec3
 %type <vec> length_pair
+%type <vec> length_triple
 %type <vec> color
 %type <str> name
 %type <str> optional_name
@@ -139,6 +146,11 @@ group_command:
 {
   $$ = new StitchCommand(parent, StitchCommand::C_stitch);
   $$->set_name($2);
+}
+        | KW_SCREEN optional_name
+{
+  $$ = new StitchCommand(parent, StitchCommand::C_screen);
+  $$->set_name($2);
 }
         | KW_USING
 {
@@ -239,6 +251,26 @@ simple_command:
 {
   $$ = new StitchCommand(parent, StitchCommand::C_hpr);
   $$->set_point3d((const LPoint3d &)$2);
+}
+        | KW_POS length_triple
+{
+  $$ = new StitchCommand(parent, StitchCommand::C_pos);
+  $$->set_point3d((const LPoint3d &)$2);
+}
+        | KW_RADIUS length
+{
+  $$ = new StitchCommand(parent, StitchCommand::C_radius);
+  $$->set_number($2);
+}
+        | KW_ANGLE vec2
+{
+  $$ = new StitchCommand(parent, StitchCommand::C_angle);
+  $$->set_point2d((const LPoint2d &)$2);
+}
+        | KW_HEIGHT length_pair
+{
+  $$ = new StitchCommand(parent, StitchCommand::C_height);
+  $$->set_point2d((const LPoint2d &)$2);
 }
         | KW_LAYERS
 {
@@ -289,10 +321,31 @@ points_list:
 length:
         NUMBER length_units
 {
-  $$ = $1 * $2;   // convert to mm
+  $$ = $1 * $2
+}
+        | NUMBER_FEET
+{
+  $$ = $1 * 304.8;  // ft to mm
+}
+        | NUMBER_INCHES
+{
+  $$ = $1 * 25.4;  // in to mm
+}
+        | NUMBER_FEET NUMBER_INCHES
+{
+  if ($1 < 0.0) {
+    $$ = $1 * 304.8 - $2 * 25.4;
+  } else {
+    $$ = $1 * 304.8 + $2 * 25.4;
+  }
+}
+        | NUMBER
+{
+  $$ = $1;   // implicitly mm
 }
         ;
 
+
 length_units:
         KW_IN
 {
@@ -305,6 +358,10 @@ length_units:
         | KW_MM
 {
   $$ = 1.0;
+}
+        | KW_FT
+{
+  $$ = 304.8;  // ft to mm
 }
         ;
 
@@ -372,15 +429,18 @@ vec3:   '(' NUMBER NUMBER NUMBER ')'
         ;
 
 length_pair:
-        '(' length length ')'
+	'(' length ',' length ')'
 {
-  $$.set($2, $3, 0.0, 0.0);
+  $$.set($2, $4, 0.0, 0.0);
   $<num_components>$ = 2;
 }
-        | '(' length ',' length ')'
+        ;
+
+length_triple:
+        '(' length ',' length ',' length ')'
 {
-  $$.set($2, $4, 0.0, 0.0);
-  $<num_components>$ = 2;
+  $$.set($2, $4, $6, 0.0);
+  $<num_components>$ = 3;
 }
         ;
 

+ 1 - 1
pandaapp/src/stitchbase/stitchParserDefs.h

@@ -19,7 +19,7 @@
 #ifndef STITCHPARSERDEFS_H
 #define STITCHPARSERDEFS_H
 
-#include <pandatoolbase.h>
+#include "pandaappbase.h"
 
 #include <luse.h>
 

+ 2 - 0
pandaapp/src/stitchbase/stitchPoint.h

@@ -19,6 +19,8 @@
 #ifndef STITCHPOINT_H
 #define STITCHPOINT_H
 
+#include "pandaappbase.h"
+
 #include <luse.h>
 
 #include <string>

+ 134 - 0
pandaapp/src/stitchbase/stitchScreen.cxx

@@ -0,0 +1,134 @@
+// Filename: stitchScreen.cxx
+// Created by:  drose (16Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "stitchScreen.h"
+
+#include "compose_matrix.h"
+
+TypeHandle StitchScreen::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchScreen::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+StitchScreen::
+StitchScreen() :
+  _transform(LMatrix4d::ident_mat()),
+  _inv_transform(LMatrix4d::ident_mat())
+{
+  _hpr_set = false;
+  _pos_set = false;
+  _hpr.set(0.0, 0.0, 0.0);
+  _pos.set(0.0, 0.0, 0.0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchScreen::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+StitchScreen::
+~StitchScreen() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchScreen::clear_transform
+//       Access: Public
+//  Description: Resets the transform on this screen to identity.
+////////////////////////////////////////////////////////////////////
+void StitchScreen::
+clear_transform() {
+  _transform = LMatrix3d::ident_mat();
+  _inv_transform = LMatrix3d::ident_mat();
+  _hpr_set = false;
+  _pos_set = false;
+  _hpr.set(0.0, 0.0, 0.0);
+  _pos.set(0.0, 0.0, 0.0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchScreen::set_transform
+//       Access: Public
+//  Description: Sets an arbitrary transform matrix on this screen.
+//               This adjusts the screen's position and/or size in
+//               space accordingly.
+////////////////////////////////////////////////////////////////////
+void StitchScreen::
+set_transform(const LMatrix4d &trans) {
+  _transform = trans;
+  _inv_transform = invert(trans);
+  LVecBase3d scale;
+  decompose_matrix(_transform, scale, _hpr, _pos);
+  _hpr_set = false;
+  _pos_set = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchScreen::set_hpr
+//       Access: Public
+//  Description: Sets the orientation of the screen, independent of
+//               its position.
+////////////////////////////////////////////////////////////////////
+void StitchScreen::
+set_hpr(const LVecBase3d &hpr) {
+  compose_matrix(_transform, LVecBase3d(1.0, 1.0, 1.0), hpr, _pos);
+  _inv_transform.invert_from(_transform);
+  _hpr_set = true;
+  _hpr = hpr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchScreen::set_pos
+//       Access: Public
+//  Description: Sets the position of the screen, independent of
+//               its orientation.
+////////////////////////////////////////////////////////////////////
+void StitchScreen::
+set_pos(const LPoint3d &pos) {
+  compose_matrix(_transform, LVecBase3d(1.0, 1.0, 1.0), _hpr, pos);
+  _inv_transform.invert_from(_transform);
+  _pos_set = true;
+  _pos = pos;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: StitchScreen::intersect
+//       Access: Public, Virtual
+//  Description: Determines the intersection point of a ray starting
+//               at the indicated origin, and continuing infinitely in
+//               the indicated direction, with the screen.
+//
+//               If there is no intersection, leaves result undefined
+//               and returns false.  If there is an intersection, sets
+//               result to the intersection point and returns true.
+////////////////////////////////////////////////////////////////////
+bool StitchScreen::
+intersect(LPoint3d &result, 
+          const LPoint3d &origin,
+          const LVector3d &direction) const {
+  double t = compute_intersect(origin, direction);
+  if (t < 0.0) {
+    // No intersection.
+    return false;
+  }
+
+  result = origin + direction * t;
+  return true;
+}

+ 82 - 0
pandaapp/src/stitchbase/stitchScreen.h

@@ -0,0 +1,82 @@
+// Filename: stitchScreen.h
+// Created by:  drose (16Jul01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 STITCHSCREEN_H
+#define STITCHSCREEN_H
+
+#include "luse.h"
+#include "referenceCount.h"
+#include "namable.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : StitchScreen
+// Description : This is an abstract base class defining the interface
+//               to a number of different kinds of screens that images
+//               may be projected onto.
+//
+//               The shape and position of the screen geometry
+//               determines the net warping of an image transform, but
+//               only when the input projector and the output image
+//               camera are not positioned at the same nodal point.
+////////////////////////////////////////////////////////////////////
+class StitchScreen : public ReferenceCount, public Namable {
+public:
+  StitchScreen();
+  virtual ~StitchScreen();
+
+  void clear_transform();
+  void set_transform(const LMatrix4d &transform);
+  void set_hpr(const LVecBase3d &hpr);
+  void set_pos(const LPoint3d &pos);
+
+  virtual bool intersect(LPoint3d &result,
+                         const LPoint3d &origin, 
+                         const LVector3d &direction) const;
+
+protected:
+  virtual double compute_intersect(const LPoint3d &origin, 
+                                   const LVector3d &direction) const=0;
+
+protected:
+  bool _hpr_set;
+  LVecBase3d _hpr;
+  bool _pos_set;
+  LPoint3d _pos;
+  LMatrix4d _transform;
+  LMatrix4d _inv_transform;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    ReferenceCount::init_type();
+    Namable::init_type();
+    register_type(_type_handle, "StitchScreen",
+                  ReferenceCount::get_class_type(),
+                  Namable::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class StitchMultiScreen;
+};
+
+#endif
+

+ 5 - 0
pandaapp/src/stitchbase/triangleRasterizer.cxx

@@ -57,6 +57,11 @@ draw_triangle(const RasterizerVertex *v0,
     // to draw it.
     return;
   }
+  if (v0->_visibility < 0 || v1->_visibility < 0 || v2->_visibility < 0) {
+    // At least one vertex is totally bogus, so throw up our hands on
+    // the triangle.
+    return;
+  }
 
   assert(_output != NULL);
   if (!_read_input) {

+ 51 - 19
pandaapp/src/stitchviewer/stitchImageVisualizer.cxx

@@ -186,12 +186,20 @@ setup() {
   // Create the render node
   _render = new NamedNode("render");
 
-  // make a node for the cameras to live under
-  _cameras = new NamedNode("cameras");
-  RenderRelation *cam_trans = new RenderRelation(_render, _cameras);
-
-  _main_win = ChanConfig(_main_pipe, chan_cfg, _cameras, _render, override);
+  ChanConfig chanConfig(_main_pipe, chan_cfg, _render, override);
+  _main_win = chanConfig.get_win();
   assert(_main_win != (GraphicsWindow*)0L);
+  PT_NamedNode cameras = chanConfig.get_group_node(0);
+  cameras->set_name("cameras");
+  for(int group_node_index = 1;
+      group_node_index < chanConfig.get_num_groups();
+      group_node_index++) {
+    DisplayRegion *dr = chanConfig.get_dr(group_node_index);
+    dr->get_camera()->set_near_far(1.0, 10000.0);
+    new RenderRelation(_render, chanConfig.get_group_node(group_node_index));
+    
+  }
+  NodeRelation *cam_trans = new RenderRelation(_render, cameras);
 
   // Turn on backface culling.
   CullFaceAttribute *cfa = new CullFaceAttribute;
@@ -261,27 +269,51 @@ toggle_viz(StitchImageVisualizer::Image &im) {
 
 void StitchImageVisualizer::
 create_image_geometry(StitchImageVisualizer::Image &im) {
-  /*
   int x_verts = im._image->get_x_verts();
   int y_verts = im._image->get_y_verts();
-  */
+  /*
   int x_verts = 2;
   int y_verts = 2;
+  */
   TriangleMesh mesh(x_verts, y_verts);
 
   StitchLens *lens = im._image->_lens;
-  LVector3d center =
-    lens->extrude(LPoint2d(0.0, 0.0), im._image->_size_mm[0]);
-  double scale = 10.0 / length(center);
-
-  for (int xi = 0; xi < x_verts; xi++) {
-    for (int yi = 0; yi < y_verts; yi++) {
-      LPoint2d uv = LPoint2d((double)xi / (double)(x_verts - 1),
-                             1.0 - (double)yi / (double)(y_verts - 1));
-      LVector3d p = im._image->extrude(uv);
-
-      mesh._coords.push_back(LCAST(float, p) * scale);
-      mesh._texcoords.push_back(LCAST(float, uv));
+
+  if (_screen->is_empty()) {
+    // If we have no screens, draw the image geometry by extruding an
+    // arbitrary distance from each camera's origin.
+    LVector3d center =
+      lens->extrude(LPoint2d(0.0, 0.0), im._image->_size_mm[0]);
+    double scale = 10.0 / length(center);
+    
+    for (int xi = 0; xi < x_verts; xi++) {
+      for (int yi = 0; yi < y_verts; yi++) {
+        LPoint2d uv = LPoint2d((double)xi / (double)(x_verts - 1),
+                               1.0 - (double)yi / (double)(y_verts - 1));
+        LVector3d p = im._image->extrude(uv);
+        
+        mesh._coords.push_back(LCAST(float, p) * scale);
+        mesh._texcoords.push_back(LCAST(float, uv));
+      }
+    }
+  } else {
+    // Otherwise, if we do have screens, draw the image geometry by
+    // projecting its vertices on to the screen(s).
+    
+    for (int xi = 0; xi < x_verts; xi++) {
+      for (int yi = 0; yi < y_verts; yi++) {
+        LPoint2d uv = LPoint2d((double)xi / (double)(x_verts - 1),
+                               1.0 - (double)yi / (double)(y_verts - 1));
+        LVector3d space = im._image->extrude(uv);
+        LPoint3d p;
+        if (_screen->intersect(p, im._image->get_pos(), space)) {
+          mesh._coords.push_back(LCAST(float, p));
+        } else {
+          // No intersection.
+          mesh._coords.push_back(Vertexf(0.0, 0.0, 0.0));
+        }
+        mesh._texcoords.push_back(LCAST(float, uv));
+      }
     }
   }
 

+ 0 - 1
pandaapp/src/stitchviewer/stitchImageVisualizer.h

@@ -82,7 +82,6 @@ protected:
   PT(GraphicsWindow) _main_win;
   NodeAttributes _initial_state;
   PT(NamedNode) _render;
-  PT(NamedNode) _cameras;
   PT(NamedNode) _data_root;
   PT(MouseAndKeyboard) _mak;
   PT(Trackball) _trackball;