Files
OpenSceneGraph/src/osgGLUT/Viewer.cpp
2002-11-12 10:22:38 +00:00

1792 lines
67 KiB
C++

#if defined(_MSC_VER)
#pragma warning( disable : 4786 )
#endif
#include <osg/GL>
#include <osgGLUT/glut>
#include <stdlib.h>
#if (!defined(WIN32) && !defined(macintosh)) || defined(__CYGWIN__)
#include <unistd.h>
#include <sys/time.h>
#endif
#include <stdio.h>
#include <osg/Math>
#include <osg/Statistics>
#include <string>
#include <osgGLUT/Viewer>
#include <osgGLUT/GLUTEventAdapter>
#include <osg/Switch>
#include <osg/Billboard>
#include <osg/LOD>
#include <osg/Light>
#include <osg/LightSource>
#include <osg/Geode>
#include <osg/Group>
#include <osg/NodeVisitor>
#include <osg/LineSegment>
#include <osg/PolygonMode>
#include <osg/Texture2D>
#include <osg/LightModel>
#include <osg/ShadeModel>
#include <osg/Notify>
#include <osg/CollectOccludersVisitor>
#include <osg/Fog>
#include <osgDB/WriteFile>
#include <osgUtil/IntersectVisitor>
#include <osgUtil/DisplayListVisitor>
#include <osgUtil/SmoothingVisitor>
#include <osgUtil/TriStripVisitor>
#include <osgUtil/DisplayRequirementsVisitor>
#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osg/Version>
#include <osgUtil/Version>
#ifdef WIN32
#define USE_FLTK
#define USE_GLUT
#endif
/*
#if defined(WIN32) && !defined(__CYGWIN__)
#include <sys/timeb.h>
#else
#endif
*/
#include <osg/Timer>
osg::Timer g_timer;
osg::Timer_t g_initTime;
//static GLenum polymodes [] = { GL_FILL, GL_LINE, GL_POINT };
static osg::PolygonMode::Mode polymodes [] = { osg::PolygonMode::FILL, osg::PolygonMode::LINE, osg::PolygonMode::POINT };
// forward declare functions to be used in stats.
GLuint makeRasterFont(void);
void displaytext(int x, int y, char *s);
int writePrims( const int ypos, osg::Statistics& stats);
using namespace osg;
using namespace osgUtil;
using namespace osgGLUT;
using namespace osgGA;
using namespace std;
Viewer* Viewer::s_theViewer = 0;
Viewer::Viewer()
{
s_theViewer = this;
polymode = 0;
texture = 1;
backface = 1;
lighting = 1;
flat_shade = 0;
_printStats = 0; // gwm change from bool was : false;
#ifdef SGV_USE_RTFS
fs = osgNew RTfs( RTFS_MODE_RTC_SPIN );
frame_rate = 16;
fs->setUpdateRate( frame_rate );
#endif
_viewFrustumCullingActive = true;
_smallFeatureCullingActive = true;
_useDisplayLists = true;
_saveFileName = "saved_model.osg";
osg::notify(osg::INFO)<<"Scene Graph Viewer (sgv)"<< std::endl;
// osg::notify(osg::INFO)<<" '"<<osgGetLibraryName()<<"' Version "<<osgGetVersion()<< std::endl;
// osg::notify(osg::INFO)<<" '"<<osgUtilGetLibraryName()<<"' Version "<<osgUtilGetVersion()<< std::endl;
_initialTick = _timer.tick();
_frameTick = _initialTick;
_lastFrameTick = _initialTick;
frRate=0;
_focusedViewport = 0; // The viewport with mouse/keyboard focus
_frameStamp = osgNew osg::FrameStamp;
_displaySettings = osgNew osg::DisplaySettings;
_recordingAnimationPath = false;
}
Viewer::~Viewer()
{
}
void Viewer::clear()
{
_viewportList.clear();
_frameStamp = 0L;
_displaySettings = 0L;
Window::clear();
}
/** read the command line string list, removing any matched control sequences.*/
void Viewer::readCommandLine(std::vector<std::string>& commandLine)
{
std::vector<std::string>::iterator itr = commandLine.begin();
for(;itr!=commandLine.end();++itr)
{
if (*itr=="-f")
{
_fullscreen = true;
break;
}
}
_displaySettings->readCommandLine(commandLine);
}
void
Viewer::toggleFullScreen()
{
_fullscreen = !_fullscreen;
if (_fullscreen)
{
_saved_ww = _ww;
_saved_wh = _wh;
glutFullScreen();
} else
{
//glutPositionWindow(wx,wy);
glutReshapeWindow(_saved_ww,_saved_wh);
}
}
/**
* Configure and open the GLUT window for this Viewer
*
*/
bool Viewer::open()
{
if ( getNumViewports() <= 0 ) {
osg::notify(osg::FATAL)<<"osgGLUT::Viewer::open() called with no Viewports registered."<< std::endl;
return false;
}
// Verify all viewports have an active camera manipulator
unsigned int index = 0;
ViewportList::iterator itr;
for(itr=_viewportList.begin();
itr!=_viewportList.end();
++itr, ++index)
{
if (itr->_cameraManipList.empty())
{
osg::notify(osg::INFO)<<"osgGLUT::Viewer::open() called without any camara manipulators registered for a viewport,"<< std::endl;
osg::notify(osg::INFO)<<"automatically registering trackball,flight and drive manipulators."<< std::endl;
registerCameraManipulator(new osgGA::TrackballManipulator, index);
registerCameraManipulator(new osgGA::FlightManipulator, index);
registerCameraManipulator(new osgGA::DriveManipulator, index);
}
if (!itr->_cameraManipulator.valid())
selectCameraManipulator(0,index);
}
GLUTEventAdapter::setWindowSize( _wx, _wy, _wx+_ww, _wx+_wh );
GLUTEventAdapter::setButtonMask(0);
bool needQuadBufferStereo = false;
// do we need quad buffer stereo?
// Set the absolute viewport for each SceneView based on the
// relative viewport coordinates given to us
for(itr=_viewportList.begin();
itr!=_viewportList.end();
++itr)
{
osgUtil::SceneView* sceneView = itr->sceneView.get();
int view[4] = { int(itr->viewport[0]*_ww), int(itr->viewport[1]*_wh),
int(itr->viewport[2]*_ww), int(itr->viewport[3]*_wh) };
sceneView->setViewport(view[0], view[1], view[2], view[3]);
osg::ref_ptr<GLUTEventAdapter> ea = osgNew GLUTEventAdapter;
ea->adaptResize(clockSeconds(),
view[0], view[1],
view[0]+view[2], view[1]+view[3]);
if (itr->_cameraManipulator->handle(*ea,*this))
{
// osg::notify(osg::INFO) << "Handled reshape "<< std::endl;
}
const osg::DisplaySettings* vs = sceneView->getDisplaySettings();
if (vs)
{
_displaySettings->merge(*vs);
}
else
{
// one does not already exist so attach the viewers visualsSettins to the SceneView
sceneView->setDisplaySettings(_displaySettings.get());
}
}
if (_displaySettings->getStereo() &&
_displaySettings->getStereoMode()==osg::DisplaySettings::QUAD_BUFFER) needQuadBufferStereo = true;
// traverse the scene graphs gathering the requirements of the OpenGL buffers.
osgUtil::DisplayRequirementsVisitor drv;
drv.setDisplaySettings(_displaySettings.get());
for(itr=_viewportList.begin();
itr!=_viewportList.end();
++itr)
{
Node* node = itr->sceneView->getSceneData();
if (node) node->accept(drv);
}
// set up each render stage to clear the appropriate buffers.
GLbitfield clear_mask=0;
if (_displaySettings->getRGB()) clear_mask |= GL_COLOR_BUFFER_BIT;
if (_displaySettings->getDepthBuffer()) clear_mask |= GL_DEPTH_BUFFER_BIT;
if (_displaySettings->getStencilBuffer()) clear_mask |= GL_STENCIL_BUFFER_BIT;
for(itr=_viewportList.begin();
itr!=_viewportList.end();
++itr)
{
osgUtil::RenderStage *stage = itr->sceneView->getRenderStage();
if (stage) stage->setClearMask(clear_mask);
}
// set the GLUT display mode bit mask up to handle it.
unsigned int displayMode=0;
if (_displaySettings->getDoubleBuffer()) displayMode |= GLUT_DOUBLE;
else displayMode |= GLUT_SINGLE;
if (_displaySettings->getRGB()) displayMode |= GLUT_RGB;
if (_displaySettings->getDepthBuffer()) displayMode |= GLUT_DEPTH;
if (_displaySettings->getAlphaBuffer()) displayMode |= GLUT_ALPHA;
if (_displaySettings->getStencilBuffer()) displayMode |= GLUT_STENCIL;
if (needQuadBufferStereo) displayMode |= GLUT_STEREO;
// and we'll add in multisample so that on systems like Onyx's can
// go ahead and use there loverly anti-aliasing. This is ignored
// by other systems I've come across so not need to worry about it.
displayMode |= GLUT_MULTISAMPLE;
osg::notify(osg::INFO) <<"osgGLUT::Viewer::open() requesting displayMode = "<<displayMode<< std::endl;
if (displayMode & GLUT_DOUBLE) osg::notify(osg::INFO)<<" requesting GLUT_DOUBLE."<< std::endl;
if (displayMode & GLUT_SINGLE) osg::notify(osg::INFO)<<" requesting GLUT_SINGLE."<< std::endl;
if (displayMode & GLUT_RGB) osg::notify(osg::INFO)<<" requesting GLUT_RGB."<< std::endl;
if (displayMode & GLUT_DEPTH) osg::notify(osg::INFO)<<" requesting GLUT_DEPTH."<< std::endl;
if (displayMode & GLUT_ALPHA) osg::notify(osg::INFO)<<" requesting GLUT_ALPHA."<< std::endl;
if (displayMode & GLUT_STENCIL) osg::notify(osg::INFO)<<" requesting GLUT_STENCIL."<< std::endl;
if (displayMode & GLUT_MULTISAMPLE) osg::notify(osg::INFO)<<" requesting GLUT_MULTISAMPLE."<< std::endl;
if (displayMode & GLUT_STEREO) osg::notify(osg::INFO)<<" requesting GLUT_STEREO."<< std::endl;
_displayMode = displayMode;
return Window::open();
}
unsigned int Viewer::registerCameraManipulator(osgGA::CameraManipulator* cm,
unsigned int viewport)
{
ViewportDef &viewp = _viewportList[viewport];
unsigned int pos = viewp._cameraManipList.size();
viewp._cameraManipList.push_back(cm);
return pos;
}
void Viewer::prependEventHandler(osgGA::GUIEventHandler* handler,unsigned int viewport)
{
ViewportDef &viewp = _viewportList[viewport];
viewp._eventHandlerList.push_front( handler );
}
void Viewer::appendEventHandler(osgGA::GUIEventHandler* handler,unsigned int viewport)
{
ViewportDef &viewp = _viewportList[viewport];
viewp._eventHandlerList.push_back( handler );
}
void Viewer::setFocusedViewport(unsigned int pos)
{
if (pos>=_viewportList.size()) return;
_focusedViewport = pos;
}
void Viewer::selectCameraManipulator(unsigned int pos, unsigned int viewport)
{
if (viewport>=_viewportList.size()) return;
ViewportDef &viewp = _viewportList[viewport];
if (pos>=viewp._cameraManipList.size()) return;
viewp._cameraManipulator = viewp._cameraManipList[pos];
osgUtil::SceneView *sceneView = viewp.sceneView.get();
viewp._cameraManipulator->setCamera(sceneView->getCamera());
viewp._cameraManipulator->setNode(sceneView->getSceneData());
osg::ref_ptr<GLUTEventAdapter> ea = osgNew GLUTEventAdapter;
viewp._cameraManipulator->init(*ea,*this);
}
void Viewer::requestWarpPointer(int x,int y)
{
// glutWarpPointer core dumps if invoked before a GLUT window is open
if ( !_is_open ) {
osg::notify(osg::INFO)<<"osgGLUT::Viewer::requestWarpPointer() called with window closed; ignored."<< std::endl;
return;
}
glutWarpPointer(x,y);
}
float Viewer::app(unsigned int viewport)
{
osg::Timer_t beforeApp = _timer.tick();
// update the camera manipulator.
osg::ref_ptr<GLUTEventAdapter> ea = osgNew GLUTEventAdapter;
ea->adaptFrame(_frameStamp->getReferenceTime());
bool handled = false;
for (EventHandlerList::iterator eh = _viewportList[viewport]._eventHandlerList.begin();
eh != _viewportList[viewport]._eventHandlerList.end();
eh++ )
{
if ( eh->valid() )
{
if ( (*eh)->handle(*ea,*this) )
{
handled = true;
break;
}
}
}
// if ( !handled ) {
_viewportList[viewport]._cameraManipulator->handle(*ea,*this);
// }
if (getRecordingAnimationPath() && getAnimationPath())
{
osg::Camera* camera = getViewportSceneView(viewport)->getCamera();
osg::Matrix matrix;
matrix.invert(camera->getModelViewMatrix());
osg::Quat quat;
quat.set(matrix);
getAnimationPath()->insert(_frameStamp->getReferenceTime(),osg::AnimationPath::ControlPoint(matrix.getTrans(),quat));
}
// do app traversal.
getViewportSceneView(viewport)->setFrameStamp(_frameStamp.get());
getViewportSceneView(viewport)->app();
osg::Timer_t beforeCull = _timer.tick();
return _timer.delta_m(beforeApp,beforeCull);
}
float Viewer::cull(unsigned int viewport)
{
osg::Timer_t beforeCull = _timer.tick();
// do cull traversal.
getViewportSceneView(viewport)->cull();
osg::Timer_t beforeDraw = _timer.tick();
return _timer.delta_m(beforeCull,beforeDraw);
}
float Viewer::draw(unsigned int viewport)
{
osg::Timer_t beforeDraw = _timer.tick();
// do draw traversal.
getViewportSceneView(viewport)->draw();
osg::Timer_t afterDraw = _timer.tick();
return _timer.delta_m(beforeDraw,afterDraw);
}
int Viewer::mapWindowXYToViewport(int x, int y)
{
int ogl_y = _wh-y;
int index = 0;
for(ViewportList::iterator itr=_viewportList.begin();
itr!=_viewportList.end();
++itr, ++index)
{
if ( x >= int( itr->viewport[0]*_ww ) &&
ogl_y >= int( itr->viewport[1]*_wh ) &&
x <= int( (itr->viewport[0]+itr->viewport[2])*_ww ) &&
ogl_y <= int( (itr->viewport[1]+itr->viewport[3])*_wh ) )
return index;
}
return -1;
}
// GWM July 2001 - moved all draw stats to Statistics structure, and related RenderBin
// GWM Sept 2001 - all draw stats now calculated by calls to <Drawable>->getStats(Statistic..)
void Viewer::showStats(const unsigned int /*viewport*/)
{ // collect stats for viewport
static int maxbins=1; // count number of bins
static GLfloat tmax=100;
glViewport(0,0,_ww,_wh);
float vh = _wh;
glDisable( GL_DEPTH_TEST ); // to see the stats always
glDisable( GL_ALPHA_TEST );
glDisable( GL_LIGHTING );
glDisable( GL_TEXTURE_2D );
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
// set tmax using hysteresis to prevent flip-flopping between two values of tmax
// tmax is the scale for the stage timing graph
if (times[2].timeFrame>360.0f && tmax<1600) tmax=1600;
else if (times[2].timeFrame<300.0f && tmax>800) tmax=800;
else if (times[2].timeFrame>180.0f && tmax<800) tmax=800;
else if (times[2].timeFrame<150.0f && tmax>400) tmax=400;
else if (times[2].timeFrame>90.0f && tmax<400) tmax=400;
else if (times[2].timeFrame<75.0f && tmax>200) tmax=200;
else if (times[2].timeFrame>45.0f && tmax<200) tmax=200;
else if (times[2].timeFrame<36.0f && tmax>100) tmax=100;
glOrtho(-0.1f*tmax, tmax*1.1f,0,vh,0,500);
glDepthRange(0,1);
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glDisable(GL_STENCIL_TEST); // dont want to count pixels set by performance graphs
if (_printStats>0) { // output the text frame rate
char clin[72]; // buffer to print
glColor3f(1.0f,1.0f,0.0f);
if (frRate>10.0f)
{
float smoothRatio = 0.4; // should be >0 and <= 1.0,
// lower the value greater smoothing.
frRate=(1.0f-smoothRatio)*frRate+smoothRatio*frameRate(); // smooth out variations in frame rate
}
else
{
frRate=frameRate(); // frame rate so slow no need to smooth in frame rate
}
sprintf(clin,"%.1f Hz.", frRate);
displaytext(0,(int)(0.98f*vh),clin);
}
if (_printStats>=Statistics::STAT_GRAPHS && _printStats!=Statistics::STAT_PRIMSPERVIEW && _printStats!=Statistics::STAT_PRIMSPERBIN) { // more stats - graphs this time
int sampleIndex = 2;
float timeApp=times[sampleIndex].timeApp;
float timeCull=times[sampleIndex].timeCull;
float timeDraw=times[sampleIndex].timeDraw;
float timeFrame=times[sampleIndex].timeFrame;
osg::Vec4 app_color(0.0f,1.0f,0.0f,1.0f);
osg::Vec4 cull_color(1.0f,0.0f,1.0f,1.0f);
osg::Vec4 draw_color(0.0f,1.0f,1.0f,1.0f);
osg::Vec4 swap_color(1.0f,0.5f,0.5f,1.0f);
osg::Vec4 frame_color(1.0f,1.0f,0.0f,1.0f);
char clin[72]; // buffer to print
glColor4fv((GLfloat * )&app_color);
sprintf(clin,"App %.2f ms.", timeApp);
displaytext((int)(.15f*tmax),(int)(0.98f*vh),clin);
glColor4fv((GLfloat * )&cull_color);
sprintf(clin,"Cull %.2f ms.", timeCull);
displaytext((int)(.35*tmax),(int)(0.98f*vh),clin);
glColor4fv((GLfloat * )&draw_color);
sprintf(clin,"Draw %.2f ms.", timeDraw);
displaytext((int)(.55*tmax),(int)(0.98f*vh),clin);
glColor4fv((GLfloat * )&frame_color);
sprintf(clin,"Frame %.2f ms.", timeFrame);
displaytext((int)(.75*tmax),(int)(0.98f*vh),clin);
/* osg::notify(osg::NOTICE) << "Time of App "<<timeApp<<"ms "<< std::endl;
osg::notify(osg::NOTICE) << "Time of Cull "<<timeCull<<"ms "<< std::endl;
osg::notify(osg::NOTICE) << "Time of Draw "<<timeDraw<<"ms "<< std::endl;
osg::notify(osg::NOTICE) << "Frame time "<<frameTime<< std::endl;
osg::notify(osg::NOTICE) << "frameRate() = "<<frameRate()<< std::endl;*/
glLineWidth(2.0f);
glBegin(GL_LINE_LOOP );
// yellow frame/grid in front of stats, units of .01 sec(?)
glColor3f(.6f,.6f,0.0f);
glVertex2f(0.0,0.97f*vh);
glVertex2f(tmax,0.97f*vh);
glVertex2f(tmax,0.88f*vh);
glVertex2f(0.0,0.88f*vh);
glEnd();
glBegin(GL_LINES);
// time marks
int i;
for (i=10; i<tmax; i+=10) {
if ((i%100) == 0) glColor3f(.6f,.0f,0.0f); // red mark every 0.1 sec
else glColor3f(.6f,.6f,0.0f); // yellow every 0.01 sec
glVertex2f(i,0.97f*vh);
glVertex2f(i,0.88f*vh);
}
// plot time for app, cull, draw, frame...
float tstart=0;
for (i=0; i<3; i++) {
glColor4fv((GLfloat * )&app_color);
glVertex2f(tstart,0.95f*vh);
glVertex2f(tstart+times[i].timeApp,0.95f*vh);
glColor4fv((GLfloat * )&cull_color);
glVertex2f(tstart+times[i].timeApp,0.93f*vh);
glVertex2f(tstart+times[i].timeApp+times[i].timeCull, 0.93f*vh);
glColor4fv((GLfloat * )&draw_color);
glVertex2f(tstart+times[i].timeApp+times[i].timeCull, 0.91f*vh);
glVertex2f(tstart+times[i].timeApp+times[i].timeCull+times[i].timeDraw, 0.91f*vh);
glColor4fv((GLfloat * )&swap_color);
glVertex2f(tstart+times[i].timeApp+times[i].timeCull+times[i].timeDraw, 0.90f*vh);
glVertex2f(tstart+times[i].timeFrame, 0.90f*vh);
tstart+=times[i].timeFrame;
}
glEnd();
glLineWidth(1.0f);
}
if (_printStats==osg::Statistics::STAT_PRIMS) { // yet more stats - add triangles, number of strips...
/*
* Use the new renderStage. Required mods to RenderBin.cpp, and RenderStage.cpp (add getPrims)
* also needed to define a new class called Statistic (see osgUtil/Statistic).
* RO, July 2001.
*/
ViewportList::iterator itr;
Statistics primStats;
for(itr=_viewportList.begin();
itr!=_viewportList.end();
++itr)
{
osgUtil::RenderStage *stage = itr->sceneView->getRenderStage();
stage->getPrims(&primStats);
}
primStats.setType(Statistics::STAT_PRIMS); // full print out required
writePrims((int)(0.86f*vh),primStats);
maxbins=(primStats.getBins()>maxbins)?primStats.getBins():maxbins;
}
if (_printStats==Statistics::STAT_PRIMSPERBIN) { // more stats - add triangles, number of strips... as seen per bin
/*
* Use the new renderStage. Required mods to RenderBin.cpp, and RenderStage.cpp (add getPrims)
* also needed to define a new class called Statistic (see osgUtil/Statistic).
* RO, July 2001.
*/
Statistics *primStats=new Statistics[maxbins]; // array of bin stats
ViewportList::iterator itr;
for(itr=_viewportList.begin();
itr!=_viewportList.end();
++itr)
{
osgUtil::RenderStage *stage = itr->sceneView->getRenderStage();
stage->getPrims(primStats, maxbins);
}
int nbinsUsed=(primStats[0].getBins()<maxbins)?primStats[0].getBins():maxbins;
int ntop=0; // offset
for (int i=0; i<nbinsUsed; i++) {
primStats[i].setType(Statistics::STAT_PRIMSPERBIN); // cuts out vertices & triangles to save space on screen
ntop+=writePrims((int)(0.96f*vh-ntop),primStats[i]);
//osg::notify(osg::INFO) << "ntop "<< ntop<< std::endl;
}
maxbins=(primStats[0].getBins()>maxbins)?primStats[0].getBins():maxbins;
osgDelete [] primStats; // free up
}
if (_printStats==Statistics::STAT_DC) { // yet more stats - read the depth complexity
int wid=_ww, ht=_wh; // temporary local screen size - must change during this section
if (wid>0 && ht>0) {
const int blsize=16;
char *clin=new char[wid/blsize+2]; // buffer to print dc
char ctext[128]; // buffer to print details
float mdc=0;
GLubyte *buffer=new GLubyte[wid*ht];
if (buffer) {
glPixelStorei(GL_PACK_ALIGNMENT, 1); // no extra bytes at ends of rows- easier to analyse
glColor3f(.9f,.9f,0.0f);
glReadPixels(0,0,wid,ht, GL_STENCIL_INDEX ,GL_UNSIGNED_BYTE, buffer);
for (int j=0; j<ht; j+=blsize) { // break up screen into blsize*blsize pixel blocks
char *clpt=clin; // moves across the clin to display lines of text
for (int i=0; i<wid; i+=blsize) { // horizontal pixel blocks
int dc=0;
int nav=0; // number of pixels averaged for DC calc
for (int jj=j; jj<j+blsize; jj++) {
for (int ii=i; ii<i+blsize; ii++) {
if (jj<ht && ii<wid && jj>=0 && ii>=0) {
dc+=buffer[ii+ (ht-jj-1)*wid];
nav++;
}
}
}
mdc+=dc;
if (dc<nav) *clpt= ' '+(10*dc)/nav; // fine detail in dc=[0,1]; 0.1 increment in display, space for empty areas
else if (dc<80*nav) *clpt= '0'+dc/nav; // show 1-9 for DC=1-9; then ascii to 127
else *clpt= '+'; // too large a DC - use + to show over limit
clpt++;
}
*clpt='\0';
displaytext(0,(int)(0.84f*vh-(j*12)/blsize),clin); // display average DC over the blsize box
}
sprintf(ctext, "Pixels hit %.1f Mean DC %.2f: %4d by %4d pixels.", mdc, mdc/(wid*ht), wid, ht);
displaytext(0,(int)(0.86f*vh),ctext);
glEnable(GL_STENCIL_TEST); // re-enable stencil buffer counting
osgDelete [] buffer;
}
osgDelete [] clin;
}
}
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
glMatrixMode( GL_PROJECTION );
glPopMatrix();
}
void Viewer::display()
{
_frameStamp->setFrameNumber(_frameStamp->getFrameNumber()+1);
_frameStamp->setReferenceTime(clockSeconds());
// application traverasal.
times[2].timeApp=0.0f;
// cull traverasal.
times[2].timeCull=0.0f;
// draw traverasal.
times[2].timeDraw=0.0f;
for(unsigned int i = 0; i < getNumViewports(); i++ )
{
// application traverasal.
times[2].timeApp+=app(i);
// cull traverasal.
times[2].timeCull+=cull(i);
if (_printStats>=1) glFinish();
// draw traverasal.
times[2].timeDraw+=draw(i);
if (_printStats==Statistics::STAT_PRIMSPERVIEW)
{ // gwm - get and show stats in each window
showStats(i);
}
}
if (_printStats>1) glFinish();
times[2].frameend=updateFrameTick(); // absolute time
times[2].timeFrame=frameSeconds()*1000;
if (_printStats) {
showStats(0); // output selected stats at this point - timing graph.
times[0]=times[1]; // move the times buffers down
times[1]=times[2];
}
glutSwapBuffers(); // moved after draw of stats & glFinish() to get accurate timing (excluding stat draw!)
// cout << "Time elapsed "<<_timer.delta_s(_initialTick,_timer.tick())<< std::endl;
if (_printStats>1) glFinish();
#ifdef SGV_USE_RTFS
fs->frame();
#endif
}
void Viewer::reshape(GLint w, GLint h)
{
Window::reshape(w,h);
// Propagate new window size to viewports
for(ViewportList::iterator itr=_viewportList.begin();
itr!=_viewportList.end();
++itr)
{
osgUtil::SceneView* sceneView = itr->sceneView.get();
int view[4] = { int(itr->viewport[0]*_ww), int(itr->viewport[1]*_wh),
int(itr->viewport[2]*_ww), int(itr->viewport[3]*_wh) };
sceneView->setViewport(view[0], view[1], view[2], view[3]);
osg::ref_ptr<GLUTEventAdapter> ea = osgNew GLUTEventAdapter;
ea->adaptResize(clockSeconds(),
view[0], view[1],
view[0]+view[2], view[1]+view[3]);
if (itr->_cameraManipulator->handle(*ea,*this))
{
// osg::notify(osg::INFO) << "Handled reshape "<< std::endl;
}
for ( EventHandlerList::iterator eh = itr->_eventHandlerList.begin();
eh != itr->_eventHandlerList.end(); eh++ ) {
if ( eh->valid() ) {
if ( (*eh)->handle(*ea,*this) ) {
// event handler handle this call.
}
}
}
}
}
void Viewer::mouseMotion(int x, int y)
{
osg::ref_ptr<GLUTEventAdapter> ea = osgNew GLUTEventAdapter;
ea->adaptMouseMotion(clockSeconds(),x,y);
bool handled = false;
for ( EventHandlerList::iterator eh =
_viewportList[_focusedViewport]._eventHandlerList.begin();
eh != _viewportList[_focusedViewport]._eventHandlerList.end();
eh++ ) {
if ( eh->valid() ) {
if ( (*eh)->handle(*ea,*this) ) {
handled = true;
break;
}
}
}
if ( !handled ) {
if ( _viewportList[_focusedViewport]._cameraManipulator->handle(
*ea,*this) ) {
// osg::notify(osg::INFO) << "Handled mouseMotion "<<ea->_buttonMask<<" x="<<ea->_mx<<" y="<<ea->_my<< std::endl;
}
}
_mx = x;
_my = y;
}
void Viewer::mousePassiveMotion(int x, int y)
{
osg::ref_ptr<GLUTEventAdapter> ea = osgNew GLUTEventAdapter;
ea->adaptMousePassiveMotion(clockSeconds(),x,y);
// Switch viewport focus if no buttons are pressed
if (ea->getButtonMask() == 0)
{
int focus = mapWindowXYToViewport(x,y);
if (focus >= 0 && focus != int(_focusedViewport))
setFocusedViewport(focus);
}
bool handled = false;
for ( EventHandlerList::iterator eh =
_viewportList[_focusedViewport]._eventHandlerList.begin();
eh != _viewportList[_focusedViewport]._eventHandlerList.end();
eh++ ) {
if ( eh->valid() ) {
if ( (*eh)->handle(*ea,*this) ) {
handled = true;
break;
}
}
}
if ( !handled ) {
if ( _viewportList[_focusedViewport]._cameraManipulator->handle(
*ea,*this) ) {
// osg::notify(osg::INFO) << "Handled mousePassiveMotion "<<ea->_buttonMask<<" x="<<ea->_mx<<" y="<<ea->_my<< std::endl;
}
}
}
void Viewer::mouse(int button, int state, int x, int y)
{
osg::ref_ptr<GLUTEventAdapter> ea = osgNew GLUTEventAdapter;
ea->adaptMouse(clockSeconds(),button,state,x,y);
// Switch viewport focus if button is pressed, and it is the only one
unsigned mask = ea->getButtonMask();
if (state == GLUT_DOWN &&
(mask == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON ||
mask == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON ||
mask == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON))
{
int focus = mapWindowXYToViewport(x,y);
if (focus >= 0 && focus != int(_focusedViewport))
setFocusedViewport(focus);
}
bool handled = false;
for ( EventHandlerList::iterator eh =
_viewportList[_focusedViewport]._eventHandlerList.begin();
eh != _viewportList[_focusedViewport]._eventHandlerList.end();
eh++ ) {
if ( eh->valid() ) {
if ( (*eh)->handle(*ea,*this) ) {
handled = true;
break;
}
}
}
if ( !handled ) {
if ( _viewportList[_focusedViewport]._cameraManipulator->handle(
*ea,*this) ) {
// osg::notify(osg::INFO) << "Handled mouse "<<ea->_buttonMask<<" x="<<ea->_mx<<" y="<<ea->_my<< std::endl;
}
}
}
void Viewer::keyboard(unsigned char key, int x, int y)
{
osg::ref_ptr<GLUTEventAdapter> ea = osgNew GLUTEventAdapter;
ea->adaptKeyboard(clockSeconds(),key,x,y);
for ( EventHandlerList::iterator eh =
_viewportList[_focusedViewport]._eventHandlerList.begin();
eh != _viewportList[_focusedViewport]._eventHandlerList.end();
eh++ ) {
if ( eh->valid() ) {
if ( (*eh)->handle(*ea,*this) ) {
return;
}
}
}
if ( _viewportList[_focusedViewport]._cameraManipulator->handle(
*ea,*this) ) {
return;
}
if (key>='1' && key<='4')
{
int pos = key-'1';
selectCameraManipulator(pos,_focusedViewport);
}
osgUtil::SceneView* sceneView = getViewportSceneView(_focusedViewport);
osg::StateSet* globalStateSet = sceneView->getGlobalStateSet();
if (!globalStateSet)
{
globalStateSet = osgNew osg::StateSet;
sceneView->setGlobalStateSet(globalStateSet);
}
switch( key )
{
case '>' :
{
osg::DisplaySettings* ds = const_cast<osg::DisplaySettings*>(sceneView->getDisplaySettings());
if (ds) ds->setEyeSeparation(ds->getEyeSeparation()*1.5f);
}
break;
case '<' :
{
osg::DisplaySettings* ds = const_cast<osg::DisplaySettings*>(sceneView->getDisplaySettings());
if (ds) ds->setEyeSeparation(ds->getEyeSeparation()/1.5f);
}
break;
case '7' :
sceneView->setBackgroundColor(osg::Vec4(0.0f,0.0f,0.0f,1.0f));
break;
case '8' :
sceneView->setBackgroundColor(osg::Vec4(0.2f, 0.2f, 0.4f, 1.0f));
break;
case '9' :
sceneView->setBackgroundColor(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
break;
case '/' :
if (sceneView->getLODScale()>0.5) sceneView->setLODScale(sceneView->getLODScale()/1.5f);
break;
case '*' :
if (sceneView->getLODScale()<30) sceneView->setLODScale(sceneView->getLODScale()*1.5f);
break;
case '+' :
#ifdef SGV_USE_RTFS
frame_rate <<= 1;
fs->stop();
fs->setUpdateRate( frame_rate );
fs->start();
#endif
break;
case '-' :
#ifdef SGV_USE_RTFS
frame_rate >>= 1;
if( frame_rate < 1 ) frame_rate = 1;
fs->stop();
fs->setUpdateRate( frame_rate );
fs->start();
#endif
break;
case 'd' :
_useDisplayLists = !_useDisplayLists;
if (_useDisplayLists)
{
// traverse the scene graph setting up all osg::Drawable's so they will use
// OpenGL display lists.
osgUtil::DisplayListVisitor dlv(osgUtil::DisplayListVisitor::SWITCH_ON_DISPLAY_LISTS);
sceneView->getSceneData()->accept(dlv);
osg::notify(osg::NOTICE) << "Switched on use of OpenGL Display Lists."<< std::endl;
}
else
{
// traverse the scene graph setting up all osg::Drawable's so they will use
// OpenGL display lists.
osgUtil::DisplayListVisitor dlv(osgUtil::DisplayListVisitor::SWITCH_OFF_DISPLAY_LISTS);
sceneView->getSceneData()->accept(dlv);
osg::notify(osg::NOTICE) << "Switched off use of OpenGL Display Lists."<< std::endl;
}
break;
case 'p' :
if (_printStats==Statistics::STAT_DC) glDisable(GL_STENCIL_TEST); // switch off stencil counting
_printStats++; //gwm jul 2001 range of possible outputs, 0-4 = !_printStats;
if (_printStats>=Statistics::STAT_RESTART) _printStats=0;
if (getNumViewports()<=1 && _printStats==Statistics::STAT_PRIMSPERVIEW) _printStats++; // no need for these stats as only one view
if (_printStats==Statistics::STAT_DC) { // count depth complexity by incrementing the stencil buffer every
// time a pixel is hit
GLint nsten=0; // Number of stencil planes available
glGetIntegerv(GL_STENCIL_BITS , &nsten);
if (nsten>0) {
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_INCR ,GL_INCR ,GL_INCR);
} else {// skip this option
_printStats++;
}
}
break;
case 's' :
{
flat_shade = 1 - flat_shade ;
osg::StateSet* stateset = globalStateSet;
osg::ShadeModel* shademodel = dynamic_cast<osg::ShadeModel*>(stateset->getAttribute(osg::StateAttribute::SHADEMODEL));
if (!shademodel)
{
shademodel = osgNew osg::ShadeModel;
stateset->setAttribute(shademodel,osg::StateAttribute::OVERRIDE);
}
if( flat_shade )
shademodel->setMode( osg::ShadeModel::FLAT );
else
shademodel->setMode( osg::ShadeModel::SMOOTH );
break;
}
case 'S' :
{
osg::notify(osg::NOTICE) << "Smoothing scene..."<< std::endl;
osgUtil::SmoothingVisitor sv;
sceneView->getSceneData()->accept(sv);
osg::notify(osg::NOTICE) << "Smoothed scene."<< std::endl;
}
break;
case 'R' :
{
osg::notify(osg::NOTICE) << "Tri Striping scene..."<< std::endl;
osgUtil::TriStripVisitor tsv;
sceneView->getSceneData()->accept(tsv);
osg::notify(osg::NOTICE) << "Tri Striping scene scene."<< std::endl;
}
break;
case 'b' :
backface = 1 - backface;
if( backface )
globalStateSet->setMode(GL_CULL_FACE,osg::StateAttribute::ON);
else
globalStateSet->setMode(GL_CULL_FACE,osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
break;
case 'l' :
lighting = 1 - lighting ;
if( lighting )
globalStateSet->setMode(GL_LIGHTING,osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
else
globalStateSet->setMode(GL_LIGHTING,osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
break;
case 'L' :
{
osgUtil::SceneView::LightingMode lm= sceneView->getLightingMode();
switch(lm)
{
case(osgUtil::SceneView::HEADLIGHT) : lm = osgUtil::SceneView::SKY_LIGHT; break;
case(osgUtil::SceneView::SKY_LIGHT) : lm = osgUtil::SceneView::NO_SCENEVIEW_LIGHT; break;
case(osgUtil::SceneView::NO_SCENEVIEW_LIGHT) : lm = osgUtil::SceneView::HEADLIGHT; break;
}
sceneView->setLightingMode(lm);
break;
}
case 't' :
texture = 1 - texture;
if (texture)
{
globalStateSet->setTextureModeToInherit(0,GL_TEXTURE_2D);
// globalStateSet->setAttributeToInherit(osg::StateAttribute::TEXTURE);
}
else
{
// use blank texture to override all local texture in scene graph.
// thus causing them to all use the same texture attribute, hence
// preventing a state attribute change due to unused textures.
globalStateSet->setTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
// static osg::ref_ptr<osg::Texture> blank_texture = osgNew osg::Texture2D;
// globalStateSet->setTextureAttribute(0,blank_texture.get());
}
break;
case 'T' :
{
osg::LightModel* lightmodel = dynamic_cast<LightModel*>(globalStateSet->getAttribute(osg::StateAttribute::LIGHTMODEL));
if (lightmodel)
{
lightmodel = osgNew osg::LightModel;
globalStateSet->setAttribute(lightmodel);
}
lightmodel->setTwoSided(!lightmodel->getTwoSided());
}
break;
case 'w' :
{
polymode = (polymode+1)%3;
osg::PolygonMode* polyModeObj = osgNew osg::PolygonMode;
polyModeObj->setMode(osg::PolygonMode::FRONT_AND_BACK,polymodes[polymode]);
globalStateSet->setAttribute(polyModeObj);
}
break;
case 'f' :
toggleFullScreen();
break;
case 'o' :
if (sceneView->getSceneData() && osgDB::writeNodeFile(*sceneView->getSceneData(), _saveFileName))
{
osg::notify(osg::NOTICE) << "Saved scene to '"<<_saveFileName<<"'"<< std::endl;
}
break;
case 'c' :
_smallFeatureCullingActive = !_smallFeatureCullingActive;
sceneView->setCullingMode((osgUtil::CullVisitor::CullingMode)
((_smallFeatureCullingActive ? osgUtil::CullVisitor::SMALL_FEATURE_CULLING : osgUtil::CullVisitor::NO_CULLING) |
(_viewFrustumCullingActive ? osgUtil::CullVisitor::VIEW_FRUSTUM_CULLING : osgUtil::CullVisitor::NO_CULLING)));
if (_smallFeatureCullingActive)
{
osg::notify(osg::NOTICE) << "Small feature culling switched on "<< std::endl;
}
else
{
osg::notify(osg::NOTICE) << "Small feature culling switched off "<< std::endl;
}
break;
case 'C' :
_viewFrustumCullingActive = !_viewFrustumCullingActive;
if (_viewFrustumCullingActive)
{
osg::notify(osg::NOTICE) << "View frustum culling switched on "<< std::endl;
}
else
{
osg::notify(osg::NOTICE) << "View frustum culling switched off "<< std::endl;
}
sceneView->setCullingMode((osgUtil::CullVisitor::CullingMode)
((_smallFeatureCullingActive ? osgUtil::CullVisitor::SMALL_FEATURE_CULLING : osgUtil::CullVisitor::NO_CULLING) |
(_viewFrustumCullingActive ? osgUtil::CullVisitor::VIEW_FRUSTUM_CULLING : osgUtil::CullVisitor::NO_CULLING)));
break;
case 'P' :
sceneView->setPrioritizeTextures(!sceneView->getPrioritizeTextures());
if (sceneView->getPrioritizeTextures())
{
osg::notify(osg::NOTICE) << "Prioritize textures switched on "<< std::endl;
}
else
{
osg::notify(osg::NOTICE) << "Prioritize textures switched off "<< std::endl;
}
break;
case '?' :
case 'h' :
help(osg::notify(osg::NOTICE));
break;
case 'O' :
{
osg::ref_ptr<osg::Viewport> viewport = osgNew osg::Viewport;
viewport->setViewport(_wx,_wy,_ww,_wh);
std::string filename("screenshot.bmp");
glReadBuffer(GL_FRONT);
osg::ref_ptr<Image> image = osgNew osg::Image;
image->readPixels(viewport->x(),viewport->y(),viewport->width(),viewport->height(),
GL_RGB,GL_UNSIGNED_BYTE);
osgDB::writeImageFile(*image,filename);
osg::notify(osg::NOTICE) << "Saved screen image to `"<<filename<<"`"<< std::endl;
}
break;
case 'v' :
{
osg::notify(osg::NOTICE) << "Creating occluders"<< std::endl;
osg::CollectOccludersVisitor cov;
cov.setCreateDrawablesOnOccludeNodes(true);
cov.pushViewport(sceneView->getViewport());
if (sceneView->getProjectionMatrix()) cov.pushProjectionMatrix(sceneView->getProjectionMatrix());
else if (sceneView->getCamera()) cov.pushProjectionMatrix(osgNew Matrix(sceneView->getCamera()->getProjectionMatrix()));
else cov.pushProjectionMatrix(osgNew Matrix());
if (sceneView->getModelViewMatrix()) cov.pushModelViewMatrix(sceneView->getModelViewMatrix());
else if (sceneView->getCamera()) cov.pushModelViewMatrix(osgNew Matrix(sceneView->getCamera()->getModelViewMatrix()));
else cov.pushModelViewMatrix(osgNew Matrix());
sceneView->getSceneData()->accept(cov);
cov.popModelViewMatrix();
cov.popProjectionMatrix();
cov.popViewport();
}
break;
case 'i' :
case 'r' :
{
osg::notify(osg::NOTICE) << "***** Intersecting **************"<< std::endl;
osg::Vec3 near_point,far_point;
if (!sceneView->projectWindowXYIntoObject(x,_wh-y,near_point,far_point))
{
osg::notify(osg::NOTICE) << "Failed to calculate intersection ray."<< std::endl;
return;
}
osg::ref_ptr<osg::LineSegment> lineSegment = osgNew osg::LineSegment;
lineSegment->set(near_point,far_point);
osg::notify(osg::NOTICE) << "start("<<lineSegment->start()<<") end("<<lineSegment->end()<<")"<< std::endl;
osgUtil::IntersectVisitor iv;
iv.addLineSegment(lineSegment.get());
float startTime = clockSeconds();
sceneView->getSceneData()->accept(iv);
float endTime = clockSeconds();
osg::notify(osg::NOTICE) << "Time for interesection = "<<(endTime-startTime)*1000<<"ms"<< std::endl;
if (iv.hits())
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(lineSegment.get());
for(osgUtil::IntersectVisitor::HitList::iterator hitr=hitList.begin();
hitr!=hitList.end();
++hitr)
{
osg::Vec3 ip = hitr->getLocalIntersectPoint();
osg::Vec3 in = hitr->getLocalIntersectNormal();
osg::Geode* geode = hitr->_geode.get();
osg::notify(osg::NOTICE) << " Itersection Point ("<<ip<<") Normal ("<<in<<")"<< std::endl;
if (hitr->_matrix.valid())
{
osg::Vec3 ipEye = hitr->getWorldIntersectPoint();
osg::Vec3 inEye = hitr->getWorldIntersectNormal();
inEye.normalize();
if (geode) osg::notify(osg::NOTICE) << "Geode '"<<geode->getName()<< std::endl;
osg::notify(osg::NOTICE) << " Eye Itersection Point ("<<ipEye<<") Normal ("<<inEye<<")"<< std::endl;
}
if (key=='r' && geode)
{
// remove geoset..
osg::Drawable* drawable = hitr->_drawable.get();
osg::notify(osg::NOTICE) << " drawable ("<<drawable<<") "<<geode->removeDrawable(drawable)<<")"<< std::endl;
}
}
}
osg::notify(osg::NOTICE) << std::endl << std::endl;
}
break;
case 'y':
case 'Y':
{
osg::Fog* globalFog = dynamic_cast<osg::Fog*>(globalStateSet->getAttribute(osg::StateAttribute::FOG));
if(!globalFog)
{
globalFog = new osg::Fog;
globalFog->setColor(osg::Vec4(0.9,0.9,0.9,1.0));
globalFog->setDensity(0.01f);
globalStateSet->setAttributeAndModes(globalFog,osg::StateAttribute::ON);
}
//increase/reduce fog:
if(globalFog)
{
float density = globalFog->getDensity();
if (key=='y') density -= 0.001;
else density += 0.001;
if (density<0.0f) density=0.0f;
std::cout<<"setting fog density "<<density<<std::endl;
globalFog->setDensity(density);
}
}
break;
case 'Z' :
case 'z' :
if (getRecordingAnimationPath())
{
// have already been recording so switch of recording.
setRecordingAnimationPath(false);
osg::notify(osg::NOTICE) << "Finished recording camera animation, press 'Z' to reply."<< std::endl;
if (getAnimationPath())
{
std::ofstream fout("saved_animation.path");
const AnimationPath::TimeControlPointMap& tcpm = getAnimationPath()->getTimeControlPointMap();
for(AnimationPath::TimeControlPointMap::const_iterator tcpmitr=tcpm.begin();
tcpmitr!=tcpm.end();
++tcpmitr)
{
const AnimationPath::ControlPoint& cp = tcpmitr->second;
fout<<tcpmitr->first<<" "<<cp._position<<" "<<cp._rotation<<std::endl;
}
fout.close();
osg::notify(osg::NOTICE) << "Saved camera animation to 'saved_animation.path'"<< std::endl;
}
}
else if (key=='z')
{
setRecordingAnimationPath(true);
setAnimationPath(new osg::AnimationPath());
getAnimationPath()->setLoopMode(osg::AnimationPath::LOOP);
osg::notify(osg::NOTICE) << "Recording camera animation, press 'z' to finish recording."<< std::endl;
}
if (key=='Z')
{
osgGA::AnimationPathManipulator* apm = 0;
int apmNo = 0;
CameraManipList& cmlist = _viewportList[_focusedViewport]._cameraManipList;
for(CameraManipList::iterator cmlitr=cmlist.begin();
cmlitr!=cmlist.end() && apm==0;
++cmlitr,++apmNo)
{
apm = dynamic_cast<osgGA::AnimationPathManipulator*>(cmlitr->get());
}
if (!apm)
{
apm = new osgGA::AnimationPathManipulator();
apmNo = registerCameraManipulator(apm,_focusedViewport);
}
apm->setAnimationPath(getAnimationPath());
apm->home(*ea,*this);
selectCameraManipulator(apmNo,_focusedViewport);
}
break;
case 27 :
_exit = true;
//
// // Escape
// #ifdef __MWERKS__
// std::exit(0); // avoid collision of std::exit(..) / exit(..) compile errors.
// #else
// exit(0);
// #endif
// break;
}
}
void Viewer::help(std::ostream& fout)
{
fout << std::endl
<<"Scene Graph Viewer (sgv) keyboard bindings:"<< std::endl
<< std::endl
<<"1 Select the trackball camera manipulator."<< std::endl
<<" Left mouse button - rotate,"<< std::endl
<<" Middle (or Left & Right) mouse button - pan,"<< std::endl
<<" Right mouse button - zoom."<< std::endl
<<"2 Select the flight camera manipulator."<< std::endl
<<" Left mouse button - speed up,"<< std::endl
<<" Middle (or Left & Right) mouse button - stop,"<< std::endl
<<" Right mouse button - slow down, reverse."<< std::endl
<<" Move mouse left to roll left, right to roll right."<< std::endl
<<" Move mouse back (down) to pitch nose up, forward to pitch down."<< std::endl
<<" In mode Q, the default, selected by pressing 'q'"<< std::endl
<<" The flight path is yawed automatically into the turn to"<< std::endl
<<" produce a similar effect as flying an aircaft."<< std::endl
<<" In mode A, selected by pressing 'a'"<< std::endl
<<" The flight path is not yawed automatically into the turn,"<< std::endl
<<" producing a similar effect as space/marine flight."<< std::endl
<<"3 Select the drive camera manipulator."<< std::endl
<<" In mode Q, the default, selected by pressing 'q'"<< std::endl
<<" Move mouse left to turn left, right to turn right."<< std::endl
<<" Move mouse back (down) to reverse, forward to drive forward."<< std::endl
<<" In mode A, selected by pressing 'a'"<< std::endl
<<" Move mouse left to turn left, right to turn right."<< std::endl
<<" Left mouse button - speed up,"<< std::endl
<<" Middle (or Left & Right) mouse button - stop,"<< std::endl
<<" Right mouse button - slow down, reverse."<< std::endl
<< std::endl
<<"+ Half the frame delay which speeds up the frame rate on Linux and Windows."<< std::endl
<<"- Double the frame delay and therefore reduce the frame rate on Linux"<< std::endl
<<" and Windows."<< std::endl
<< std::endl
<<"/ Divide the Level-Of-Detail (LOD) bias by 1.5, to encourage the"<< std::endl
<<" selection of more complex LOD children."<< std::endl
<<"* Multiple the Level-of-Detail (LOD) bias by 1.5, to encourage the"<< std::endl
<<" selection of less complex LOD children."<< std::endl
<< std::endl
<<"c Toggle Small Feature Culling on or off."<< std::endl
<<"C Toggle View Frustum Culling on or off."<< std::endl
<<"d Toggle use of OpenGL's display lists."<< std::endl
<<"b Toggle OpenGL's backface culling."<< std::endl
<<"t Toggle OpenGL texturing on or off."<< std::endl
<<"T Toggle OpenGL two-sided lighting on or off."<< std::endl
<<"l Toggle OpenGL lighting on or off."<< std::endl
<<"L Toggle SceneView lighting mode between HEADLIGHT, SKY_LIGHT"<< std::endl
<<" and NO_SCENEVIEW_LIGHT."<< std::endl
<<"s Toggle OpenGL shade model between flat and smooth shading."<< std::endl
<<"S Apply osgUtil::SmoothingVisitor to the scene."<< std::endl
<<"w Toggle OpenGL polygon mode between solid, wireframe and points modes."<< std::endl
<< std::endl
<<"i Calculate and report the intersections with the scene under the"<< std::endl
<<" current mouse x and mouse y position."<< std::endl
<< std::endl
<<"r Calculate and report the intersections with the scene under the"<< std::endl
<<" current mouse x and mouse y position and osgDelete the nearest"<< std::endl
<<" interesected geoset."<< std::endl
<< std::endl
<<"7 Set the background color to black."<< std::endl
<<"8 Set the background color to blue."<< std::endl
<<"9 Set the background color to white."<< std::endl
<< std::endl
<<"p Print frame rate statistics on each frame."<< std::endl
<<"o Output the loaded scene to 'saved_model.osg'."<< std::endl
<<"?/h Print out sgv's keyboard bindings."<< std::endl
<<"f Toggle between fullscreen and the previous window size. Note, GLUT"<< std::endl
<<" fullscreen works properly on Windows and Irix, but on Linux"<< std::endl
<<" it just maximizes the window and leaves the window's borders."<< std::endl
<<" If started in full screen mode on Linux, window will be borderless"<< std::endl
<<" and will resize down, but will remain borderless."<< std::endl
<< std::endl
<<"y Reduce fog density."<< std::endl
<<"Y Increase fog density."<< std::endl
<< std::endl
<<"z Toggle recording of camera path."<< std::endl
<<"Z Reply recorded camera path."<< std::endl
<<"Space Reset scene to the default view."<< std::endl
<<"Esc Exit sgv."<< std::endl;
}
osg::Timer_t Viewer::clockTick()
{
return _timer.tick();
}
osg::Timer_t Viewer::frameTick()
{
return _frameTick;
}
// update time from the current frame update and the previous one.
osg::Timer_t Viewer::updateFrameTick()
{
_lastFrameTick = _frameTick;
_frameTick = _timer.tick();
return _frameTick;
}
bool Viewer::run()
{
{
// Reset the views of all of SceneViews
osg::ref_ptr<GLUTEventAdapter> ea = osgNew GLUTEventAdapter;
for(ViewportList::iterator itr=_viewportList.begin();
itr!=_viewportList.end();
++itr)
{
itr->_cameraManipulator->home(*ea,*this);
}
}
updateFrameTick();
return Window::run();
}
unsigned int Viewer::addViewport(osgUtil::SceneView* sv,
float x, float y, float width, float height)
{
ViewportDef def;
def.sceneView = sv;
def.viewport[0] = x;
def.viewport[1] = y;
def.viewport[2] = width;
def.viewport[3] = height;
if (!_viewportList.empty())
{
// force all the viewports to share the same state object as
// they all share the same graphics context.
osg::State* state = _viewportList.front().sceneView->getState();
def.sceneView->setState(state);
}
unsigned int pos = _viewportList.size();
_viewportList.push_back(def);
return pos;
}
/**
* Adds a default SceneView referring to the passed scene graph root.
*/
unsigned int Viewer::addViewport(osg::Node* rootnode,
float x, float y, float width, float height)
{
osgUtil::SceneView *sceneView = osgNew osgUtil::SceneView(_displaySettings.get());
sceneView->setDefaults();
sceneView->setSceneData(rootnode);
return addViewport( sceneView, x, y, width, height );
}
void Viewer::init(osg::Node* rootnode)
{
osg::notify(osg::WARN)<<"Warning - call to Viewer::init(osg::Node*) which is a deprecated method."<< std::endl;
osg::notify(osg::WARN)<<" This should be replaced with Viewer::addViewport(osg::Node*)."<< std::endl;
osg::notify(osg::WARN)<<" Automatically mapping init to addViewport."<< std::endl;
addViewport(rootnode);
}
//////////////////////////////////////////////////////////////////////
GLuint makeRasterFont(void)
{ // GWM creates a set of display lists which may be used to render a character string on the screen
// data from GWM's reading of the Windows ASCII_FIXED_FONT.
GLubyte rasters[][12] = { // ascii symbols 32-127, small font
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x00},
{0x00, 0x00, 0x28, 0x28, 0x7e, 0x14, 0x14, 0x14, 0x3f, 0x0a, 0x0a, 0x00},
{0x00, 0x00, 0x08, 0x1c, 0x22, 0x02, 0x1c, 0x20, 0x22, 0x1c, 0x08, 0x00},
{0x00, 0x00, 0x02, 0x45, 0x22, 0x10, 0x08, 0x04, 0x22, 0x51, 0x20, 0x00},
{0x00, 0x00, 0x3b, 0x44, 0x4a, 0x49, 0x30, 0x10, 0x20, 0x20, 0x18, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00},
{0x04, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x04, 0x00},
{0x10, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x10, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x36, 0x1c, 0x7f, 0x1c, 0x36, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x08, 0x08, 0x08, 0x7f, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00},
{0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00},
{0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00},
{0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x08, 0x00},
{0x00, 0x00, 0x3e, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x22, 0x1c, 0x00},
{0x00, 0x00, 0x1c, 0x22, 0x02, 0x02, 0x0c, 0x02, 0x02, 0x22, 0x1c, 0x00},
{0x00, 0x00, 0x0e, 0x04, 0x3e, 0x24, 0x14, 0x14, 0x0c, 0x0c, 0x04, 0x00},
{0x00, 0x00, 0x1c, 0x22, 0x02, 0x02, 0x3c, 0x20, 0x20, 0x20, 0x3e, 0x00},
{0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x10, 0x0c, 0x00},
{0x00, 0x00, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x22, 0x3e, 0x00},
{0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00},
{0x00, 0x00, 0x18, 0x04, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1c, 0x00},
{0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x04, 0x02, 0x02, 0x22, 0x1c, 0x00},
{0x00, 0x00, 0x1c, 0x20, 0x4e, 0x55, 0x55, 0x55, 0x4d, 0x21, 0x1e, 0x00},
{0x00, 0x00, 0x77, 0x22, 0x3e, 0x22, 0x14, 0x14, 0x08, 0x08, 0x18, 0x00},
{0x00, 0x00, 0x7e, 0x21, 0x21, 0x21, 0x3e, 0x21, 0x21, 0x21, 0x7e, 0x00},
{0x00, 0x00, 0x1e, 0x21, 0x40, 0x40, 0x40, 0x40, 0x40, 0x21, 0x1e, 0x00},
{0x00, 0x00, 0x7c, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x7c, 0x00},
{0x00, 0x00, 0x7f, 0x21, 0x20, 0x24, 0x3c, 0x24, 0x20, 0x21, 0x7f, 0x00},
{0x00, 0x00, 0x78, 0x20, 0x20, 0x24, 0x3c, 0x24, 0x20, 0x21, 0x7f, 0x00},
{0x00, 0x00, 0x1e, 0x21, 0x41, 0x47, 0x40, 0x40, 0x40, 0x21, 0x1e, 0x00},
{0x00, 0x00, 0x77, 0x22, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x22, 0x77, 0x00},
{0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00},
{0x00, 0x00, 0x38, 0x44, 0x44, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1e, 0x00},
{0x00, 0x00, 0x73, 0x22, 0x24, 0x38, 0x28, 0x24, 0x24, 0x22, 0x73, 0x00},
{0x00, 0x00, 0x7f, 0x11, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00},
{0x00, 0x00, 0x77, 0x22, 0x22, 0x2a, 0x2a, 0x36, 0x36, 0x22, 0x63, 0x00},
{0x00, 0x00, 0x72, 0x22, 0x26, 0x26, 0x2a, 0x32, 0x32, 0x22, 0x67, 0x00},
{0x00, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00},
{0x00, 0x00, 0x78, 0x20, 0x20, 0x20, 0x3e, 0x21, 0x21, 0x21, 0x7e, 0x00},
{0x00, 0x1b, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00},
{0x00, 0x00, 0x73, 0x22, 0x24, 0x24, 0x3e, 0x21, 0x21, 0x21, 0x7e, 0x00},
{0x00, 0x00, 0x3e, 0x41, 0x01, 0x01, 0x3e, 0x40, 0x40, 0x41, 0x3e, 0x00},
{0x00, 0x00, 0x1c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x49, 0x7f, 0x00},
{0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x77, 0x00},
{0x00, 0x00, 0x08, 0x08, 0x14, 0x14, 0x14, 0x22, 0x22, 0x22, 0x77, 0x00},
{0x00, 0x00, 0x14, 0x14, 0x2a, 0x2a, 0x2a, 0x22, 0x22, 0x22, 0x77, 0x00},
{0x00, 0x00, 0x77, 0x22, 0x14, 0x14, 0x08, 0x14, 0x14, 0x22, 0x77, 0x00},
{0x00, 0x00, 0x1c, 0x08, 0x08, 0x08, 0x14, 0x14, 0x22, 0x22, 0x77, 0x00},
{0x00, 0x00, 0x7f, 0x21, 0x10, 0x10, 0x08, 0x04, 0x04, 0x42, 0x7f, 0x00},
{0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1c, 0x00},
{0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00},
{0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1c, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08},
{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00},
{0x00, 0x00, 0x3d, 0x42, 0x42, 0x3e, 0x02, 0x3c, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x7e, 0x21, 0x21, 0x21, 0x21, 0x3e, 0x20, 0x20, 0x60, 0x00},
{0x00, 0x00, 0x3e, 0x41, 0x40, 0x40, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x3f, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x06, 0x00},
{0x00, 0x00, 0x3e, 0x41, 0x40, 0x7f, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x3c, 0x10, 0x10, 0x10, 0x10, 0x3c, 0x10, 0x10, 0x0c, 0x00},
{0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x3f, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x77, 0x22, 0x22, 0x22, 0x32, 0x2c, 0x20, 0x20, 0x60, 0x00},
{0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x08, 0x00},
{0x38, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x3c, 0x00, 0x00, 0x04, 0x00},
{0x00, 0x00, 0x63, 0x24, 0x38, 0x28, 0x24, 0x26, 0x20, 0x20, 0x60, 0x00},
{0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x18, 0x00},
{0x00, 0x00, 0x6b, 0x2a, 0x2a, 0x2a, 0x2a, 0x74, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x77, 0x22, 0x22, 0x22, 0x32, 0x6c, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x3e, 0x41, 0x41, 0x41, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x00},
{0x70, 0x20, 0x3e, 0x21, 0x21, 0x21, 0x21, 0x7e, 0x00, 0x00, 0x00, 0x00},
{0x07, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x3f, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x7c, 0x10, 0x10, 0x10, 0x19, 0x76, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x3e, 0x41, 0x06, 0x38, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x0c, 0x12, 0x10, 0x10, 0x10, 0x3c, 0x10, 0x10, 0x00, 0x00},
{0x00, 0x00, 0x1b, 0x26, 0x22, 0x22, 0x22, 0x66, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x08, 0x14, 0x14, 0x22, 0x22, 0x77, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x14, 0x14, 0x2a, 0x2a, 0x22, 0x77, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x77, 0x22, 0x1c, 0x1c, 0x22, 0x77, 0x00, 0x00, 0x00, 0x00},
{0x30, 0x08, 0x08, 0x14, 0x14, 0x22, 0x22, 0x77, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x7e, 0x22, 0x10, 0x08, 0x44, 0x7e, 0x00, 0x00, 0x00, 0x00},
{0x06, 0x08, 0x08, 0x08, 0x08, 0x30, 0x08, 0x08, 0x08, 0x08, 0x06, 0x00},
{0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08},
{0x30, 0x08, 0x08, 0x08, 0x08, 0x06, 0x08, 0x08, 0x08, 0x08, 0x30, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x49, 0x31, 0x00, 0x00},
{0x00, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x00, 0x00}
};
// the remaining lines of this routine are similar to code developed and published in the
// OPENGL big red book. However I have modified the code slightly, and
// SGI are not responsible for any errors, omissions etc.
static GLuint fontOffset=0; // first display list
if (!fontOffset) { // then make the raster fonts
GLuint i;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
fontOffset = glGenLists (128);
for (i = 32; i < 127; i++) {
glNewList(i+fontOffset, GL_COMPILE);
glBitmap(8, 12, 0.0, 2.0, 10.0, 0.0, rasters[i-32]);
glEndList();
}
}
return fontOffset;
}
void displaytext(int x, int y, char *s)
{ // GWM July 2001 statistics text display at xy text S
GLuint fontOffset=makeRasterFont(); // first display list
glRasterPos2i(x,y);
glListBase(fontOffset);
glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *) s);
glListBase(0);
// glPopAttrib ();
}
int writePrims( const int ypos, osg::Statistics& stats)
{
char clin[128]; // buffer to print
char ctmp[32];
char intro[32]; // start of first line
int npix=0; // offset from ypos
static char *prtypes[]=
{
" Point", // GL_POINTS 0x0000
" Lines", // GL_LINES 0x0001
" LnLoop", // GL_LINE_LOOP 0x0002
" LnStr", // GL_LINE_SRIP 0x0002
" Tris", // GL_TRIANGLES 0x0004
" TriStr", // GL_TRIANGLE_STRIP 0x0005
" TriFan", // GL_TRIANGLE_FAN 0x0006
" Quads", // GL_QUADS 0x0007
" QudStr", // GL_QUAD_STRIP 0x0008
" Poly" // GL_POLYGON 0x0009
};
glColor3f(.9f,.9f,0.0f);
if (stats.depth==1) sprintf(intro,"==> Bin %2d", stats._binNo);
else sprintf(intro,"General Stats: ");
sprintf(clin,"%s %d Drawables %d Lights %d Bins %d Impostors",
intro ,stats.numDrawables, stats.nlights, stats.nbins, stats.nimpostor);
displaytext(0,ypos-npix,clin);
npix+=24;
strcpy(clin," Total");
unsigned int totalNumPrimives = 0;
unsigned int totalNumIndices = 0;
osg::Statistics::PrimtiveValueMap::iterator pItr;
for(pItr=stats._primitiveCount.begin();
pItr!=stats._primitiveCount.end();
++pItr)
{
totalNumPrimives += (pItr->second.first);
totalNumIndices += (pItr->second.second);
strcat(clin, prtypes[pItr->first]);
}
displaytext(0,ypos-npix,clin);
npix+=12;
strcpy(clin,"Primitives: ");
sprintf(ctmp,"%7d", totalNumPrimives);
strcat(clin, ctmp);
for(pItr=stats._primitiveCount.begin();
pItr!=stats._primitiveCount.end();
++pItr)
{
sprintf(ctmp,"%7d", pItr->second.first);
strcat(clin, ctmp);
}
displaytext(0,ypos-npix,clin);
npix+=12;
strcpy(clin,"Indices: ");
sprintf(ctmp,"%7d", totalNumIndices);
strcat(clin, ctmp);
for(pItr=stats._primitiveCount.begin();
pItr!=stats._primitiveCount.end();
++pItr)
{
sprintf(ctmp,"%7d", pItr->second.second);
strcat(clin, ctmp);
}
displaytext(0,ypos-npix,clin);
npix+=12;
strcpy(clin,"Vertices: ");
sprintf(ctmp,"%7d", stats._vertexCount);
strcat(clin, ctmp);
displaytext(0,ypos-npix,clin);
npix+=12;
return npix;
}