Hi Robert,

I'm now testing static building of OSG and found a possible bug in the
present3D application. As static-link present3d should depend on
freetype, png, pdf and some other plugins, any mis-compiling of these
plugins will make present3d fail to be built. Some lirbaries like
poppler and cairo are not popular under Windows, so it is very common
that we don't have osgdb_pdf compiled and thus get errors when
building present3d. I've modified the CMakeLists and present3d.cpp to
avoid this problem.

Besides, it seems that there is another problem when using static
building: models are not able to be read, even with the USE_PLUGIN
macro. I've tested with both present3d and osgstaticviewer, and osg
and obj files, and found that the DynamicLibrary methods were still
called. But images and fonts (png, rgb and freetype) can be loaded
without problems, so I just wonder if some modification to osgDB
readNode() implementation has broken the static node reader/writer?

I'll try to go deeper in the following few days.

Cheers,

Wang Rui
/* -*-c++-*- Present3D - Copyright (C) 1999-2006 Robert Osfield 
 *
 * This software is open source and may be redistributed and/or modified under  
 * the terms of the GNU General Public License (GPL) version 2.0.
 * The full license is in LICENSE.txt file included with this distribution,.
 * 
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * include LICENSE.txt for more details.
*/

#include <osg/Geometry>
#include <osg/CameraNode>
#include <osg/Texture2D>
#include <osg/AutoTransform>
#include <osg/Notify>
#include <osg/io_utils>


#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgDB/FileNameUtils>
#include <osgUtil/Optimizer>

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

#include <OpenThreads/Thread>

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

#include <osgPresentation/SlideEventHandler>
#include <osgPresentation/SlideShowConstructor>

#include "ReadShowFile.h"
#include "PointsEventHandler.h"
#include "Cluster.h"
#include "ExportHTML.h"
#include "SpellChecker.h"

#include <sstream>
#include <fstream>
#include <iostream>

#include <string.h>

#ifdef USE_SDL
    #include "SDLIntegration.h"
#endif

#ifdef OSG_LIBRARY_STATIC

    // include the plugins we need
    USE_OSGPLUGIN(ive)
    USE_OSGPLUGIN(osg)
    USE_OSGPLUGIN(p3d)
    USE_OSGPLUGIN(paths)
    USE_OSGPLUGIN(rgb)
    USE_OSGPLUGIN(OpenFlight)
    USE_OSGPLUGIN(obj)

#ifdef USE_FREETYPE
    USE_OSGPLUGIN(freetype)
#endif

#ifdef USE_PNG
    USE_OSGPLUGIN(png)
#endif

#ifdef USE_JPEG
    USE_OSGPLUGIN(jpeg)
#endif

#ifdef USE_FFMPEG
    USE_OSGPLUGIN(ffmpeg)
#endif

#ifdef USE_POPPLER_CAIRO
    USE_OSGPLUGIN(pdf)
#endif

#ifdef USE_CURL
    USE_OSGPLUGIN(curl)
#endif

    // include the platform specific GraphicsWindow implementation.
    USE_GRAPHICSWINDOW()

#endif

static const char* s_version = "1.4 beta";

void setViewer(osgViewer::Viewer& viewer, float width, float height, float 
distance)
{
    double vfov = osg::RadiansToDegrees(atan2(height/2.0f,distance)*2.0);
    // double hfov = osg::RadiansToDegrees(atan2(width/2.0f,distance)*2.0);

    viewer.getCamera()->setProjectionMatrixAsPerspective( vfov, width/height, 
0.1, 1000.0);
}

#if 1

class RayFollowsMouseCallback : public osg::Drawable::EventCallback
{
    RayFollowsMouseCallback() {}

    /** do customized Event code. */
    virtual void event(osg::NodeVisitor* nv, osg::Drawable* drawable)
    {
        osg::Geometry* geometry = drawable->asGeometry();
        osgGA::EventVisitor* ev = dynamic_cast<osgGA::EventVisitor*>(nv);

        if (!ev || !geometry) return;

        osgGA::GUIActionAdapter* aa = ev->getActionAdapter();
        osgViewer::View* view = dynamic_cast<osgViewer::View*>(aa);
        if (!view) return;

        osg::Vec3Array* vertices = 
dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
        if (!vertices) return;

        osg::Camera* camera = view->getCamera();
        osg::Matrix VP =  camera->getViewMatrix() * 
camera->getProjectionMatrix();

        osg::Matrix inverse_VP;
        inverse_VP.invert(VP);

        osgGA::EventQueue::Events& events = ev->getEvents();
        for(osgGA::EventQueue::Events::iterator itr = events.begin();
            itr != events.end();
            ++itr)
        {
            handle(inverse_VP, *(*itr), vertices);
        }

    }

    void handle(const osg::Matrix& inverse_VP, osgGA::GUIEventAdapter& ea, 
osg::Vec3Array* vertices)
    {
        osg::Vec3d start_eye(ea.getXnormalized(), ea.getYnormalized(), 0.0);
        osg::Vec3d end_eye(ea.getXnormalized(), ea.getYnormalized(), 1.0);

        osg::Vec3d start_world = start_eye * inverse_VP;
        osg::Vec3d end_world = start_eye * inverse_VP;

        osg::notify(osg::NOTICE)<<"start_world="<<start_world<<std::endl;
        osg::notify(osg::NOTICE)<<"end_world="<<end_world<<std::endl;

        (*vertices)[0] = start_world;
        (*vertices)[1] = end_world;
    }
};

class FollowMouseCallback: public osgGA::GUIEventHandler
{
    public:

        virtual bool handle(const osgGA::GUIEventAdapter& 
ea,osgGA::GUIActionAdapter& aa, osg::Object* object, osg::NodeVisitor* nv)
        {
            osg::AutoTransform* transform = 
dynamic_cast<osg::AutoTransform*>(object);
            if (!transform) return false;

            switch(ea.getEventType())
            {
                case(osgGA::GUIEventAdapter::FRAME):
                //case(osgGA::GUIEventAdapter::MOVE):
                //case(osgGA::GUIEventAdapter::DRAG):
                {
                    osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);

                    transform->setNodeMask(0x0);

                    
osg::notify(osg::NOTICE)<<std::endl<<"ea.getGraphicsContext()="<<ea.getGraphicsContext()<<std::endl;
                    
osg::notify(osg::NOTICE)<<"ea.getWindowWidth()="<<ea.getWindowWidth()<<std::endl;
                    
osg::notify(osg::NOTICE)<<"ea.getWindowHeight()="<<ea.getWindowHeight()<<std::endl;
                    
osg::notify(osg::NOTICE)<<"ea.getX()="<<ea.getX()<<std::endl;
                    
osg::notify(osg::NOTICE)<<"ea.getXin()="<<ea.getXmin()<<std::endl;
                    
osg::notify(osg::NOTICE)<<"ea.getXmax()="<<ea.getXmax()<<std::endl;
                    
osg::notify(osg::NOTICE)<<"ea.getY()="<<ea.getY()<<std::endl;
                    
osg::notify(osg::NOTICE)<<"ea.getYin()="<<ea.getYmin()<<std::endl;
                    
osg::notify(osg::NOTICE)<<"ea.getYmax()="<<ea.getYmax()<<std::endl;

                    osg::Camera* camera = view->getCamera();
                    osg::Matrix VP =  camera->getViewMatrix() * 
camera->getProjectionMatrix();

                    osg::Matrix inverse_VP;
                    inverse_VP.invert(VP);

                    osg::Vec3d start_eye(ea.getXnormalized(), 
ea.getYnormalized(), 0.0);
                    osg::Vec3d end_eye(ea.getXnormalized(), 
ea.getYnormalized(), 1.0);

                    osg::Vec3d start_world = start_eye * inverse_VP;
                    osg::Vec3d end_world = start_eye * inverse_VP;

                    
osg::notify(osg::NOTICE)<<"start_world="<<start_world<<std::endl;
                    
osg::notify(osg::NOTICE)<<"end_world="<<end_world<<std::endl;

                    transform->setPosition(end_world);

                    transform->setNodeMask(0xffffffff);

                    break;
                }
                case(osgGA::GUIEventAdapter::KEYDOWN):
                {
                    if (ea.getKey()=='c')
                    {
                        for(unsigned int i=0; i< transform->getNumChildren(); 
++i)
                        {
                            osg::Node* node = transform->getChild(i);
                            node->setNodeMask(
                                node->getNodeMask()!=0 ?
                                0 :
                                0xffffff);
                        }
                    }
                    break;
                }
                default:
                    break;
            }
            return false;
        }

        virtual void accept(osgGA::GUIEventHandlerVisitor& v)
        {
            v.visit(*this);
        }

};

osg::Node* createCursorSubgraph(const std::string& filename, float size)
{
    osg::Geode* geode = new osg::Geode;

    size = 20.0f;

    osg::Geometry* geom = 
osg::createTexturedQuadGeometry(osg::Vec3(-size*0.5f,-size*0.5f,0.0f),osg::Vec3(size,0.0f,0.0f),osg::Vec3(0.0f,size,0.0f));

    osg::Image* image = osgDB::readImageFile(osgDB::findDataFile(filename));
    if (image)
    {
        osg::StateSet* stateset = geom->getOrCreateStateSet();
        stateset->setTextureAttributeAndModes(0, new 
osg::Texture2D(image),osg::StateAttribute::ON);
        stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
        // stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
        stateset->setRenderBinDetails(1000, "DepthSortedBin");
    }

    geode->addDrawable(geom);

    osg::AutoTransform* transform = new osg::AutoTransform;
    transform->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_CAMERA);
    transform->setAutoScaleToScreen(true);

    transform->addChild(geode);

    transform->setEventCallback(new FollowMouseCallback());

    return transform;

}
#else
class FollowMouseCallback: public osgGA::GUIEventHandler
{
    public:
    
        virtual bool handle(const osgGA::GUIEventAdapter& 
ea,osgGA::GUIActionAdapter&, osg::Object* object, osg::NodeVisitor*)
        {

            switch(ea.getEventType())
            {
                case(osgGA::GUIEventAdapter::MOVE):
                case(osgGA::GUIEventAdapter::DRAG):
                {
                    osg::Camera* camera = dynamic_cast<osg::Camera*>(object);
                    if (camera)
                    {
                        double x = ea.getXnormalized();
                        double y = ea.getYnormalized();

                        camera->setViewMatrix(osg::Matrixd::translate(x,y,0.0));
                    }
                    break;
                }
                case(osgGA::GUIEventAdapter::KEYDOWN):
                {
                    if (ea.getKey()=='c')
                    {
                        osg::Camera* camera = 
dynamic_cast<osg::Camera*>(object);
                        if (camera)
                        {
                            for(unsigned int i=0; i< camera->getNumChildren(); 
++i)
                            {
                                osg::Node* node = camera->getChild(i);
                                node->setNodeMask(
                                    node->getNodeMask()!=0 ?
                                    0 :
                                    0xffffff);
                            }
                        }
                    }
                    break;
                }
                default:
                    break;
            }
            return false;
        }
                
        virtual void accept(osgGA::GUIEventHandlerVisitor& v)
        {
            v.visit(*this);
        }

};
 
osg::Node* createCursorSubgraph(const std::string& filename, float size)
{
    osg::Geode* geode = new osg::Geode;

    osg::Geometry* geom = 
osg::createTexturedQuadGeometry(osg::Vec3(-size*0.5f,-size*0.5f,0.0f),osg::Vec3(size,0.0f,0.0f),osg::Vec3(0.0f,size,0.0f));

    osg::Image* image = osgDB::readImageFile(osgDB::findDataFile(filename));
    if (image)
    {
        osg::StateSet* stateset = geom->getOrCreateStateSet();
        stateset->setTextureAttributeAndModes(0, new 
osg::Texture2D(image),osg::StateAttribute::ON);
        stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
        stateset->setRenderBinDetails(1000, "DepthSortedBin");
    }
    
    geode->addDrawable(geom);
    
    osg::Camera* camera = new osg::Camera;

    // set the projection matrix
    camera->setProjectionMatrix(osg::Matrix::ortho2D(-1,1,-1,1));

    // set the view matrix    
    camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
    camera->setViewMatrix(osg::Matrix::identity());

    // only clear the depth buffer
    camera->setClearMask(GL_DEPTH_BUFFER_BIT);

    // draw subgraph after main camera view.
    camera->setRenderOrder(osg::CameraNode::NESTED_RENDER);

    camera->addChild(geode);
    
    camera->setEventCallback(new FollowMouseCallback());
    
    return camera;

}
#endif


enum P3DApplicationType
{
    VIEWER,
    MASTER,
    SLAVE
};



int main( int argc, char **argv )
{
    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);
    
    // set up the usage document, in case we need to print out how to use this 
program.
    
arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
    
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+"
 is the application for presenting 3D interactive slide shows.");
    
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+"
 [options] filename ...");
    arguments.getApplicationUsage()->addCommandLineOption("-h or 
--help","Display this information");
    arguments.getApplicationUsage()->addCommandLineOption("-a","Turn auto 
stepping on by default");
    arguments.getApplicationUsage()->addCommandLineOption("-d <float>","Time 
duration in seconds between layers/slides");
    arguments.getApplicationUsage()->addCommandLineOption("-s <float> <float> 
<float>","width, height, distance and of the screen away from the viewer");
    arguments.getApplicationUsage()->addCommandLineOption("--viewer","Start 
Present3D as the viewer version.");
    arguments.getApplicationUsage()->addCommandLineOption("--authoring","Start 
Present3D as the authoring version, license required.");
    arguments.getApplicationUsage()->addCommandLineOption("--master","Start 
Present3D as the master version, license required.");
    arguments.getApplicationUsage()->addCommandLineOption("--slave","Start 
Present3D as the slave version, license required.");
    arguments.getApplicationUsage()->addCommandLineOption("--publishing","Start 
Present3D as the publishing version, license required.");
    
arguments.getApplicationUsage()->addCommandLineOption("--timeDelayOnNewSlideWithMovies","Set
 the time delay on new slide with movies, done to allow movie threads to get in 
sync with rendering thread.");
    
arguments.getApplicationUsage()->addCommandLineOption("--targetFrameRate","Set 
the target frame rate, defaults to 80Hz.");
    arguments.getApplicationUsage()->addCommandLineOption("--version","Report 
the Present3D version.");
    arguments.getApplicationUsage()->addCommandLineOption("--print 
<filename>","Print out slides to a series of image files.");
    arguments.getApplicationUsage()->addCommandLineOption("--html 
<filename>","Print out slides to a series of html & image files.");
    arguments.getApplicationUsage()->addCommandLineOption("--loop","Switch on 
looping of presentation.");
    arguments.getApplicationUsage()->addCommandLineOption("--devices","Print 
the Video input capability via QuickTime and exit.");

    // add alias from xml to p3d to provide backwards compatibility for old p3d 
files.
    osgDB::Registry::instance()->addFileExtensionAlias("xml","p3d");

    // if user requests devices video capability.
    if (arguments.read("-devices") || arguments.read("--devices"))
    {
        // Force load QuickTime plugin, probe video capability, exit
        osgDB::readImageFile("devices.live");
        return 1;
    }


    // read any env vars from presentations before we create viewer to make 
sure the viewer
    // utilises these env vars
    if (p3d::readEnvVars(arguments))
    {
        osg::DisplaySettings::instance()->readEnvironmentalVariables();
    }


#ifdef USE_SDL
    SDLIntegration sdlIntegration;
    
    osg::notify(osg::INFO)<<"USE_SDL"<<std::endl;
#endif    
    
    bool doSetViewer = true;
    std::string configurationFile;

    // check env vars for configuration file
    const char* str = getenv("PRESENT3D_CONFIG_FILE");
    if (!str) str = getenv("OSG_CONFIG_FILE");
    if (str) configurationFile = str;

    // check command line parameters for configuration file.
    while (arguments.read("-c",configurationFile)) {}

    osg::Vec4 clearColor(0.0f,0.0f,0.0f,0.0f);
    
    while 
(arguments.read("--clear-color",clearColor[0],clearColor[1],clearColor[2],clearColor[3]))
 {}

    std::string filename;
    if (arguments.read("--spell-check",filename))
    {
        p3d::SpellChecker spellChecker;
        spellChecker.checkP3dXml(filename);
        return 1;
    }

    if (arguments.read("--strip-text",filename))
    {
        p3d::XmlPatcher patcher;
        // patcher.stripP3dXml(filename, osg::notify(osg::NOTICE));

        osg::ref_ptr<osgDB::XmlNode> newNode = patcher.simplifyP3dXml(filename);
        if (newNode.valid())
        {
            newNode->write(std::cout);
        }
        return 1;
    }

    std::string lhs_filename, rhs_filename;
    if (arguments.read("--merge",lhs_filename, rhs_filename))
    {
        p3d::XmlPatcher patcher;
        osg::ref_ptr<osgDB::XmlNode> newNode = 
patcher.mergeP3dXml(lhs_filename, rhs_filename);
        if (newNode.valid())
        {
            newNode->write(std::cout);
        }
        return 1;
    }


    // construct the viewer.
    osgViewer::Viewer viewer(arguments);
    
    // set clear colour to black by default.
    viewer.getCamera()->setClearColor(clearColor);

    if (!configurationFile.empty())
    {
        viewer.readConfiguration(configurationFile);
        doSetViewer = false;
    }
    
    // set up stereo masks
    viewer.getCamera()->setCullMask(0xffffffff);
    viewer.getCamera()->setCullMaskLeft(0x00000001);
    viewer.getCamera()->setCullMaskRight(0x00000002);   

    // set up the camera manipulators.
    {
        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() );

        std::string pathfile;
        char keyForAnimationPath = '5';
        while (arguments.read("-p",pathfile))
        {
            osgGA::AnimationPathManipulator* apm = new 
osgGA::AnimationPathManipulator(pathfile);
            if (apm || !apm->valid()) 
            {
                unsigned int num = 
keyswitchManipulator->getNumMatrixManipulators();
                keyswitchManipulator->addMatrixManipulator( 
keyForAnimationPath, "Path", apm );
                keyswitchManipulator->selectMatrixManipulator(num);
                ++keyForAnimationPath;
            }
        }

        viewer.setCameraManipulator( keyswitchManipulator.get() );
    }

    // add the state manipulator
    viewer.addEventHandler( new 
osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );

    // add the state manipulator
    viewer.addEventHandler( new osgViewer::StatsHandler() );

    viewer.addEventHandler( new osgViewer::WindowSizeHandler() );

    // neeed to address.
    // 
viewer.getScene()->getUpdateVisitor()->setTraversalMode(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);


    const char* p3dCursor = getenv("P3D_CURSOR");
    std::string cursorFileName( p3dCursor ? p3dCursor : "");
    while (arguments.read("--cursor",cursorFileName)) {}


    while (arguments.read("--set-viewer")) { doSetViewer = true; }
    
    while (arguments.read("--no-set-viewer")) { doSetViewer = false; }
    

    // cluster related entries.
    int socketNumber=8100;
    while (arguments.read("-n",socketNumber)) {}

    float camera_fov=-1.0f;
    while (arguments.read("-f",camera_fov)) {}

    float camera_offset=45.0f;
    while (arguments.read("-o",camera_offset)) {}


    std::string exportName;
    while (arguments.read("--print",exportName)) {}

    while (arguments.read("--html",exportName)) {}

    // read any time delay argument.
    float timeDelayBetweenSlides = 1.0f;
    while (arguments.read("-d",timeDelayBetweenSlides)) {}

    bool autoSteppingActive = false;
    while (arguments.read("-a")) autoSteppingActive = true;

    bool loopPresentation = false;
    while (arguments.read("--loop")) loopPresentation = true;


    // register the slide event handler - which moves the presentation from 
slide to slide, layer to layer.
    osgPresentation::SlideEventHandler* seh = new 
osgPresentation::SlideEventHandler(&viewer);
    viewer.addEventHandler(seh);

    seh->setAutoSteppingActive(autoSteppingActive);
    seh->setTimeDelayBetweenSlides(timeDelayBetweenSlides);
    seh->setLoopPresentation(loopPresentation);

    double targetFrameRate = 80.0;
    while (arguments.read("--targetFrameRate",targetFrameRate)) {}


    // set the time delay
    float timeDelayOnNewSlideWithMovies = 0.4f;
    while 
(arguments.read("--timeDelayOnNewSlideWithMovies",timeDelayOnNewSlideWithMovies))
 {}
    seh->setTimeDelayOnNewSlideWithMovies(timeDelayOnNewSlideWithMovies);

    // set up optimizer options
    unsigned int optimizer_options = osgUtil::Optimizer::DEFAULT_OPTIMIZATIONS;
    bool relase_and_compile = false;
    while (arguments.read("--release-and-compile")) 
    {
        relase_and_compile = true;
    }
    seh->setReleaseAndCompileOnEachNewSlide(relase_and_compile);
    if (relase_and_compile)
    {
        // make sure that imagery stays around after being applied to textures.
        
viewer.getDatabasePager()->setUnrefImageDataAfterApplyPolicy(true,false);
        optimizer_options &= ~osgUtil::Optimizer::OPTIMIZE_TEXTURE_SETTINGS;
    }
// 
//     
osgDB::Registry::instance()->getOrCreateDatabasePager()->setUnrefImageDataAfterApplyPolicy(true,false);
//     optimizer_options &= ~osgUtil::Optimizer::OPTIMIZE_TEXTURE_SETTINGS;
//     osg::Texture::getTextureObjectManager()->setExpiryDelay(0.0f);
//     
osgDB::Registry::instance()->getOrCreateDatabasePager()->setExpiryDelay(1.0f);

    // register the handler for modifying the point size
    PointsEventHandler* peh = new PointsEventHandler;
    viewer.addEventHandler(peh);
    
    // 
osg::DisplaySettings::instance()->setSplitStereoAutoAjustAspectRatio(false);

    float width = osg::DisplaySettings::instance()->getScreenWidth();
    float height = osg::DisplaySettings::instance()->getScreenHeight();
    float distance = osg::DisplaySettings::instance()->getScreenDistance();
    bool sizesSpecified = false;
    while (arguments.read("-s", width, height, distance)) 
    {
        sizesSpecified = true;
        
        osg::DisplaySettings::instance()->setScreenDistance(distance);
        osg::DisplaySettings::instance()->setScreenHeight(height);
        osg::DisplaySettings::instance()->setScreenWidth(width);
    }

    std::string outputFileName;
    while(arguments.read("--output",outputFileName)) {}


    // get details on keyboard and mouse bindings used by the viewer.
    viewer.getUsage(*arguments.getApplicationUsage());

    // if user request help write it out to cout.
    if (arguments.read("-h") || arguments.read("--help"))
    {
        arguments.getApplicationUsage()->write(osg::notify(osg::NOTICE));
        return 1;
    }

    P3DApplicationType P3DApplicationType = VIEWER;

    str = getenv("PRESENT3D_TYPE");
    if (str)
    {
        if (strcmp(str,"viewer")==0) P3DApplicationType = VIEWER;
        else if (strcmp(str,"master")==0) P3DApplicationType = MASTER;
        else if (strcmp(str,"slave")==0) P3DApplicationType = SLAVE;
    }
        
    while (arguments.read("--viewer")) { P3DApplicationType = VIEWER; }
    while (arguments.read("--master")) { P3DApplicationType = MASTER; }
    while (arguments.read("--slave")) { P3DApplicationType = SLAVE; }
    
    while (arguments.read("--version"))
    {
        std::string appTypeName = "invalid";
        switch(P3DApplicationType)
        {
            case(VIEWER): appTypeName = "viewer"; break;
            case(MASTER): appTypeName = "master"; break;
            case(SLAVE): appTypeName = "slave"; break;
        }

        osg::notify(osg::NOTICE)<<std::endl;
        osg::notify(osg::NOTICE)<<"Present3D "<<appTypeName<<" version : 
"<<s_version<<std::endl;
        osg::notify(osg::NOTICE)<<std::endl;

        return 0;
    }

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

    // report any errors if they have ocured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(osg::notify(osg::INFO));
        return 1;
    }


    // read files name from arguments.
    p3d::FileNameList xmlFiles, normalFiles;
    if (!p3d::getFileNames(arguments, xmlFiles, normalFiles))
    {
        osg::notify(osg::NOTICE)<<std::endl;
        osg::notify(osg::NOTICE)<<"No file specified, please specify and file 
to load."<<std::endl;
        osg::notify(osg::NOTICE)<<std::endl;
        return 1;
    }



    bool viewerInitialized = false;
    if (!xmlFiles.empty())
    {
        osg::ref_ptr<osg::Node> holdingModel = 
p3d::readHoldingSlide(xmlFiles.front());

        if (holdingModel.valid())
        {
            viewer.setSceneData(holdingModel.get());

            seh->selectSlide(0);

            if (!viewerInitialized)
            {
                // pass the global stateset to the point event handler so that 
it can
                // alter the point size of all points in the scene.
                peh->setStateSet(viewer.getCamera()->getOrCreateStateSet());

                // create the windows and run the threads.
                viewer.realize();

                if (doSetViewer) setViewer(viewer, width, height, distance);

                viewerInitialized = true;
            }

            seh->home();

            // render a frame
            viewer.frame();
        }
    }

    osg::Timer timer;
    osg::Timer_t start_tick = timer.tick();


    osg::ref_ptr<osgDB::ReaderWriter::Options> cacheAllOption = new 
osgDB::ReaderWriter::Options;
    cacheAllOption->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_ALL);
    osgDB::Registry::instance()->setOptions(cacheAllOption.get());

    // read the scene from the list of file specified commandline args.
    osg::ref_ptr<osg::Node> loadedModel = 
p3d::readShowFiles(arguments,cacheAllOption.get()); // 
osgDB::readNodeFiles(arguments, cacheAllOption.get());


    osgDB::Registry::instance()->setOptions( 0 );


    // if no model has been successfully loaded report failure.
    if (!loadedModel) 
    {
        osg::notify(osg::INFO) << arguments.getApplicationName() <<": No data 
loaded" << std::endl;
        return 1;
    }

    osg::Timer_t end_tick = timer.tick();

    osg::notify(osg::INFO) << "Time to load = 
"<<timer.delta_s(start_tick,end_tick)<<std::endl;


    if (loadedModel->getNumDescriptions()>0)
    {
        for(unsigned int i=0; i<loadedModel->getNumDescriptions(); ++i)
        {
            const std::string& desc = loadedModel->getDescription(i);
            if (desc=="loop") 
            {
                osg::notify(osg::NOTICE)<<"Enabling looping"<<std::endl;
                seh->setLoopPresentation(true);
            }
            else if (desc=="auto") 
            {
                osg::notify(osg::NOTICE)<<"Enabling auto run"<<std::endl;
                seh->setAutoSteppingActive(true);
            }
        }
    }


#if !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)

    // add back in enabling of the GL_ALPHA_TEST to get around the core OSG no 
longer setting it by default for opaque bins.
    // the alpha test is required for the volume rendering alpha clipping to 
work.
    loadedModel->getOrCreateStateSet()->setMode(GL_ALPHA_TEST, 
osg::StateAttribute::ON);
#endif


    // optimize the scene graph, remove rendundent nodes and state etc.
    osgUtil::Optimizer optimizer;
    optimizer.optimize(loadedModel.get(), optimizer_options);

    if (!cursorFileName.empty())
    {
        osg::ref_ptr<osg::Group> group = new osg::Group;
        group->addChild(loadedModel.get());
        group->addChild(createCursorSubgraph(cursorFileName, 0.05f));
        
        loadedModel = group.get();
    }

    // set the scene to render
    viewer.setSceneData(loadedModel.get());

    if (!viewerInitialized)
    {
        // pass the global stateset to the point event handler so that it can
        // alter the point size of all points in the scene.
        peh->setStateSet(viewer.getCamera()->getOrCreateStateSet());

        // create the windows and run the threads.
        viewer.realize();

        if (doSetViewer) setViewer(viewer, width, height, distance);

        viewerInitialized = true;
    }

    if (!cursorFileName.empty())
    {
        // have to add a frame in here to avoid problems with X11 threading 
issue on switching off the cursor
        // not yet sure why it makes a difference, but it at least fixes the 
crash that would otherwise occur
        // under X11.
        viewer.frame();

        // switch off the cursor
        osgViewer::Viewer::Windows windows;
        viewer.getWindows(windows);
        for(osgViewer::Viewer::Windows::iterator itr = windows.begin();
            itr != windows.end();
            ++itr)
        {
            (*itr)->useCursor(false);
        }
    }

    // pass the model to the slide event handler so it knows which to 
manipulate.
    seh->set(loadedModel.get());
    seh->selectSlide(0);

    seh->home();

    if (!outputFileName.empty())
    {
        osgDB::writeNodeFile(*loadedModel,outputFileName);
        return 0;
    }
    
    osg::Timer_t startOfFrameTick = osg::Timer::instance()->tick();
    double targetFrameTime = 1.0/targetFrameRate;
    
    if (exportName.empty())
    {
        // objects for managing the broadcasting and recieving of camera 
packets.
        CameraPacket cp;
        Broadcaster  bc;
        Receiver     rc;
        bc.setPort(static_cast<short int>(socketNumber));
        rc.setPort(static_cast<short int>(socketNumber));

        bool masterKilled = false;
        DataConverter scratchPad(1024);

        while( !viewer.done() && !masterKilled)
        {
            // wait for all cull and draw threads to complete.
            viewer.advance();

            osg::Timer_t currentTick = osg::Timer::instance()->tick();
            double deltaTime = 
osg::Timer::instance()->delta_s(startOfFrameTick, currentTick);


            if (deltaTime<targetFrameTime)
            {
                OpenThreads::Thread::microSleep(static_cast<unsigned 
int>((targetFrameTime-deltaTime)*1000000.0));
            }

            startOfFrameTick =  osg::Timer::instance()->tick();

#if 0            
            if (kmcb)
            {
                double time = kmcb->getTime();
                viewer.getFrameStamp()->setReferenceTime(time);
            }
#endif

#ifdef USE_SDL
            sdlIntegration.update(viewer);
#endif

            if (P3DApplicationType==MASTER)
            {
                // take camera zero as the guide.
                osg::Matrix modelview(viewer.getCamera()->getViewMatrix());
                
                cp.setPacket(modelview,viewer.getFrameStamp());
                
                // cp.readEventQueue(viewer);

                scratchPad.reset();
                scratchPad.write(cp);

                scratchPad.reset();
                scratchPad.read(cp);

                bc.setBuffer(scratchPad._startPtr, scratchPad._numBytes);
                
                std::cout << "bc.sync()"<<scratchPad._numBytes<<std::endl;

                bc.sync();
            }
            else if (P3DApplicationType==SLAVE)
            {
                rc.setBuffer(scratchPad._startPtr, scratchPad._numBytes);

                rc.sync();
                
                scratchPad.reset();
                scratchPad.read(cp);
    
                // cp.writeEventQueue(viewer);

                if (cp.getMasterKilled()) 
                {
                    std::cout << "Received master killed."<<std::endl;
                    // break out of while (!done) loop since we've now want to 
shut down.
                    masterKilled = true;
                }
            }

            // update the scene by traversing it with the the update visitor 
which will
            // call all node update callbacks and animations.
            viewer.eventTraversal();

            // update the scene by traversing it with the the update visitor 
which will
            // call all node update callbacks and animations.
            viewer.updateTraversal();

            if (P3DApplicationType==SLAVE)
            {
                osg::Matrix modelview;
                cp.getModelView(modelview,camera_offset);

                viewer.getCamera()->setViewMatrix(modelview);
            }

            // fire off the cull and draw traversals of the scene.
            if(!masterKilled)
                viewer.renderingTraversals();
        }
    }
    else
    {
        ExportHTML::write(seh, viewer, exportName);
    }
            
    return 0;
}

SET(TARGET_SRC
    Cluster.cpp
    ExportHTML.cpp
    PointsEventHandler.cpp
    present3D.cpp
    ReadShowFile.cpp
    ShowEventHandler.cpp
    SpellChecker.cpp
)

SET(TARGET_H
    Cluster.h
    ExportHTML.h
    PointsEventHandler.h
    ReadShowFile.h
    ShowEventHandler.h
    SpellChecker.h
)

IF (SDL_FOUND)

    OPTION(BUILD_PRESENT3D_WITH_SDL "Set to ON to build Present3D with SDL for 
joystick support." OFF)

    IF (BUILD_PRESENT3D_WITH_SDL)

        SET(TARGET_EXTERNAL_LIBRARIES ${SDL_LIBRARY} )
        INCLUDE_DIRECTORIES(${SDL_INCLUDE_DIR} )

        SET(TARGET_SRC
           ${TARGET_SRC}
           SDLIntegration.cpp
        )

        SET(TARGET_H
           ${TARGET_H}
           SDLIntegration.h
        )

        ADD_DEFINITIONS(-DUSE_SDL)

    ENDIF()

ENDIF()

SET(TARGET_ADDED_LIBRARIES osgVolume osgFX osgPresentation)

IF (NOT DYNAMIC_OPENSCENEGRAPH)
    SET(TARGET_ADDED_LIBRARIES
        ${TARGET_ADDED_LIBRARIES}
            osgdb_ive
            osgdb_osg
            osgdb_p3d
            osgdb_rgb
            osgdb_openflight
            osgdb_obj
            osgdb_png
    )

    IF(JPEG_FOUND)
        ADD_DEFINITIONS(-DUSE_JPEG)
        SET(TARGET_ADDED_LIBRARIES ${TARGET_ADDED_LIBRARIES} osgdb_jpeg)
    ENDIF(JPEG_FOUND)

    IF(PNG_FOUND)
        ADD_DEFINITIONS(-DUSE_PNG)
        #SET(TARGET_ADDED_LIBRARIES ${TARGET_ADDED_LIBRARIES} osgdb_png)
    ENDIF(PNG_FOUND)

    IF(CURL_FOUND)
        ADD_DEFINITIONS(-DUSE_CURL)
        SET(TARGET_ADDED_LIBRARIES ${TARGET_ADDED_LIBRARIES} osgdb_curl)
    ENDIF(CURL_FOUND)

    IF(FFMPEG_FOUND)
        ADD_DEFINITIONS(-DUSE_FFMPEG)
        SET(TARGET_ADDED_LIBRARIES ${TARGET_ADDED_LIBRARIES} osgdb_ffmpeg)
    ENDIF(FFMPEG_FOUND)

    IF(FREETYPE_FOUND)
        ADD_DEFINITIONS(-DUSE_FREETYPE)
        SET(TARGET_ADDED_LIBRARIES ${TARGET_ADDED_LIBRARIES} osgdb_freetype)
    ENDIF(FREETYPE_FOUND)

    IF(POPPLER_FOUND AND CAIRO_FOUND)
        ADD_DEFINITIONS(-DUSE_POPPLER_CAIRO)
        SET(TARGET_ADDED_LIBRARIES ${TARGET_ADDED_LIBRARIES} osgdb_pdf)
    ENDIF(POPPLER_FOUND AND CAIRO_FOUND)
ENDIF()

IF   (WIN32)
    # to support cluster code
    SET(TARGET_EXTERNAL_LIBRARIES ${TARGET_EXTERNAL_LIBRARIES} ws2_32)
ENDIF()


SETUP_APPLICATION(present3D)
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to