Skip to content

Commit

Permalink
From John Vidar Larring, osgautocapture example that captures an imag…
Browse files Browse the repository at this point in the history
…e from a paged database by frame loop to the paging is complete, then takes a snapshot.
  • Loading branch information
robertosfield committed Nov 26, 2008
1 parent b2762c4 commit 270fd48
Show file tree
Hide file tree
Showing 3 changed files with 351 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ IF(DYNAMIC_OPENSCENEGRAPH)
ADD_SUBDIRECTORY(osgautotransform)
ADD_SUBDIRECTORY(osgbillboard)
ADD_SUBDIRECTORY(osgblendequation)
ADD_SUBDIRECTORY(osgautocapture)
ADD_SUBDIRECTORY(osgcallback)
ADD_SUBDIRECTORY(osgcamera)
ADD_SUBDIRECTORY(osgcatch)
Expand Down
4 changes: 4 additions & 0 deletions examples/osgautocapture/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
SET(TARGET_SRC osgautocapture.cpp )

#### end var setup ###
SETUP_EXAMPLE(osgautocapture)
346 changes: 346 additions & 0 deletions examples/osgautocapture/osgautocapture.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,346 @@
/**
* TODO:
* 1) Change example to use offscreen rendering (pbuffer) so that it becomes a true commandline tool with now windows
* 2) Make example work with other threading models than SingleThreaded
* 3) Add support for autocapture to movies
*
*/
#include <osg/ArgumentParser>
#include <osg/CoordinateSystemNode>
#include <osg/Matrix>
#include <osg/NodeVisitor>

#include <osgUtil/IntersectionVisitor>
#include <osgUtil/GLObjectsVisitor>

#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

#include <osgGA/DriveManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/TerrainManipulator>
#include <osgGA/TrackballManipulator>

#include <osgTerrain/Terrain>
#include <osgTerrain/GeometryTechnique>

#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/Renderer>

#include <iostream>
#include <sstream>

/** Helper class*/
template<class T>
class FindTopMostNodeOfTypeVisitor : public osg::NodeVisitor
{
public:
FindTopMostNodeOfTypeVisitor():
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_foundNode(0)
{}

void apply(osg::Node& node)
{
T* result = dynamic_cast<T*>(&node);
if (result)
_foundNode = result;
else
traverse(node);
}

T* _foundNode;
};

/** Convenience function*/
template<class T>
T* findTopMostNodeOfType(osg::Node* node)
{
if (!node) return 0;

FindTopMostNodeOfTypeVisitor<T> fnotv;
node->accept(fnotv);

return fnotv._foundNode;
}

/** Capture the frame buffer and write image to disk*/
class WindowCaptureCallback : public osg::Camera::DrawCallback
{
public:
WindowCaptureCallback(GLenum readBuffer, const std::string& name):
_readBuffer(readBuffer),
_fileName(name)
{
_image = new osg::Image;
}

virtual void operator () (osg::RenderInfo& renderInfo) const
{
glReadBuffer(_readBuffer);

OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
osg::GraphicsContext* gc = renderInfo.getState()->getGraphicsContext();
if (gc->getTraits())
{
GLenum pixelFormat;

if (gc->getTraits()->alpha)
pixelFormat = GL_RGBA;
else
pixelFormat = GL_RGB;

int width = gc->getTraits()->width;
int height = gc->getTraits()->height;

std::cout<<"Capture: size="<<width<<"x"<<height<<", format="<<(pixelFormat == GL_RGBA ? "GL_RGBA":"GL_RGB")<<std::endl;

_image->readPixels(0, 0, width, height, pixelFormat, GL_UNSIGNED_BYTE);
}

if (!_fileName.empty())
{
std::cout << "Writing to: " << _fileName << std::endl;
osgDB::writeImageFile(*_image, _fileName);
}
}

protected:
GLenum _readBuffer;
std::string _fileName;
osg::ref_ptr<osg::Image> _image;
mutable OpenThreads::Mutex _mutex;
};


/** Do Culling only while loading PagedLODs*/
class CustomRenderer : public osgViewer::Renderer
{
public:
CustomRenderer(osg::Camera* camera)
: osgViewer::Renderer(camera),
_cullOnly(true)
{
setTargetFrameRate(1);
setMinimumTimeAvailableForGLCompileAndDeletePerFrame(1);
}

/** Set flag to omit drawing in renderingTraversals */
void setCullOnly(bool on) { _cullOnly = on; }

virtual void operator () (osg::GraphicsContext* /*context*/)
{
if (_graphicsThreadDoesCull)
{
if (_cullOnly)
cull();
else
cull_draw();
}
}

virtual void cull()
{
osgUtil::SceneView* sceneView = _sceneView[0].get();
if (!sceneView || _done ) return;

updateSceneView(sceneView);

osgViewer::View* view = dynamic_cast<osgViewer::View*>(_camera->getView());
if (view) sceneView->setFusionDistance(view->getFusionDistanceMode(), view->getFusionDistanceValue());

sceneView->inheritCullSettings(*(sceneView->getCamera()));
sceneView->cull();
}

bool _cullOnly;
};


//===============================================================
// MAIN
//
int main( int argc, char **argv )
{
osg::ArgumentParser arguments(&argc, argv);
osg::ApplicationUsage* usage = arguments.getApplicationUsage();

usage->setApplicationName(arguments.getApplicationName());
usage->setDescription(arguments.getApplicationName()+" loads a model, sets a camera position and automatically captures screenshot to disk");
usage->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
usage->addCommandLineOption("--camera <lat> <lon> <alt> <heading> <incline> <roll>", "Specify camera position for image capture. Angles are specified in degrees and altitude in meters above sealevel (e.g. --camera 55 10 300000 0 30 0)");
usage->addCommandLineOption("--filename", "Filename for the captured image", "autocapture.jpg");
usage->addCommandLineOption("--db-threads", "Number of DatabasePager threads to use", "2");
usage->addCommandLineOption("--active", "Use active rendering instead of passive / lazy rendering");

// Construct the viewer and register options arguments.
osgViewer::Viewer viewer(arguments);

if (arguments.argc()<=1)
{
arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
return 1;
}

// Get user specified number of DatabaseThreads
int dbThreads = 2;
arguments.read("--db-threads", dbThreads);
if (dbThreads < 1) dbThreads = 1;

osg::DisplaySettings::instance()->setNumOfDatabaseThreadsHint(dbThreads);

// Get user specified file name
std::string fileName("autocapture.jpg");
arguments.read("--filename", fileName);

// Rendering mode is passive by default
bool activeMode = false;
if (arguments.read("--active"))
activeMode = true;

// Read camera settings for screenshot
double lat=50;
double lon=10;
double alt=2000;
double heading=0;
double incline=45;
double roll=0;
bool camera_specified=false;
if (arguments.read("--camera", lat, lon, alt, heading, incline, roll))
{
camera_specified=true;
lat = lat * M_PI / 180.0; // Convert to radians
lon = lon * M_PI / 180.0; // Convert to radians
heading = heading * M_PI / 180.0; // Convert to radians
incline = incline * M_PI / 180.0; // Convert to radians
roll = roll * M_PI / 180.0; // Convert to radians
}

// load the data
osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
if (!loadedModel)
{
std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
return 1;
}

// any option left unread are converted into errors to write out later.
arguments.reportRemainingOptionsAsUnrecognized();

// report any errors if they have occurred when parsing the program arguments.
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}

// Setup specified camera
if (camera_specified)
{
osg::CoordinateSystemNode* csn = findTopMostNodeOfType<osg::CoordinateSystemNode>(loadedModel.get());
if(!csn) return 1;

// Compute eye point in world coordiantes
osg::Vec3d eye;
csn->getEllipsoidModel()->convertLatLongHeightToXYZ(lat, lon, alt, eye.x(), eye.y(), eye.z());

// Build matrix for computing target vector
osg::Matrixd target_matrix = osg::Matrixd::rotate(-heading, osg::Vec3d(1,0,0),
-lat, osg::Vec3d(0,1,0),
lon, osg::Vec3d(0,0,1));

// Compute tangent vector ...
osg::Vec3d tangent = target_matrix.preMult(osg::Vec3d(0, 0, 1));

// Compute non-inclined, non-rolled up vector ...
osg::Vec3d up(eye);
up.normalize();

// Incline by rotating the target- and up vector around the tangent/up-vector
// cross-product ...
osg::Vec3d up_cross_tangent = up ^ tangent;
osg::Matrixd incline_matrix = osg::Matrixd::rotate(incline, up_cross_tangent);
osg::Vec3d target = incline_matrix.preMult(tangent);

// Roll by rotating the up vector around the target vector ...
osg::Matrixd roll_matrix = incline_matrix * osg::Matrixd::rotate(roll, target);
up = roll_matrix.preMult(up);

viewer.getCamera()->setViewMatrixAsLookAt(eye, eye+target, up);
}
else
{
// Only add camera manipulators if camera is not specified
camera_specified=false;
osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;

keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
}


// Optimize DatabasePager for auto-capture
osgDB::DatabasePager* pager = viewer.getDatabasePager();
pager->setDoPreCompile(false);

// Install custom renderer
osg::ref_ptr<CustomRenderer> customRenderer = new CustomRenderer(viewer.getCamera());
viewer.getCamera()->setRenderer(customRenderer.get());

// Override threading model
viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);

// Set the final SceneData to show
viewer.setSceneData(loadedModel.get());

// Realize GUI
viewer.realize();

//--- Load PageLOD tiles ---

// Initiate the first PagedLOD request
viewer.frame();

osg::Timer_t beforeLoadTick = osg::Timer::instance()->tick();

// Keep updating and culling until full level of detail is reached
while(!viewer.done() && pager->getRequestsInProgress())
{
// std::cout <<pager->getRequestsInProgress()<<" ";
viewer.updateTraversal();
viewer.renderingTraversals();
}
// std::cout<<std::endl;

osg::Timer_t afterLoadTick = osg::Timer::instance()->tick();
std::cout<<"Load and Compile time = "<<osg::Timer::instance()->delta_s(beforeLoadTick, afterLoadTick)<<" seconds"<<std::endl;


//--- Capture the image!!! ---
if (!activeMode)
{
// Do cull and draw to render the scene correctly
customRenderer->setCullOnly(false);

// Add the WindowCaptureCallback now that we have full resolution
viewer.getCamera()->setFinalDrawCallback(new WindowCaptureCallback(GL_BACK, fileName));

osg::Timer_t beforeRenderTick = osg::Timer::instance()->tick();

// Do rendering with capture callback
viewer.renderingTraversals();

osg::Timer_t afterRenderTick = osg::Timer::instance()->tick();
std::cout<<"Rendring time = "<<osg::Timer::instance()->delta_s(beforeRenderTick, afterRenderTick) <<" seconds"<<std::endl;

return 0;
}
else
{
return viewer.run();
}
}

0 comments on commit 270fd48

Please sign in to comment.