397 lines
11 KiB
C++
397 lines
11 KiB
C++
// Filename: stitchImageVisualizer.cxx
|
|
// Created by: drose (05Nov99)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d-general@lists.sourceforge.net .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stitchImageVisualizer.h"
|
|
#include "config_stitch.h"
|
|
#include "triangleMesh.h"
|
|
#include "stitchLens.h"
|
|
|
|
#include "luse.h"
|
|
#include "chancfg.h"
|
|
#include "transform2sg.h"
|
|
#include "geomTristrip.h"
|
|
#include "geomNode.h"
|
|
#include "interactiveGraphicsPipe.h"
|
|
#include "noninteractiveGraphicsPipe.h"
|
|
#include "buttonThrower.h"
|
|
#include "dataGraphTraversal.h"
|
|
#include "eventQueue.h"
|
|
#include "texture.h"
|
|
#include "textureTransition.h"
|
|
#include "renderModeTransition.h"
|
|
#include "cullFaceTransition.h"
|
|
#include "clockObject.h"
|
|
#include "config_gobj.h"
|
|
#include "renderRelation.h"
|
|
#include "dataRelation.h"
|
|
|
|
#include <algorithm>
|
|
|
|
StitchImageVisualizer *StitchImageVisualizer::_static_siv;
|
|
|
|
// Returns the largest power of 2 less than or equal to value.
|
|
static int
|
|
to_power_2(int value) {
|
|
int x = 1;
|
|
while ((x << 1) <= value) {
|
|
x = (x << 1);
|
|
}
|
|
return x;
|
|
}
|
|
|
|
StitchImageVisualizer::Image::
|
|
Image(StitchImage *image, int index, bool scale) :
|
|
_image(image),
|
|
_index(index)
|
|
{
|
|
_arc = NULL;
|
|
_viz = true;
|
|
|
|
if (!image->read_file()) {
|
|
nout << "Unable to read image.\n";
|
|
}
|
|
|
|
if (scale && image->_data != NULL) {
|
|
// We have to make it a power of 2.
|
|
int old_xsize = image->_data->get_x_size();
|
|
int old_ysize = image->_data->get_y_size();
|
|
int new_xsize = old_xsize;
|
|
int new_ysize = old_ysize;
|
|
if (max_texture_dimension > 0) {
|
|
new_xsize = min(new_xsize, max_texture_dimension);
|
|
new_ysize = min(new_ysize, max_texture_dimension);
|
|
}
|
|
new_xsize = to_power_2(new_xsize);
|
|
new_ysize = to_power_2(new_ysize);
|
|
|
|
if (new_xsize != old_xsize || new_ysize != old_ysize) {
|
|
nout << "Scaling " << image->get_name() << " from "
|
|
<< old_xsize << " " << old_ysize << " to "
|
|
<< new_xsize << " " << new_ysize << "\n";
|
|
|
|
PNMImage *n = new PNMImage(new_xsize, new_ysize);
|
|
n->quick_filter_from(*image->_data);
|
|
delete image->_data;
|
|
image->_data = n;
|
|
}
|
|
}
|
|
}
|
|
|
|
StitchImageVisualizer::Image::
|
|
Image(const Image ©) :
|
|
_image(copy._image),
|
|
_arc(copy._arc),
|
|
_tex(copy._tex),
|
|
_viz(copy._viz),
|
|
_index(copy._index)
|
|
{
|
|
}
|
|
|
|
void StitchImageVisualizer::Image::
|
|
operator = (const Image ©) {
|
|
_image = copy._image;
|
|
_arc = copy._arc;
|
|
_tex = copy._tex;
|
|
_viz = copy._viz;
|
|
_index = copy._index;
|
|
}
|
|
|
|
StitchImageVisualizer::
|
|
StitchImageVisualizer() :
|
|
_eyepoint_inv(LMatrix4f::ident_mat()),
|
|
_event_handler(EventQueue::get_global_event_queue())
|
|
{
|
|
_event_handler.add_hook("q", static_handle_event);
|
|
_event_handler.add_hook("z", static_handle_event);
|
|
}
|
|
|
|
|
|
void StitchImageVisualizer::
|
|
add_input_image(StitchImage *image) {
|
|
int index = _images.size();
|
|
char letter = index + 'a';
|
|
_images.push_back(Image(image, index, true));
|
|
|
|
string event_name(1, letter);
|
|
_event_handler.add_hook(event_name, static_handle_event);
|
|
}
|
|
|
|
void StitchImageVisualizer::
|
|
add_output_image(StitchImage *) {
|
|
}
|
|
|
|
void StitchImageVisualizer::
|
|
add_stitcher(Stitcher *) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: StitchImageVisualizer::set_eyepoint
|
|
// Access: Public, Virtual
|
|
// Description: Sets the eye point to the indicated coordinate frame,
|
|
// if it makes sense to this kind of outputter.
|
|
////////////////////////////////////////////////////////////////////
|
|
void StitchImageVisualizer::
|
|
set_eyepoint(const LMatrix4d &mat) {
|
|
_eyepoint_inv.invert_from(LCAST(float, mat));
|
|
}
|
|
|
|
void StitchImageVisualizer::
|
|
execute() {
|
|
setup();
|
|
|
|
if (is_interactive()) {
|
|
_main_win->set_draw_callback(this);
|
|
_main_win->set_idle_callback(this);
|
|
_running = true;
|
|
while (_running) {
|
|
_main_win->update();
|
|
}
|
|
} else {
|
|
nout << "Drawing frame\n";
|
|
draw(true);
|
|
nout << "Done drawing frame\n";
|
|
}
|
|
}
|
|
|
|
void StitchImageVisualizer::
|
|
setup() {
|
|
ChanCfgOverrides override;
|
|
|
|
override_chan_cfg(override);
|
|
|
|
// load display modules
|
|
GraphicsPipe::resolve_modules();
|
|
|
|
// Create a window
|
|
TypeHandle want_pipe_type = InteractiveGraphicsPipe::get_class_type();
|
|
if (!is_interactive()) {
|
|
want_pipe_type = NoninteractiveGraphicsPipe::get_class_type();
|
|
}
|
|
|
|
_main_pipe = GraphicsPipe::get_factory().make_instance(want_pipe_type);
|
|
|
|
if (_main_pipe == (GraphicsPipe*)0L) {
|
|
nout << "No suitable pipe is available! Check your Configrc!\n";
|
|
exit(1);
|
|
}
|
|
|
|
nout << "Opened a '" << _main_pipe->get_type().get_name()
|
|
<< "' graphics pipe." << endl;
|
|
|
|
// Create the render node
|
|
_render_top = new NamedNode("render_top");
|
|
_render = new NamedNode("render");
|
|
_render_arc = new RenderRelation(_render_top, _render);
|
|
|
|
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()->get_lens()->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.
|
|
CullFaceTransition *cfa = new CullFaceTransition(CullFaceProperty::M_cull_clockwise);
|
|
_render_arc->set_transition(cfa);
|
|
|
|
// Create the data graph root.
|
|
_data_root = new NamedNode( "data" );
|
|
|
|
// Create a mouse and put it in the data graph.
|
|
_mak = new MouseAndKeyboard(_main_win, 0);
|
|
new DataRelation(_data_root, _mak);
|
|
|
|
// Create a trackball to handle the mouse input.
|
|
_trackball = new Trackball("trackball");
|
|
_trackball->set_mat(_eyepoint_inv);
|
|
|
|
new DataRelation(_mak, _trackball);
|
|
|
|
// Connect the trackball output to the camera's transform.
|
|
PT(Transform2SG) tball2cam = new Transform2SG("tball2cam");
|
|
tball2cam->set_arc(cam_trans);
|
|
new DataRelation(_trackball, tball2cam);
|
|
|
|
// Create an ButtonThrower to throw events from the keyboard.
|
|
PT(ButtonThrower) et = new ButtonThrower("kb-events");
|
|
new DataRelation(_mak, et);
|
|
|
|
// Create all the images.
|
|
Images::iterator ii;
|
|
for (ii = _images.begin(); ii != _images.end(); ++ii) {
|
|
create_image_geometry(*ii);
|
|
}
|
|
}
|
|
|
|
|
|
void StitchImageVisualizer::
|
|
override_chan_cfg(ChanCfgOverrides &override) {
|
|
override.setField(ChanCfgOverrides::Mask,
|
|
((unsigned int)(W_DOUBLE|W_DEPTH|W_MULTISAMPLE)));
|
|
override.setField(ChanCfgOverrides::Title, "Stitch");
|
|
}
|
|
|
|
void StitchImageVisualizer::
|
|
setup_camera(const RenderRelation &) {
|
|
}
|
|
|
|
bool StitchImageVisualizer::
|
|
is_interactive() const {
|
|
return true;
|
|
}
|
|
|
|
void StitchImageVisualizer::
|
|
toggle_viz(StitchImageVisualizer::Image &im) {
|
|
im._viz = !im._viz;
|
|
if (im._viz) {
|
|
im._arc->set_transition(new RenderModeTransition(RenderModeProperty::M_filled));
|
|
im._arc->set_transition(new CullFaceTransition(CullFaceProperty::M_cull_clockwise));
|
|
if (im._tex != (Texture *)NULL) {
|
|
im._arc->set_transition(new TextureTransition(im._tex));
|
|
}
|
|
} else {
|
|
im._arc->set_transition(new RenderModeTransition(RenderModeProperty::M_wireframe));
|
|
im._arc->set_transition(new CullFaceTransition(CullFaceProperty::M_cull_none));
|
|
im._arc->set_transition(new TextureTransition);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
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));
|
|
}
|
|
}
|
|
}
|
|
|
|
PT(GeomTristrip) geom = mesh.build_mesh();
|
|
|
|
PT(GeomNode) node = new GeomNode;
|
|
node->add_geom(geom.p());
|
|
|
|
im._arc = new RenderRelation(_render, node);
|
|
|
|
if (im._image->_data != NULL) {
|
|
im._tex = new Texture;
|
|
im._tex->set_name(im._image->get_filename());
|
|
im._tex->load(*im._image->_data);
|
|
im._arc->set_transition(new TextureTransition(im._tex));
|
|
}
|
|
}
|
|
|
|
|
|
void StitchImageVisualizer::
|
|
draw(bool) {
|
|
int num_windows = _main_pipe->get_num_windows();
|
|
for (int w = 0; w < num_windows; w++) {
|
|
GraphicsWindow *win = _main_pipe->get_window(w);
|
|
win->get_gsg()->render_frame();
|
|
}
|
|
ClockObject::get_global_clock()->tick();
|
|
}
|
|
|
|
void StitchImageVisualizer::
|
|
idle() {
|
|
// Initiate the data traversal, to send device data down its
|
|
// respective pipelines.
|
|
traverse_data_graph(_data_root);
|
|
|
|
// Throw any events generated recently.
|
|
_static_siv = this;
|
|
_event_handler.process_events();
|
|
}
|
|
|
|
void StitchImageVisualizer::
|
|
static_handle_event(CPT(Event) event) {
|
|
_static_siv->handle_event(event);
|
|
}
|
|
|
|
|
|
void StitchImageVisualizer::
|
|
handle_event(CPT(Event) event) {
|
|
string name = event->get_name();
|
|
|
|
if (name.size() == 1 && isalpha(name[0])) {
|
|
int index = tolower(name[0]) - 'a';
|
|
if (index >= 0 && index < (int)_images.size()) {
|
|
toggle_viz(_images[index]);
|
|
return;
|
|
}
|
|
}
|
|
if (name == "q") {
|
|
_running = false;
|
|
|
|
} else if (name == "z") {
|
|
_trackball->reset();
|
|
_trackball->set_mat(_eyepoint_inv);
|
|
}
|
|
}
|
|
|
|
|
|
|