diff --git a/pandaapp/src/stitch/stitchImageProgram.cxx b/pandaapp/src/stitch/stitchImageProgram.cxx index 6f30302a55..58dbe7d1fd 100644 --- a/pandaapp/src/stitch/stitchImageProgram.cxx +++ b/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); } diff --git a/pandaapp/src/stitch/stitchImageProgram.h b/pandaapp/src/stitch/stitchImageProgram.h index e57dfefefe..f9e41e2c71 100644 --- a/pandaapp/src/stitch/stitchImageProgram.h +++ b/pandaapp/src/stitch/stitchImageProgram.h @@ -36,7 +36,7 @@ public: void run(); private: - bool _filter_output; + double _filter_factor; }; #endif diff --git a/pandaapp/src/stitchbase/Sources.pp b/pandaapp/src/stitchbase/Sources.pp index fdcd744685..0ec5af464a 100644 --- a/pandaapp/src/stitchbase/Sources.pp +++ b/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 diff --git a/pandaapp/src/stitchbase/config_stitch.cxx b/pandaapp/src/stitchbase/config_stitch.cxx index 288a02c9fc..60268a98ee 100644 --- a/pandaapp/src/stitchbase/config_stitch.cxx +++ b/pandaapp/src/stitchbase/config_stitch.cxx @@ -17,12 +17,14 @@ //////////////////////////////////////////////////////////////////// #include "config_stitch.h" +#include "stitchScreen.h" #include Configure(config_stitch); ConfigureFn(config_stitch) { + StitchScreen::init_type(); } string chan_cfg = config_stitch.GetString("chan-config", "single"); diff --git a/pandaapp/src/stitchbase/config_stitch.h b/pandaapp/src/stitchbase/config_stitch.h index f64b3ccbfe..ef961ca56a 100644 --- a/pandaapp/src/stitchbase/config_stitch.h +++ b/pandaapp/src/stitchbase/config_stitch.h @@ -19,7 +19,7 @@ #ifndef CONFIG_STITCH_H #define CONFIG_STITCH_H -#include +#include "pandaappbase.h" extern string chan_cfg; diff --git a/pandaapp/src/stitchbase/layeredImage.h b/pandaapp/src/stitchbase/layeredImage.h index 041104a72e..d75b868de4 100644 --- a/pandaapp/src/stitchbase/layeredImage.h +++ b/pandaapp/src/stitchbase/layeredImage.h @@ -19,7 +19,7 @@ #ifndef LAYEREDIMAGE_H #define LAYEREDIMAGE_H -#include +#include "pandaappbase.h" #include #include diff --git a/pandaapp/src/stitchbase/stitchCommand.cxx b/pandaapp/src/stitchbase/stitchCommand.cxx index 8e14b6a6d2..8e0354493e 100644 --- a/pandaapp/src/stitchbase/stitchCommand.cxx +++ b/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 @@ -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; +} + diff --git a/pandaapp/src/stitchbase/stitchCommand.h b/pandaapp/src/stitchbase/stitchCommand.h index 8ff68a4e43..5e87646104 100644 --- a/pandaapp/src/stitchbase/stitchCommand.h +++ b/pandaapp/src/stitchbase/stitchCommand.h @@ -19,15 +19,16 @@ #ifndef STITCHCOMMAND_H #define STITCHCOMMAND_H -#include +#include "pandaappbase.h" +#include "stitchScreen.h" -#include - -#include -#include +#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 Commands; + typedef pvector Commands; Commands _using; Commands _nested; }; diff --git a/pandaapp/src/stitchbase/stitchCommandReader.h b/pandaapp/src/stitchbase/stitchCommandReader.h index 2a3d994904..9436180d7f 100644 --- a/pandaapp/src/stitchbase/stitchCommandReader.h +++ b/pandaapp/src/stitchbase/stitchCommandReader.h @@ -19,7 +19,7 @@ #ifndef STITCHCOMMANDREADER_H #define STITCHCOMMANDREADER_H -#include +#include "pandaappbase.h" #include "stitchFile.h" diff --git a/pandaapp/src/stitchbase/stitchCylindricalScreen.cxx b/pandaapp/src/stitchbase/stitchCylindricalScreen.cxx new file mode 100644 index 0000000000..901875dc81 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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; + } + } + } +} diff --git a/pandaapp/src/stitchbase/stitchCylindricalScreen.h b/pandaapp/src/stitchbase/stitchCylindricalScreen.h new file mode 100644 index 0000000000..42b4dfc269 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 + + diff --git a/pandaapp/src/stitchbase/stitchFlatScreen.cxx b/pandaapp/src/stitchbase/stitchFlatScreen.cxx new file mode 100644 index 0000000000..e6bb5ebead --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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; +} diff --git a/pandaapp/src/stitchbase/stitchFlatScreen.h b/pandaapp/src/stitchbase/stitchFlatScreen.h new file mode 100644 index 0000000000..67f8c83d80 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 + + diff --git a/pandaapp/src/stitchbase/stitchImage.cxx b/pandaapp/src/stitchbase/stitchImage.cxx index c45057891a..e9e8753af6 100644 --- a/pandaapp/src/stitchbase/stitchImage.cxx +++ b/pandaapp/src/stitchbase/stitchImage.cxx @@ -20,8 +20,8 @@ #include "stitchLens.h" #include "layeredImage.h" -#include -#include +#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; +} diff --git a/pandaapp/src/stitchbase/stitchImage.h b/pandaapp/src/stitchbase/stitchImage.h index 33784cd983..6cfea643ba 100644 --- a/pandaapp/src/stitchbase/stitchImage.h +++ b/pandaapp/src/stitchbase/stitchImage.h @@ -19,7 +19,7 @@ #ifndef STITCHIMAGE_H #define STITCHIMAGE_H -#include +#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 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) { diff --git a/pandaapp/src/stitchbase/stitchImageCommandOutput.cxx b/pandaapp/src/stitchbase/stitchImageCommandOutput.cxx index cbc91d56e9..9ea7479aaa 100644 --- a/pandaapp/src/stitchbase/stitchImageCommandOutput.cxx +++ b/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. } } diff --git a/pandaapp/src/stitchbase/stitchImageOutputter.cxx b/pandaapp/src/stitchbase/stitchImageOutputter.cxx index 0e97d6805b..d9df76b906 100644 --- a/pandaapp/src/stitchbase/stitchImageOutputter.cxx +++ b/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); +} diff --git a/pandaapp/src/stitchbase/stitchImageOutputter.h b/pandaapp/src/stitchbase/stitchImageOutputter.h index a4de316e93..633fb12185 100644 --- a/pandaapp/src/stitchbase/stitchImageOutputter.h +++ b/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 - +//////////////////////////////////////////////////////////////////// +// 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 diff --git a/pandaapp/src/stitchbase/stitchImageRasterizer.cxx b/pandaapp/src/stitchbase/stitchImageRasterizer.cxx index ff423aedd9..4f109c5655 100644 --- a/pandaapp/src/stitchbase/stitchImageRasterizer.cxx +++ b/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 VRow; typedef vector 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); + 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 = 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]._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); - _table[xi][yi]._space = normalize(_table[xi][yi]._space); + // Tag any triangle including this vertex as totally invalid. + table[xi][yi]._visibility = -1; - // 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)); + } 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); diff --git a/pandaapp/src/stitchbase/stitchImageRasterizer.h b/pandaapp/src/stitchbase/stitchImageRasterizer.h index 24c5fdbe10..0e7943575b 100644 --- a/pandaapp/src/stitchbase/stitchImageRasterizer.h +++ b/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, diff --git a/pandaapp/src/stitchbase/stitchLexer.lxx b/pandaapp/src/stitchbase/stitchLexer.lxx index 0cea3ffe8f..ded5b1fdad 100644 --- a/pandaapp/src/stitchbase/stitchLexer.lxx +++ b/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; } diff --git a/pandaapp/src/stitchbase/stitchLexerDefs.h b/pandaapp/src/stitchbase/stitchLexerDefs.h index 7950c3608b..e5a19f339f 100644 --- a/pandaapp/src/stitchbase/stitchLexerDefs.h +++ b/pandaapp/src/stitchbase/stitchLexerDefs.h @@ -19,7 +19,7 @@ #ifndef STITCHLEXERDEFS_H #define STITCHLEXERDEFS_H -#include +#include "pandaappbase.h" void stitch_init_lexer(istream &in, const string &filename); int stitch_error_count(); diff --git a/pandaapp/src/stitchbase/stitchMultiScreen.cxx b/pandaapp/src/stitchbase/stitchMultiScreen.cxx new file mode 100644 index 0000000000..7119852d78 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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; +} diff --git a/pandaapp/src/stitchbase/stitchMultiScreen.h b/pandaapp/src/stitchbase/stitchMultiScreen.h new file mode 100644 index 0000000000..e585da91e9 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 + + diff --git a/pandaapp/src/stitchbase/stitchParser.h b/pandaapp/src/stitchbase/stitchParser.h index 36809c9089..cd430bf850 100644 --- a/pandaapp/src/stitchbase/stitchParser.h +++ b/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 -// panda3d@yahoogroups.com . -// -//////////////////////////////////////////////////////////////////// - -#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; diff --git a/pandaapp/src/stitchbase/stitchParser.yxx b/pandaapp/src/stitchbase/stitchParser.yxx index 096d100ee9..4159b200c2 100644 --- a/pandaapp/src/stitchbase/stitchParser.yxx +++ b/pandaapp/src/stitchbase/stitchParser.yxx @@ -29,7 +29,7 @@ stitch_init_parser(istream &in, const string &filename, %} -%token NUMBER +%token NUMBER NUMBER_FEET NUMBER_INCHES %token IDENTIFIER %token 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 vec2 %type vec3 %type length_pair +%type length_triple %type color %type name %type 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,18 +429,21 @@ vec3: '(' NUMBER NUMBER NUMBER ')' ; length_pair: - '(' length length ')' -{ - $$.set($2, $3, 0.0, 0.0); - $$ = 2; -} - | '(' length ',' length ')' + '(' length ',' length ')' { $$.set($2, $4, 0.0, 0.0); $$ = 2; } ; +length_triple: + '(' length ',' length ',' length ')' +{ + $$.set($2, $4, $6, 0.0); + $$ = 3; +} + ; + color: '(' NUMBER NUMBER NUMBER ')' { diff --git a/pandaapp/src/stitchbase/stitchParserDefs.h b/pandaapp/src/stitchbase/stitchParserDefs.h index 090fd6793f..12a97797da 100644 --- a/pandaapp/src/stitchbase/stitchParserDefs.h +++ b/pandaapp/src/stitchbase/stitchParserDefs.h @@ -19,7 +19,7 @@ #ifndef STITCHPARSERDEFS_H #define STITCHPARSERDEFS_H -#include +#include "pandaappbase.h" #include diff --git a/pandaapp/src/stitchbase/stitchPoint.h b/pandaapp/src/stitchbase/stitchPoint.h index 2892e733e9..459ea76b2d 100644 --- a/pandaapp/src/stitchbase/stitchPoint.h +++ b/pandaapp/src/stitchbase/stitchPoint.h @@ -19,6 +19,8 @@ #ifndef STITCHPOINT_H #define STITCHPOINT_H +#include "pandaappbase.h" + #include #include diff --git a/pandaapp/src/stitchbase/stitchScreen.cxx b/pandaapp/src/stitchbase/stitchScreen.cxx new file mode 100644 index 0000000000..05376279bb --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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; +} diff --git a/pandaapp/src/stitchbase/stitchScreen.h b/pandaapp/src/stitchbase/stitchScreen.h new file mode 100644 index 0000000000..6382bb0434 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 + diff --git a/pandaapp/src/stitchbase/triangleRasterizer.cxx b/pandaapp/src/stitchbase/triangleRasterizer.cxx index c0c4bdb242..28e7c31c33 100644 --- a/pandaapp/src/stitchbase/triangleRasterizer.cxx +++ b/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) { diff --git a/pandaapp/src/stitchviewer/stitchImageVisualizer.cxx b/pandaapp/src/stitchviewer/stitchImageVisualizer.cxx index 02f2558c8b..0991bc3e34 100644 --- a/pandaapp/src/stitchviewer/stitchImageVisualizer.cxx +++ b/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)); + } } } diff --git a/pandaapp/src/stitchviewer/stitchImageVisualizer.h b/pandaapp/src/stitchviewer/stitchImageVisualizer.h index 76d36dbeb9..fd56618d53 100644 --- a/pandaapp/src/stitchviewer/stitchImageVisualizer.h +++ b/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;