#include <simgear/route/waypoint.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/viewer.hxx>
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
#include <Airports/dynamics.hxx>
#include <math.h>
#include <Main/util.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/viewer.hxx>
#include "AICarrier.hxx"
#include <math.h>
#include <Main/util.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/viewer.hxx>
#include <Scenery/scenery.hxx>
#include <simgear/sg_inlines.h>
-#include <Main/viewer.hxx>
+#include <Viewer/viewer.hxx>
#include <Scenery/scenery.hxx>
#include <Airports/dynamics.hxx>
Time
Traffic
FDM
+ Viewer
Main
- )
+ )
+
+ add_subdirectory(${mylibfolder})
- add_subdirectory(${mylibfolder})
endforeach( mylibfolder )
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
-#include <Main/viewmgr.hxx>
+#include <Viewer/viewmgr.hxx>
+#include <Viewer/viewer.hxx>
#include <Time/light.hxx>
#include <GUI/FGFontCache.hxx>
-#include <Main/viewer.hxx>
#include <Instrumentation/dclgps.hxx>
#define WIN_X 0
#include <simgear/structure/event_mgr.hxx>
#include <Main/main.hxx>
-#include <Main/renderer.hxx>
#include <Main/fg_props.hxx>
+#include <Viewer/renderer.hxx>
#include <FDM/flight.hxx>
#include "environment.hxx"
#include <simgear/props/props_io.hxx>
#include <Main/globals.hxx>
-#include <Main/renderer.hxx>
-#include <Airports/simple.hxx>
#include <Main/util.hxx>
+#include <Viewer/renderer.hxx>
+#include <Airports/simple.hxx>
#include "fgclouds.hxx"
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
-#include <Main/renderer.hxx>
+#include <Viewer/renderer.hxx>
#include <Scenery/scenery.hxx>
#include "precipitation_mgr.hxx"
#include <Main/globals.hxx>
#include <Main/locale.hxx>
#include <Main/fg_props.hxx>
-#include <Main/WindowSystemAdapter.hxx>
+#include <Viewer/WindowSystemAdapter.hxx>
#include <GUI/new_gui.hxx>
#include <GUI/FGFontCache.hxx>
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include <Main/fg_os.hxx>
-#include <Main/renderer.hxx>
-#include <Main/viewmgr.hxx>
-#include <Main/WindowSystemAdapter.hxx>
-#include <Main/CameraGroup.hxx>
+#include <Viewer/renderer.hxx>
+#include <Viewer/viewmgr.hxx>
+#include <Viewer/WindowSystemAdapter.hxx>
+#include <Viewer/CameraGroup.hxx>
#include <GUI/new_gui.hxx>
#include <list>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/scene/util/SGPickCallback.hxx>
-#include <Main/renderer.hxx>
+#include <Viewer/renderer.hxx>
+
/**
* List of currently pressed mouse button events
*/
#include <plib/fnt.h>
#include <Main/globals.hxx>
-#include <Main/viewmgr.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/viewmgr.hxx>
+#include <Viewer/viewer.hxx>
#include <GUI/FGFontCache.hxx>
#include "HUD.hxx"
#include <sstream>
#include <simgear/math/SGGeometry.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/viewer.hxx>
#include "HUD.hxx"
// FIXME
#include <FDM/flight.hxx>
#include <Environment/environment.hxx>
#include <Environment/environment_mgr.hxx>
-#include <Main/viewer.hxx>
-#include <Main/viewmgr.hxx>
+#include <Viewer/viewer.hxx>
+#include <Viewer/viewmgr.hxx>
#include <ATCDCL/ATCutils.hxx>
#include "HUD.hxx"
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
-#include <Main/renderer.hxx>
+#include <Viewer/renderer.hxx>
#include <Cockpit/panel.hxx>
#include <Airports/simple.hxx>
#include <Airports/runways.hxx>
#include <simgear/debug/logstream.hxx>
#include <Main/globals.hxx>
-#include <Main/renderer.hxx>
+#include <Viewer/renderer.hxx>
#include <Scenery/scenery.hxx>
#include "od_gauge.hxx"
endif (MSVC)
set(SOURCES
- CameraGroup.cxx
- FGEventHandler.cxx
- WindowBuilder.cxx
- WindowSystemAdapter.cxx
bootstrap.cxx
fg_commands.cxx
fg_init.cxx
fg_io.cxx
fg_os_common.cxx
- fg_os_osgviewer.cxx
fg_props.cxx
- fgviewer.cxx
globals.cxx
locale.cxx
logger.cxx
main.cxx
options.cxx
- renderer.cxx
- splash.cxx
util.cxx
- viewer.cxx
- viewmgr.cxx
${RESOURCE_FILE}
)
set(HEADERS
- CameraGroup.hxx
- FGEventHandler.hxx
- WindowBuilder.hxx
- WindowSystemAdapter.hxx
fg_commands.hxx
fg_init.hxx
fg_io.hxx
fg_props.hxx
- fgviewer.hxx
globals.hxx
locale.hxx
logger.hxx
main.hxx
options.hxx
- renderer.hxx
- splash.hxx
util.hxx
- viewer.hxx
- viewmgr.hxx
)
get_property(FG_SOURCES GLOBAL PROPERTY FG_SOURCES)
+++ /dev/null
-// Copyright (C) 2008 Tim Moore
-// Copyright (C) 2011 Mathias Froehlich
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program 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 GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "CameraGroup.hxx"
-
-#include "fg_props.hxx"
-#include "globals.hxx"
-#include "renderer.hxx"
-#include "FGEventHandler.hxx"
-#include "WindowBuilder.hxx"
-#include "WindowSystemAdapter.hxx"
-#include <simgear/props/props.hxx>
-#include <simgear/structure/OSGUtils.hxx>
-#include <simgear/structure/OSGVersion.hxx>
-#include <simgear/scene/material/EffectCullVisitor.hxx>
-#include <simgear/scene/util/RenderConstants.hxx>
-#include <simgear/scene/tgdb/userdata.hxx>
-
-#include <algorithm>
-#include <cstring>
-#include <string>
-
-#include <osg/Camera>
-#include <osg/Geometry>
-#include <osg/GraphicsContext>
-#include <osg/io_utils>
-#include <osg/Math>
-#include <osg/Matrix>
-#include <osg/Notify>
-#include <osg/Program>
-#include <osg/Quat>
-#include <osg/TexMat>
-#include <osg/Vec3d>
-#include <osg/Viewport>
-
-#include <osgUtil/IntersectionVisitor>
-
-#include <osgViewer/GraphicsWindow>
-#include <osgViewer/Renderer>
-
-static osg::Matrix
-invert(const osg::Matrix& matrix)
-{
- return osg::Matrix::inverse(matrix);
-}
-
-/// Returns the zoom factor of the master camera.
-/// The reference fov is the historic 55 deg
-static double
-zoomFactor()
-{
- double fov = fgGetDouble("/sim/current-view/field-of-view", 55);
- if (fov < 1)
- fov = 1;
- return tan(55*0.5*SG_DEGREES_TO_RADIANS)/tan(fov*0.5*SG_DEGREES_TO_RADIANS);
-}
-
-static osg::Vec2d
-preMult(const osg::Vec2d& v, const osg::Matrix& m)
-{
- osg::Vec3d tmp = m.preMult(osg::Vec3(v, 0));
- return osg::Vec2d(tmp[0], tmp[1]);
-}
-
-static osg::Matrix
-relativeProjection(const osg::Matrix& P0, const osg::Matrix& R, const osg::Vec2d ref[2],
- const osg::Matrix& pP, const osg::Matrix& pR, const osg::Vec2d pRef[2])
-{
- // Track the way from one projection space to the other:
- // We want
- // P = T*S*P0
- // where P0 is the projection template sensible for the given window size,
- // T is a translation matrix and S a scale matrix.
- // We need to determine T and S so that the reference points in the parents
- // projection space match the two reference points in this cameras projection space.
-
- // Starting from the parents camera projection space, we get into this cameras
- // projection space by the transform matrix:
- // P*R*inv(pP*pR) = T*S*P0*R*inv(pP*pR)
- // So, at first compute that matrix without T*S and determine S and T from that
-
- // Ok, now osg uses the inverse matrix multiplication order, thus:
- osg::Matrix PtoPwithoutTS = invert(pR*pP)*R*P0;
- // Compute the parents reference points in the current projection space
- // without the yet unknown T and S
- osg::Vec2d pRefInThis[2] = {
- preMult(pRef[0], PtoPwithoutTS),
- preMult(pRef[1], PtoPwithoutTS)
- };
-
- // To get the same zoom, rescale to match the parents size
- double s = (ref[0] - ref[1]).length()/(pRefInThis[0] - pRefInThis[1]).length();
- osg::Matrix S = osg::Matrix::scale(s, s, 1);
-
- // For the translation offset, incorporate the now known scale
- // and recompute the position ot the first reference point in the
- // currents projection space without the yet unknown T.
- pRefInThis[0] = preMult(pRef[0], PtoPwithoutTS*S);
- // The translation is then the difference of the reference points
- osg::Matrix T = osg::Matrix::translate(osg::Vec3d(ref[0] - pRefInThis[0], 0));
-
- // Compose and return the desired final projection matrix
- return P0*S*T;
-}
-
-namespace flightgear
-{
-using namespace osg;
-
-using std::strcmp;
-using std::string;
-
-ref_ptr<CameraGroup> CameraGroup::_defaultGroup;
-
-CameraGroup::CameraGroup(osgViewer::Viewer* viewer) :
- _viewer(viewer)
-{
-}
-
-}
-
-namespace
-{
-using namespace osg;
-
-// Given a projection matrix, return a new one with the same frustum
-// sides and new near / far values.
-
-void makeNewProjMat(Matrixd& oldProj, double znear,
- double zfar, Matrixd& projection)
-{
- projection = oldProj;
- // Slightly inflate the near & far planes to avoid objects at the
- // extremes being clipped out.
- znear *= 0.999;
- zfar *= 1.001;
-
- // Clamp the projection matrix z values to the range (near, far)
- double epsilon = 1.0e-6;
- if (fabs(projection(0,3)) < epsilon &&
- fabs(projection(1,3)) < epsilon &&
- fabs(projection(2,3)) < epsilon) {
- // Projection is Orthographic
- epsilon = -1.0/(zfar - znear); // Used as a temp variable
- projection(2,2) = 2.0*epsilon;
- projection(3,2) = (zfar + znear)*epsilon;
- } else {
- // Projection is Perspective
- double trans_near = (-znear*projection(2,2) + projection(3,2)) /
- (-znear*projection(2,3) + projection(3,3));
- double trans_far = (-zfar*projection(2,2) + projection(3,2)) /
- (-zfar*projection(2,3) + projection(3,3));
- double ratio = fabs(2.0/(trans_near - trans_far));
- double center = -0.5*(trans_near + trans_far);
-
- projection.postMult(osg::Matrixd(1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, ratio, 0.0,
- 0.0, 0.0, center*ratio, 1.0));
- }
-}
-}
-
-namespace flightgear
-{
-void CameraInfo::updateCameras()
-{
- bufferSize->set( osg::Vec2f( width, height ) );
-
- for (CameraMap::iterator ii = cameras.begin(); ii != cameras.end(); ++ii ) {
- float f = ii->second.scaleFactor;
- if ( f == 0.0f ) continue;
- ii->second.camera->getViewport()->setViewport(x*f, y*f, width*f, height*f);
- }
-
- for (RenderBufferMap::iterator ii = buffers.begin(); ii != buffers.end(); ++ii ) {
- float f = ii->second.scaleFactor;
- if ( f == 0.0f ) continue;
- osg::Texture2D* texture = ii->second.texture.get();
- if ( texture->getTextureHeight() != height*f || texture->getTextureWidth() != width*f ) {
- texture->setTextureSize( width*f, height*f );
- texture->dirtyTextureObject();
- }
- }
-}
-
-void CameraInfo::resized(double w, double h)
-{
- bufferSize->set( osg::Vec2f( w, h ) );
-
- for (RenderBufferMap::iterator ii = buffers.begin(); ii != buffers.end(); ++ii) {
- float s = ii->second.scaleFactor;
- if ( s == 0.0f ) continue;
- ii->second.texture->setTextureSize( w * s, h * s );
- ii->second.texture->dirtyTextureObject();
- }
-
- for (CameraMap::iterator ii = cameras.begin(); ii != cameras.end(); ++ii) {
- RenderStageInfo& rsi = ii->second;
- if (!rsi.resizable ||
- rsi.camera->getRenderTargetImplementation() != osg::Camera::FRAME_BUFFER_OBJECT ||
- rsi.scaleFactor == 0.0f )
- continue;
-
- Viewport* vp = rsi.camera->getViewport();
- vp->width() = w * rsi.scaleFactor;
- vp->height() = h * rsi.scaleFactor;
-
- osgViewer::Renderer* renderer
- = static_cast<osgViewer::Renderer*>(rsi.camera->getRenderer());
- for (int i = 0; i < 2; ++i) {
- osgUtil::SceneView* sceneView = renderer->getSceneView(i);
- sceneView->getRenderStage()->setFrameBufferObject(0);
- sceneView->getRenderStage()->setCameraRequiresSetUp(true);
- if (sceneView->getRenderStageLeft()) {
- sceneView->getRenderStageLeft()->setFrameBufferObject(0);
- sceneView->getRenderStageLeft()->setCameraRequiresSetUp(true);
- }
- if (sceneView->getRenderStageRight()) {
- sceneView->getRenderStageRight()->setFrameBufferObject(0);
- sceneView->getRenderStageRight()->setCameraRequiresSetUp(true);
- }
- }
- }
-}
-
-osg::Camera* CameraInfo::getCamera(CameraKind k) const
-{
- CameraMap::const_iterator ii = cameras.find( k );
- if (ii == cameras.end())
- return 0;
- return ii->second.camera.get();
-}
-
-osg::Texture2D* CameraInfo::getBuffer(RenderBufferInfo::Kind k) const
-{
- RenderBufferMap::const_iterator ii = buffers.find(k);
- if (ii == buffers.end())
- return 0;
- return ii->second.texture.get();
-}
-
-int CameraInfo::getMainSlaveIndex() const
-{
- return cameras.find( MAIN_CAMERA )->second.slaveIndex;
-}
-
-void CameraInfo::setMatrices(osg::Camera* c)
-{
- view->set( c->getViewMatrix() );
- viewInverse->set( osg::Matrix::inverse( c->getViewMatrix() ) );
- projInverse->set( osg::Matrix::inverse( c->getProjectionMatrix() ) );
-}
-
-void CameraGroup::update(const osg::Vec3d& position,
- const osg::Quat& orientation)
-{
- const Matrix masterView(osg::Matrix::translate(-position)
- * osg::Matrix::rotate(orientation.inverse()));
- _viewer->getCamera()->setViewMatrix(masterView);
- const Matrix& masterProj = _viewer->getCamera()->getProjectionMatrix();
- double masterZoomFactor = zoomFactor();
- for (CameraList::iterator i = _cameras.begin(); i != _cameras.end(); ++i) {
- const CameraInfo* info = i->get();
-
- Camera* camera = info->getCamera(MAIN_CAMERA);
- if ( camera ) {
- const View::Slave& slave = _viewer->getSlave(info->getMainSlaveIndex());
-#if SG_OSG_VERSION_LESS_THAN(3,0,0)
- // refreshes camera viewports (for now)
- info->updateCameras();
-#endif
- Matrix viewMatrix;
- if (info->flags & GUI) {
- viewMatrix = osg::Matrix(); // identifty transform on the GUI camera
- } else if ((info->flags & VIEW_ABSOLUTE) != 0)
- viewMatrix = slave._viewOffset;
- else
- viewMatrix = masterView * slave._viewOffset;
- camera->setViewMatrix(viewMatrix);
- Matrix projectionMatrix;
- if (info->flags & GUI) {
- projectionMatrix = osg::Matrix::ortho2D(0, info->width, 0, info->height);
- } else if ((info->flags & PROJECTION_ABSOLUTE) != 0) {
- if (info->flags & ENABLE_MASTER_ZOOM) {
- if (info->relativeCameraParent < _cameras.size()) {
- // template projection matrix and view matrix of the current camera
- osg::Matrix P0 = slave._projectionOffset;
- osg::Matrix R = viewMatrix;
-
- // The already known projection and view matrix of the parent camera
- const CameraInfo* parentInfo = _cameras[info->relativeCameraParent].get();
- RenderStageInfo prsi = parentInfo->cameras.find(MAIN_CAMERA)->second;
- osg::Matrix pP = prsi.camera->getProjectionMatrix();
- osg::Matrix pR = prsi.camera->getViewMatrix();
-
- // And the projection matrix derived from P0 so that the reference points match
- projectionMatrix = relativeProjection(P0, R, info->thisReference,
- pP, pR, info->parentReference);
-
- } else {
- // We want to zoom, so take the original matrix and apply the zoom to it.
- projectionMatrix = slave._projectionOffset;
- projectionMatrix.postMultScale(osg::Vec3d(masterZoomFactor, masterZoomFactor, 1));
- }
- } else {
- projectionMatrix = slave._projectionOffset;
- }
- } else {
- projectionMatrix = masterProj * slave._projectionOffset;
- }
-
- CameraMap::const_iterator ii = info->cameras.find(FAR_CAMERA);
- if (ii == info->cameras.end() || !ii->second.camera.valid()) {
- camera->setProjectionMatrix(projectionMatrix);
- } else {
- Camera* farCamera = ii->second.camera;
- farCamera->setViewMatrix(viewMatrix);
- double left, right, bottom, top, parentNear, parentFar;
- projectionMatrix.getFrustum(left, right, bottom, top,
- parentNear, parentFar);
- if ((info->flags & FIXED_NEAR_FAR) == 0) {
- parentNear = _zNear;
- parentFar = _zFar;
- }
- if (parentFar < _nearField || _nearField == 0.0f) {
- camera->setProjectionMatrix(projectionMatrix);
- camera->setCullMask(camera->getCullMask()
- | simgear::BACKGROUND_BIT);
- camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- farCamera->setNodeMask(0);
- } else {
- Matrix nearProj, farProj;
- makeNewProjMat(projectionMatrix, parentNear, _nearField,
- nearProj);
- makeNewProjMat(projectionMatrix, _nearField, parentFar,
- farProj);
- camera->setProjectionMatrix(nearProj);
- camera->setCullMask(camera->getCullMask()
- & ~simgear::BACKGROUND_BIT);
- camera->setClearMask(GL_DEPTH_BUFFER_BIT);
- farCamera->setProjectionMatrix(farProj);
- farCamera->setNodeMask(camera->getNodeMask());
- }
- }
- } else {
- bool viewDone = false;
- Matrix viewMatrix;
- bool projectionDone = false;
- Matrix projectionMatrix;
- for ( CameraMap::const_iterator ii = info->cameras.begin(); ii != info->cameras.end(); ++ii ) {
- if ( ii->first == SHADOW_CAMERA ) {
- globals->get_renderer()->updateShadowCamera(info, position);
- continue;
- }
- if ( ii->second.fullscreen )
- continue;
-
- Camera* camera = ii->second.camera.get();
- int slaveIndex = ii->second.slaveIndex;
- const View::Slave& slave = _viewer->getSlave(slaveIndex);
-
- if ( !viewDone ) {
- if ((info->flags & VIEW_ABSOLUTE) != 0)
- viewMatrix = slave._viewOffset;
- else
- viewMatrix = masterView * slave._viewOffset;
- viewDone = true;
- }
-
- camera->setViewMatrix( viewMatrix );
-
- if ( !projectionDone ) {
- if ((info->flags & PROJECTION_ABSOLUTE) != 0) {
- if (info->flags & ENABLE_MASTER_ZOOM) {
- if (info->relativeCameraParent < _cameras.size()) {
- // template projection matrix and view matrix of the current camera
- osg::Matrix P0 = slave._projectionOffset;
- osg::Matrix R = viewMatrix;
-
- // The already known projection and view matrix of the parent camera
- const CameraInfo* parentInfo = _cameras[info->relativeCameraParent].get();
- RenderStageInfo prsi = parentInfo->cameras.find(MAIN_CAMERA)->second;
- osg::Matrix pP = prsi.camera->getProjectionMatrix();
- osg::Matrix pR = prsi.camera->getViewMatrix();
-
- // And the projection matrix derived from P0 so that the reference points match
- projectionMatrix = relativeProjection(P0, R, info->thisReference,
- pP, pR, info->parentReference);
-
- } else {
- // We want to zoom, so take the original matrix and apply the zoom to it.
- projectionMatrix = slave._projectionOffset;
- projectionMatrix.postMultScale(osg::Vec3d(masterZoomFactor, masterZoomFactor, 1));
- }
- } else {
- projectionMatrix = slave._projectionOffset;
- }
- } else {
- projectionMatrix = masterProj * slave._projectionOffset;
- }
- projectionDone = true;
- }
-
- camera->setProjectionMatrix(projectionMatrix);
- }
- }
- }
-
- globals->get_renderer()->setPlanes( _zNear, _zFar );
-}
-
-void CameraGroup::setCameraParameters(float vfov, float aspectRatio)
-{
- if (vfov != 0.0f && aspectRatio != 0.0f)
- _viewer->getCamera()
- ->setProjectionMatrixAsPerspective(vfov,
- 1.0f / aspectRatio,
- _zNear, _zFar);
-}
-
-double CameraGroup::getMasterAspectRatio() const
-{
- if (_cameras.empty())
- return 0.0;
-
- const CameraInfo* info = _cameras.front();
-
- osg::Camera* camera = info->getCamera(MAIN_CAMERA);
- if ( !camera )
- camera = info->getCamera( GEOMETRY_CAMERA );
- const osg::Viewport* viewport = camera->getViewport();
- if (!viewport) {
- return 0.0;
- }
-
- return static_cast<double>(viewport->height()) / viewport->width();
-}
-
-}
-
-namespace
-{
-// A raw value for property nodes that references a class member via
-// an osg::ref_ptr.
-template<class C, class T>
-class RefMember : public SGRawValue<T>
-{
-public:
- RefMember (C *obj, T C::*ptr)
- : _obj(obj), _ptr(ptr) {}
- virtual ~RefMember () {}
- virtual T getValue () const
- {
- return _obj.get()->*_ptr;
- }
- virtual bool setValue (T value)
- {
- _obj.get()->*_ptr = value;
- return true;
- }
- virtual SGRawValue<T> * clone () const
- {
- return new RefMember(_obj.get(), _ptr);
- }
-private:
- ref_ptr<C> _obj;
- T C::* const _ptr;
-};
-
-template<typename C, typename T>
-RefMember<C, T> makeRefMember(C *obj, T C::*ptr)
-{
- return RefMember<C, T>(obj, ptr);
-}
-
-template<typename C, typename T>
-void bindMemberToNode(SGPropertyNode* parent, const char* childName,
- C* obj, T C::*ptr, T value)
-{
- SGPropertyNode* valNode = parent->getNode(childName);
- RefMember<C, T> refMember = makeRefMember(obj, ptr);
- if (!valNode) {
- valNode = parent->getNode(childName, true);
- valNode->tie(refMember, false);
- setValue(valNode, value);
- } else {
- valNode->tie(refMember, true);
- }
-}
-
-void buildViewport(flightgear::CameraInfo* info, SGPropertyNode* viewportNode,
- const osg::GraphicsContext::Traits *traits)
-{
- using namespace flightgear;
- bindMemberToNode(viewportNode, "x", info, &CameraInfo::x, 0.0);
- bindMemberToNode(viewportNode, "y", info, &CameraInfo::y, 0.0);
- bindMemberToNode(viewportNode, "width", info, &CameraInfo::width,
- static_cast<double>(traits->width));
- bindMemberToNode(viewportNode, "height", info, &CameraInfo::height,
- static_cast<double>(traits->height));
-}
-}
-
-namespace flightgear
-{
-
-// Mostly copied from osg's osgViewer/View.cpp
-
-static osg::Geometry* createPanoramicSphericalDisplayDistortionMesh(
- const Vec3& origin, const Vec3& widthVector, const Vec3& heightVector,
- double sphere_radius, double collar_radius,
- Image* intensityMap = 0, const Matrix& projectorMatrix = Matrix())
-{
- osg::Vec3d center(0.0,0.0,0.0);
- osg::Vec3d eye(0.0,0.0,0.0);
-
- double distance = sqrt(sphere_radius*sphere_radius - collar_radius*collar_radius);
- bool flip = false;
- bool texcoord_flip = false;
-
-#if 0
- osg::Vec3d projector = eye - osg::Vec3d(0.0,0.0, distance);
-
- OSG_INFO<<"createPanoramicSphericalDisplayDistortionMesh : Projector position = "<<projector<<std::endl;
- OSG_INFO<<"createPanoramicSphericalDisplayDistortionMesh : distance = "<<distance<<std::endl;
-#endif
- // create the quad to visualize.
- osg::Geometry* geometry = new osg::Geometry();
-
- geometry->setSupportsDisplayList(false);
-
- osg::Vec3 xAxis(widthVector);
- float width = widthVector.length();
- xAxis /= width;
-
- osg::Vec3 yAxis(heightVector);
- float height = heightVector.length();
- yAxis /= height;
-
- int noSteps = 160;
-
- osg::Vec3Array* vertices = new osg::Vec3Array;
- osg::Vec2Array* texcoords0 = new osg::Vec2Array;
- osg::Vec2Array* texcoords1 = intensityMap==0 ? new osg::Vec2Array : 0;
- osg::Vec4Array* colors = new osg::Vec4Array;
-
-#if 0
- osg::Vec3 bottom = origin;
- osg::Vec3 dx = xAxis*(width/((float)(noSteps-2)));
- osg::Vec3 dy = yAxis*(height/((float)(noSteps-1)));
-#endif
- osg::Vec3 top = origin + yAxis*height;
-
- osg::Vec3 screenCenter = origin + widthVector*0.5f + heightVector*0.5f;
- float screenRadius = heightVector.length() * 0.5f;
-
- geometry->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
-
- for(int i=0;i<noSteps;++i)
- {
- //osg::Vec3 cursor = bottom+dy*(float)i;
- for(int j=0;j<noSteps;++j)
- {
- osg::Vec2 texcoord(double(i)/double(noSteps-1), double(j)/double(noSteps-1));
- double theta = texcoord.x() * 2.0 * osg::PI;
- double phi = (1.0-texcoord.y()) * osg::PI;
-
- if (texcoord_flip) texcoord.y() = 1.0f - texcoord.y();
-
- osg::Vec3 pos(sin(phi)*sin(theta), sin(phi)*cos(theta), cos(phi));
- pos = pos*projectorMatrix;
-
- double alpha = atan2(pos.x(), pos.y());
- if (alpha<0.0) alpha += 2.0*osg::PI;
-
- double beta = atan2(sqrt(pos.x()*pos.x() + pos.y()*pos.y()), pos.z());
- if (beta<0.0) beta += 2.0*osg::PI;
-
- double gamma = atan2(sqrt(double(pos.x()*pos.x() + pos.y()*pos.y())), double(pos.z()+distance));
- if (gamma<0.0) gamma += 2.0*osg::PI;
-
-
- osg::Vec3 v = screenCenter + osg::Vec3(sin(alpha)*gamma*2.0/osg::PI, -cos(alpha)*gamma*2.0/osg::PI, 0.0f)*screenRadius;
-
- if (flip)
- vertices->push_back(osg::Vec3(v.x(), top.y()-(v.y()-origin.y()),v.z()));
- else
- vertices->push_back(v);
-
- texcoords0->push_back( texcoord );
-
- osg::Vec2 texcoord1(alpha/(2.0*osg::PI), 1.0f - beta/osg::PI);
- if (intensityMap)
- {
- colors->push_back(intensityMap->getColor(texcoord1));
- }
- else
- {
- colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
- if (texcoords1) texcoords1->push_back( texcoord1 );
- }
-
-
- }
- }
-
-
- // pass the created vertex array to the points geometry object.
- geometry->setVertexArray(vertices);
-
- geometry->setColorArray(colors);
- geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
-
- geometry->setTexCoordArray(0,texcoords0);
- if (texcoords1) geometry->setTexCoordArray(1,texcoords1);
-
- osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES);
- geometry->addPrimitiveSet(elements);
-
- for(int i=0;i<noSteps-1;++i)
- {
- for(int j=0;j<noSteps-1;++j)
- {
- int i1 = j+(i+1)*noSteps;
- int i2 = j+(i)*noSteps;
- int i3 = j+1+(i)*noSteps;
- int i4 = j+1+(i+1)*noSteps;
-
- osg::Vec3& v1 = (*vertices)[i1];
- osg::Vec3& v2 = (*vertices)[i2];
- osg::Vec3& v3 = (*vertices)[i3];
- osg::Vec3& v4 = (*vertices)[i4];
-
- if ((v1-screenCenter).length()>screenRadius) continue;
- if ((v2-screenCenter).length()>screenRadius) continue;
- if ((v3-screenCenter).length()>screenRadius) continue;
- if ((v4-screenCenter).length()>screenRadius) continue;
-
- elements->push_back(i1);
- elements->push_back(i2);
- elements->push_back(i3);
-
- elements->push_back(i1);
- elements->push_back(i3);
- elements->push_back(i4);
- }
- }
-
- return geometry;
-}
-
-void CameraGroup::buildDistortionCamera(const SGPropertyNode* psNode,
- Camera* camera)
-{
- const SGPropertyNode* texNode = psNode->getNode("texture");
- if (!texNode) {
- // error
- return;
- }
- string texName = texNode->getStringValue();
- TextureMap::iterator itr = _textureTargets.find(texName);
- if (itr == _textureTargets.end()) {
- // error
- return;
- }
- Viewport* viewport = camera->getViewport();
- float width = viewport->width();
- float height = viewport->height();
- TextureRectangle* texRect = itr->second.get();
- double radius = psNode->getDoubleValue("radius", 1.0);
- double collar = psNode->getDoubleValue("collar", 0.45);
- Geode* geode = new Geode();
- geode->addDrawable(createPanoramicSphericalDisplayDistortionMesh(
- Vec3(0.0f,0.0f,0.0f), Vec3(width,0.0f,0.0f),
- Vec3(0.0f,height,0.0f), radius, collar));
-
- // new we need to add the texture to the mesh, we do so by creating a
- // StateSet to contain the Texture StateAttribute.
- StateSet* stateset = geode->getOrCreateStateSet();
- stateset->setTextureAttributeAndModes(0, texRect, StateAttribute::ON);
- stateset->setMode(GL_LIGHTING, StateAttribute::OFF);
-
- TexMat* texmat = new TexMat;
- texmat->setScaleByTextureRectangleSize(true);
- stateset->setTextureAttributeAndModes(0, texmat, osg::StateAttribute::ON);
-#if 0
- if (!applyIntensityMapAsColours && intensityMap)
- {
- stateset->setTextureAttributeAndModes(1, new osg::Texture2D(intensityMap), osg::StateAttribute::ON);
- }
-#endif
- // add subgraph to render
- camera->addChild(geode);
- camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
- camera->setClearColor(osg::Vec4(0.0, 0.0, 0.0, 1.0));
- camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
- camera->setCullingMode(osg::CullSettings::NO_CULLING);
- camera->setName("DistortionCorrectionCamera");
-}
-
-CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
-{
- WindowBuilder *wBuild = WindowBuilder::getWindowBuilder();
- const SGPropertyNode* windowNode = cameraNode->getNode("window");
- GraphicsWindow* window = 0;
- int cameraFlags = DO_INTERSECTION_TEST;
- if (windowNode) {
- // New style window declaration / definition
- window = wBuild->buildWindow(windowNode);
- } else {
- // Old style: suck window params out of camera block
- window = wBuild->buildWindow(cameraNode);
- }
- if (!window) {
- return 0;
- }
- Camera* camera = new Camera;
- camera->setAllowEventFocus(false);
- camera->setGraphicsContext(window->gc.get());
- camera->setViewport(new Viewport);
- camera->setCullingMode(CullSettings::SMALL_FEATURE_CULLING
- | CullSettings::VIEW_FRUSTUM_CULLING);
- camera->setInheritanceMask(CullSettings::ALL_VARIABLES
- & ~(CullSettings::CULL_MASK
- | CullSettings::CULLING_MODE
-#if defined(HAVE_CULLSETTINGS_CLEAR_MASK)
- | CullSettings::CLEAR_MASK
-#endif
- ));
-
- osg::Matrix vOff;
- const SGPropertyNode* viewNode = cameraNode->getNode("view");
- if (viewNode) {
- double heading = viewNode->getDoubleValue("heading-deg", 0.0);
- double pitch = viewNode->getDoubleValue("pitch-deg", 0.0);
- double roll = viewNode->getDoubleValue("roll-deg", 0.0);
- double x = viewNode->getDoubleValue("x", 0.0);
- double y = viewNode->getDoubleValue("y", 0.0);
- double z = viewNode->getDoubleValue("z", 0.0);
- // Build a view matrix, which is the inverse of a model
- // orientation matrix.
- vOff = (Matrix::translate(-x, -y, -z)
- * Matrix::rotate(-DegreesToRadians(heading),
- Vec3d(0.0, 1.0, 0.0),
- -DegreesToRadians(pitch),
- Vec3d(1.0, 0.0, 0.0),
- -DegreesToRadians(roll),
- Vec3d(0.0, 0.0, 1.0)));
- if (viewNode->getBoolValue("absolute", false))
- cameraFlags |= VIEW_ABSOLUTE;
- } else {
- // Old heading parameter, works in the opposite direction
- double heading = cameraNode->getDoubleValue("heading-deg", 0.0);
- vOff.makeRotate(DegreesToRadians(heading), osg::Vec3(0, 1, 0));
- }
- // Configuring the physical dimensions of a monitor
- SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true);
- double physicalWidth = viewportNode->getDoubleValue("width", 1024);
- double physicalHeight = viewportNode->getDoubleValue("height", 768);
- double bezelHeightTop = 0;
- double bezelHeightBottom = 0;
- double bezelWidthLeft = 0;
- double bezelWidthRight = 0;
- const SGPropertyNode* physicalDimensionsNode = 0;
- if ((physicalDimensionsNode = cameraNode->getNode("physical-dimensions")) != 0) {
- physicalWidth = physicalDimensionsNode->getDoubleValue("width", physicalWidth);
- physicalHeight = physicalDimensionsNode->getDoubleValue("height", physicalHeight);
- const SGPropertyNode* bezelNode = 0;
- if ((bezelNode = physicalDimensionsNode->getNode("bezel")) != 0) {
- bezelHeightTop = bezelNode->getDoubleValue("top", bezelHeightTop);
- bezelHeightBottom = bezelNode->getDoubleValue("bottom", bezelHeightBottom);
- bezelWidthLeft = bezelNode->getDoubleValue("left", bezelWidthLeft);
- bezelWidthRight = bezelNode->getDoubleValue("right", bezelWidthRight);
- }
- }
- osg::Matrix pOff;
- unsigned parentCameraIndex = ~0u;
- osg::Vec2d parentReference[2];
- osg::Vec2d thisReference[2];
- SGPropertyNode* projectionNode = 0;
- if ((projectionNode = cameraNode->getNode("perspective")) != 0) {
- double fovy = projectionNode->getDoubleValue("fovy-deg", 55.0);
- double aspectRatio = projectionNode->getDoubleValue("aspect-ratio",
- 1.0);
- double zNear = projectionNode->getDoubleValue("near", 0.0);
- double zFar = projectionNode->getDoubleValue("far", zNear + 20000);
- double offsetX = projectionNode->getDoubleValue("offset-x", 0.0);
- double offsetY = projectionNode->getDoubleValue("offset-y", 0.0);
- double tan_fovy = tan(DegreesToRadians(fovy*0.5));
- double right = tan_fovy * aspectRatio * zNear + offsetX;
- double left = -tan_fovy * aspectRatio * zNear + offsetX;
- double top = tan_fovy * zNear + offsetY;
- double bottom = -tan_fovy * zNear + offsetY;
- pOff.makeFrustum(left, right, bottom, top, zNear, zFar);
- cameraFlags |= PROJECTION_ABSOLUTE;
- if (projectionNode->getBoolValue("fixed-near-far", true))
- cameraFlags |= FIXED_NEAR_FAR;
- } else if ((projectionNode = cameraNode->getNode("frustum")) != 0
- || (projectionNode = cameraNode->getNode("ortho")) != 0) {
- double top = projectionNode->getDoubleValue("top", 0.0);
- double bottom = projectionNode->getDoubleValue("bottom", 0.0);
- double left = projectionNode->getDoubleValue("left", 0.0);
- double right = projectionNode->getDoubleValue("right", 0.0);
- double zNear = projectionNode->getDoubleValue("near", 0.0);
- double zFar = projectionNode->getDoubleValue("far", zNear + 20000);
- if (cameraNode->getNode("frustum")) {
- pOff.makeFrustum(left, right, bottom, top, zNear, zFar);
- cameraFlags |= PROJECTION_ABSOLUTE;
- } else {
- pOff.makeOrtho(left, right, bottom, top, zNear, zFar);
- cameraFlags |= (PROJECTION_ABSOLUTE | ORTHO);
- }
- if (projectionNode->getBoolValue("fixed-near-far", true))
- cameraFlags |= FIXED_NEAR_FAR;
- } else if ((projectionNode = cameraNode->getNode("master-perspective")) != 0) {
- double zNear = projectionNode->getDoubleValue("eye-distance", 0.4*physicalWidth);
- double xoff = projectionNode->getDoubleValue("x-offset", 0);
- double yoff = projectionNode->getDoubleValue("y-offset", 0);
- double left = -0.5*physicalWidth - xoff;
- double right = 0.5*physicalWidth - xoff;
- double bottom = -0.5*physicalHeight - yoff;
- double top = 0.5*physicalHeight - yoff;
- pOff.makeFrustum(left, right, bottom, top, zNear, zNear*1000);
- cameraFlags |= PROJECTION_ABSOLUTE | ENABLE_MASTER_ZOOM;
- } else if ((projectionNode = cameraNode->getNode("right-of-perspective"))
- || (projectionNode = cameraNode->getNode("left-of-perspective"))
- || (projectionNode = cameraNode->getNode("above-perspective"))
- || (projectionNode = cameraNode->getNode("below-perspective"))
- || (projectionNode = cameraNode->getNode("reference-points-perspective"))) {
- std::string name = projectionNode->getStringValue("parent-camera");
- for (unsigned i = 0; i < _cameras.size(); ++i) {
- if (_cameras[i]->name != name)
- continue;
- parentCameraIndex = i;
- }
- if (_cameras.size() <= parentCameraIndex) {
- SG_LOG(SG_VIEW, SG_ALERT, "CameraGroup::buildCamera: "
- "failed to find parent camera for relative camera!");
- return 0;
- }
- const CameraInfo* parentInfo = _cameras[parentCameraIndex].get();
- if (projectionNode->getNameString() == "right-of-perspective") {
- double tmp = (parentInfo->physicalWidth + 2*parentInfo->bezelWidthRight)/parentInfo->physicalWidth;
- parentReference[0] = osg::Vec2d(tmp, -1);
- parentReference[1] = osg::Vec2d(tmp, 1);
- tmp = (physicalWidth + 2*bezelWidthLeft)/physicalWidth;
- thisReference[0] = osg::Vec2d(-tmp, -1);
- thisReference[1] = osg::Vec2d(-tmp, 1);
- } else if (projectionNode->getNameString() == "left-of-perspective") {
- double tmp = (parentInfo->physicalWidth + 2*parentInfo->bezelWidthLeft)/parentInfo->physicalWidth;
- parentReference[0] = osg::Vec2d(-tmp, -1);
- parentReference[1] = osg::Vec2d(-tmp, 1);
- tmp = (physicalWidth + 2*bezelWidthRight)/physicalWidth;
- thisReference[0] = osg::Vec2d(tmp, -1);
- thisReference[1] = osg::Vec2d(tmp, 1);
- } else if (projectionNode->getNameString() == "above-perspective") {
- double tmp = (parentInfo->physicalHeight + 2*parentInfo->bezelHeightTop)/parentInfo->physicalHeight;
- parentReference[0] = osg::Vec2d(-1, tmp);
- parentReference[1] = osg::Vec2d(1, tmp);
- tmp = (physicalHeight + 2*bezelHeightBottom)/physicalHeight;
- thisReference[0] = osg::Vec2d(-1, -tmp);
- thisReference[1] = osg::Vec2d(1, -tmp);
- } else if (projectionNode->getNameString() == "below-perspective") {
- double tmp = (parentInfo->physicalHeight + 2*parentInfo->bezelHeightBottom)/parentInfo->physicalHeight;
- parentReference[0] = osg::Vec2d(-1, -tmp);
- parentReference[1] = osg::Vec2d(1, -tmp);
- tmp = (physicalHeight + 2*bezelHeightTop)/physicalHeight;
- thisReference[0] = osg::Vec2d(-1, tmp);
- thisReference[1] = osg::Vec2d(1, tmp);
- } else if (projectionNode->getNameString() == "reference-points-perspective") {
- SGPropertyNode* parentNode = projectionNode->getNode("parent", true);
- SGPropertyNode* thisNode = projectionNode->getNode("this", true);
- SGPropertyNode* pointNode;
-
- pointNode = parentNode->getNode("point", 0, true);
- parentReference[0][0] = pointNode->getDoubleValue("x", 0)*2/parentInfo->physicalWidth;
- parentReference[0][1] = pointNode->getDoubleValue("y", 0)*2/parentInfo->physicalHeight;
- pointNode = parentNode->getNode("point", 1, true);
- parentReference[1][0] = pointNode->getDoubleValue("x", 0)*2/parentInfo->physicalWidth;
- parentReference[1][1] = pointNode->getDoubleValue("y", 0)*2/parentInfo->physicalHeight;
-
- pointNode = thisNode->getNode("point", 0, true);
- thisReference[0][0] = pointNode->getDoubleValue("x", 0)*2/physicalWidth;
- thisReference[0][1] = pointNode->getDoubleValue("y", 0)*2/physicalHeight;
- pointNode = thisNode->getNode("point", 1, true);
- thisReference[1][0] = pointNode->getDoubleValue("x", 0)*2/physicalWidth;
- thisReference[1][1] = pointNode->getDoubleValue("y", 0)*2/physicalHeight;
- }
-
- pOff = osg::Matrix::perspective(45, physicalWidth/physicalHeight, 1, 20000);
- cameraFlags |= PROJECTION_ABSOLUTE | ENABLE_MASTER_ZOOM;
- } else {
- // old style shear parameters
- double shearx = cameraNode->getDoubleValue("shear-x", 0);
- double sheary = cameraNode->getDoubleValue("shear-y", 0);
- pOff.makeTranslate(-shearx, -sheary, 0);
- }
- const SGPropertyNode* textureNode = cameraNode->getNode("texture");
- if (textureNode) {
- string texName = textureNode->getStringValue("name");
- int tex_width = textureNode->getIntValue("width");
- int tex_height = textureNode->getIntValue("height");
- TextureRectangle* texture = new TextureRectangle;
-
- texture->setTextureSize(tex_width, tex_height);
- texture->setInternalFormat(GL_RGB);
- texture->setFilter(Texture::MIN_FILTER, Texture::LINEAR);
- texture->setFilter(Texture::MAG_FILTER, Texture::LINEAR);
- texture->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE);
- texture->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE);
- camera->setDrawBuffer(GL_FRONT);
- camera->setReadBuffer(GL_FRONT);
- camera->setRenderTargetImplementation(Camera::FRAME_BUFFER_OBJECT);
- camera->attach(Camera::COLOR_BUFFER, texture);
- _textureTargets[texName] = texture;
- } else {
- camera->setDrawBuffer(GL_BACK);
- camera->setReadBuffer(GL_BACK);
- }
- const SGPropertyNode* psNode = cameraNode->getNode("panoramic-spherical");
- bool useMasterSceneGraph = !psNode;
- CameraInfo* info = globals->get_renderer()->buildRenderingPipeline(this, cameraFlags, camera, vOff, pOff,
- window->gc.get(), useMasterSceneGraph);
- info->name = cameraNode->getStringValue("name");
- info->physicalWidth = physicalWidth;
- info->physicalHeight = physicalHeight;
- info->bezelHeightTop = bezelHeightTop;
- info->bezelHeightBottom = bezelHeightBottom;
- info->bezelWidthLeft = bezelWidthLeft;
- info->bezelWidthRight = bezelWidthRight;
- info->relativeCameraParent = parentCameraIndex;
- info->parentReference[0] = parentReference[0];
- info->parentReference[1] = parentReference[1];
- info->thisReference[0] = thisReference[0];
- info->thisReference[1] = thisReference[1];
- // If a viewport isn't set on the camera, then it's hard to dig it
- // out of the SceneView objects in the viewer, and the coordinates
- // of mouse events are somewhat bizzare.
- buildViewport(info, viewportNode, window->gc->getTraits());
- info->updateCameras();
- // Distortion camera needs the viewport which is created by addCamera().
- if (psNode) {
- info->flags = info->flags | VIEW_ABSOLUTE;
- buildDistortionCamera(psNode, camera);
- }
- return info;
-}
-
-CameraInfo* CameraGroup::buildGUICamera(SGPropertyNode* cameraNode,
- GraphicsWindow* window)
-{
- WindowBuilder *wBuild = WindowBuilder::getWindowBuilder();
- const SGPropertyNode* windowNode = (cameraNode
- ? cameraNode->getNode("window")
- : 0);
- if (!window && windowNode) {
- // New style window declaration / definition
- window = wBuild->buildWindow(windowNode);
- }
-
- if (!window) { // buildWindow can fail
- SG_LOG(SG_VIEW, SG_WARN, "CameraGroup::buildGUICamera: failed to build a window");
- return NULL;
- }
-
- Camera* camera = new Camera;
- camera->setName( "GUICamera" );
- camera->setAllowEventFocus(false);
- camera->setGraphicsContext(window->gc.get());
- camera->setViewport(new Viewport);
- camera->setClearMask(0);
- camera->setInheritanceMask(CullSettings::ALL_VARIABLES
- & ~(CullSettings::COMPUTE_NEAR_FAR_MODE
- | CullSettings::CULLING_MODE
-#if defined(HAVE_CULLSETTINGS_CLEAR_MASK)
- | CullSettings::CLEAR_MASK
-#endif
- ));
- camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
- camera->setCullingMode(osg::CullSettings::NO_CULLING);
- camera->setProjectionResizePolicy(Camera::FIXED);
- camera->setReferenceFrame(Transform::ABSOLUTE_RF);
- const int cameraFlags = GUI | DO_INTERSECTION_TEST;
-
- CameraInfo* result = new CameraInfo(cameraFlags);
- // The camera group will always update the camera
- camera->setReferenceFrame(Transform::ABSOLUTE_RF);
-
- getViewer()->addSlave(camera, Matrixd::identity(), Matrixd::identity(), false);
- //installCullVisitor(camera);
- int slaveIndex = getViewer()->getNumSlaves() - 1;
- result->addCamera( MAIN_CAMERA, camera, slaveIndex );
- camera->setRenderOrder(Camera::POST_RENDER, slaveIndex);
- addCamera(result);
-
- // XXX Camera needs to be drawn last; eventually the render order
- // should be assigned by a camera manager.
- camera->setRenderOrder(osg::Camera::POST_RENDER, 10000);
- SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true);
- buildViewport(result, viewportNode, window->gc->getTraits());
-
- // Disable statistics for the GUI camera.
- camera->setStats(0);
- result->updateCameras();
- return result;
-}
-
-CameraGroup* CameraGroup::buildCameraGroup(osgViewer::Viewer* viewer,
- SGPropertyNode* gnode)
-{
- sgUserDataInit( globals->get_props() );
-
- CameraGroup* cgroup = new CameraGroup(viewer);
- for (int i = 0; i < gnode->nChildren(); ++i) {
- SGPropertyNode* pNode = gnode->getChild(i);
- const char* name = pNode->getName();
- if (!strcmp(name, "camera")) {
- cgroup->buildCamera(pNode);
- } else if (!strcmp(name, "window")) {
- WindowBuilder::getWindowBuilder()->buildWindow(pNode);
- } else if (!strcmp(name, "gui")) {
- cgroup->buildGUICamera(pNode);
- }
- }
- bindMemberToNode(gnode, "znear", cgroup, &CameraGroup::_zNear, .1f);
- bindMemberToNode(gnode, "zfar", cgroup, &CameraGroup::_zFar, 120000.0f);
- bindMemberToNode(gnode, "near-field", cgroup, &CameraGroup::_nearField,
- 100.0f);
- return cgroup;
-}
-
-void CameraGroup::setCameraCullMasks(Node::NodeMask nm)
-{
- for (CameraIterator i = camerasBegin(), e = camerasEnd(); i != e; ++i) {
- CameraInfo* info = i->get();
- if (info->flags & GUI)
- continue;
- osg::ref_ptr<osg::Camera> farCamera = info->getCamera(FAR_CAMERA);
- osg::Camera* camera = info->getCamera( MAIN_CAMERA );
- if (camera) {
- if (farCamera.valid() && farCamera->getNodeMask() != 0) {
- camera->setCullMask(nm & ~simgear::BACKGROUND_BIT);
- camera->setCullMaskLeft(nm & ~simgear::BACKGROUND_BIT);
- camera->setCullMaskRight(nm & ~simgear::BACKGROUND_BIT);
- farCamera->setCullMask(nm);
- farCamera->setCullMaskLeft(nm);
- farCamera->setCullMaskRight(nm);
- } else {
- camera->setCullMask(nm);
- camera->setCullMaskLeft(nm);
- camera->setCullMaskRight(nm);
- }
- } else {
- camera = info->getCamera( GEOMETRY_CAMERA );
- if (camera == 0) continue;
- camera->setCullMask( nm & ~simgear::MODELLIGHT_BIT );
- }
- }
-}
-
-void CameraGroup::resized()
-{
- for (CameraIterator i = camerasBegin(), e = camerasEnd(); i != e; ++i) {
- CameraInfo *info = i->get();
- Camera* camera = info->getCamera( MAIN_CAMERA );
- if ( camera == 0 )
- camera = info->getCamera( DISPLAY_CAMERA );
- const Viewport* viewport = camera->getViewport();
- info->x = viewport->x();
- info->y = viewport->y();
- info->width = viewport->width();
- info->height = viewport->height();
-
- info->resized( info->width, info->height );
- }
-}
-
-const CameraInfo* CameraGroup::getGUICamera() const
-{
- ConstCameraIterator result
- = std::find_if(camerasBegin(), camerasEnd(),
- FlagTester<CameraInfo>(GUI));
- if (result == camerasEnd()) {
- return NULL;
- }
-
- return *result;
-}
-
-Camera* getGUICamera(CameraGroup* cgroup)
-{
- const CameraInfo* info = cgroup->getGUICamera();
- if (!info) {
- return NULL;
- }
-
- return info->getCamera(MAIN_CAMERA);
-}
-
-static bool computeCameraIntersection(const CameraInfo* cinfo,
- const osgGA::GUIEventAdapter* ea,
- osgUtil::LineSegmentIntersector::Intersections& intersections)
-{
- using osgUtil::Intersector;
- using osgUtil::LineSegmentIntersector;
- double x, y;
- eventToWindowCoords(ea, x, y);
-
- if (!(cinfo->flags & CameraGroup::DO_INTERSECTION_TEST))
- return false;
-
- const Camera* camera = cinfo->getCamera(MAIN_CAMERA);
- if ( !camera )
- camera = cinfo->getCamera( GEOMETRY_CAMERA );
- if (camera->getGraphicsContext() != ea->getGraphicsContext())
- return false;
-
- const Viewport* viewport = camera->getViewport();
- double epsilon = 0.5;
- if (!(x >= viewport->x() - epsilon
- && x < viewport->x() + viewport->width() -1.0 + epsilon
- && y >= viewport->y() - epsilon
- && y < viewport->y() + viewport->height() -1.0 + epsilon))
- return false;
-
- Vec4d start(x, y, 0.0, 1.0);
- Vec4d end(x, y, 1.0, 1.0);
- Matrix windowMat = viewport->computeWindowMatrix();
- Matrix startPtMat = Matrix::inverse(camera->getProjectionMatrix()
- * windowMat);
- Matrix endPtMat;
- const Camera* farCamera = cinfo->getCamera( FAR_CAMERA );
- if (!farCamera || farCamera->getNodeMask() == 0)
- endPtMat = startPtMat;
- else
- endPtMat = Matrix::inverse(farCamera->getProjectionMatrix()
- * windowMat);
- start = start * startPtMat;
- start /= start.w();
- end = end * endPtMat;
- end /= end.w();
- ref_ptr<LineSegmentIntersector> picker
- = new LineSegmentIntersector(Intersector::VIEW,
- Vec3d(start.x(), start.y(), start.z()),
- Vec3d(end.x(), end.y(), end.z()));
- osgUtil::IntersectionVisitor iv(picker.get());
- iv.setTraversalMask( ~simgear::MODELLIGHT_BIT );
- const_cast<Camera*>(camera)->accept(iv);
- if (picker->containsIntersections()) {
- intersections = picker->getIntersections();
- return true;
- }
-
- return false;
-}
-
-bool computeIntersections(const CameraGroup* cgroup,
- const osgGA::GUIEventAdapter* ea,
- osgUtil::LineSegmentIntersector::Intersections& intersections)
-{
- // test the GUI first
- const CameraInfo* guiCamera = cgroup->getGUICamera();
- if (guiCamera && computeCameraIntersection(guiCamera, ea, intersections))
- return true;
-
- // Find camera that contains event
- for (CameraGroup::ConstCameraIterator iter = cgroup->camerasBegin(),
- e = cgroup->camerasEnd();
- iter != e;
- ++iter) {
- const CameraInfo* cinfo = iter->get();
- if (cinfo == guiCamera)
- continue;
-
- if (computeCameraIntersection(cinfo, ea, intersections))
- return true;
- }
-
- intersections.clear();
- return false;
-}
-
-void warpGUIPointer(CameraGroup* cgroup, int x, int y)
-{
- using osgViewer::GraphicsWindow;
- Camera* guiCamera = getGUICamera(cgroup);
- if (!guiCamera)
- return;
- Viewport* vport = guiCamera->getViewport();
- GraphicsWindow* gw
- = dynamic_cast<GraphicsWindow*>(guiCamera->getGraphicsContext());
- if (!gw)
- return;
- globals->get_renderer()->getEventHandler()->setMouseWarped();
- // Translate the warp request into the viewport of the GUI camera,
- // send the request to the window, then transform the coordinates
- // for the Viewer's event queue.
- double wx = x + vport->x();
- double wyUp = vport->height() + vport->y() - y;
- double wy;
- const GraphicsContext::Traits* traits = gw->getTraits();
- if (gw->getEventQueue()->getCurrentEventState()->getMouseYOrientation()
- == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS) {
- wy = traits->height - wyUp;
- } else {
- wy = wyUp;
- }
- gw->getEventQueue()->mouseWarped(wx, wy);
- gw->requestWarpPointer(wx, wy);
- osgGA::GUIEventAdapter* eventState
- = cgroup->getViewer()->getEventQueue()->getCurrentEventState();
- double viewerX
- = (eventState->getXmin()
- + ((wx / double(traits->width))
- * (eventState->getXmax() - eventState->getXmin())));
- double viewerY
- = (eventState->getYmin()
- + ((wyUp / double(traits->height))
- * (eventState->getYmax() - eventState->getYmin())));
- cgroup->getViewer()->getEventQueue()->mouseWarped(viewerX, viewerY);
-}
-}
+++ /dev/null
-// Copyright (C) 2008 Tim Moore
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program 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 GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-#ifndef CAMERAGROUP_HXX
-#define CAMERAGROUP_HXX 1
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include <osg/Matrix>
-#include <osg/ref_ptr>
-#include <osg/Referenced>
-#include <osg/Node>
-#include <osg/TextureRectangle>
-#include <osg/Texture2D>
-#include <osg/TexGen>
-#include <osgUtil/RenderBin>
-
-// For osgUtil::LineSegmentIntersector::Intersections, which is a typedef.
-#include <osgUtil/LineSegmentIntersector>
-namespace osg
-{
-class Camera;
-}
-
-namespace osgViewer
-{
-class Viewer;
-}
-
-class SGPropertyNode;
-
-namespace flightgear
-{
-
-class GraphicsWindow;
-
-struct RenderBufferInfo {
- enum Kind {
- DEPTH_BUFFER,
- NORMAL_BUFFER,
- DIFFUSE_BUFFER,
- SPEC_EMIS_BUFFER,
- LIGHTING_BUFFER,
- SHADOW_BUFFER
- };
-
- RenderBufferInfo(osg::Texture2D* t = 0, float s = 1.0 ) : texture(t), scaleFactor(s) {}
- osg::ref_ptr<osg::Texture2D> texture;
- float scaleFactor;
-};
-typedef std::map<RenderBufferInfo::Kind,RenderBufferInfo> RenderBufferMap;
-typedef std::map<osg::Camera::BufferComponent,size_t> AttachmentMap;
-
-struct RenderStageInfo {
- RenderStageInfo(osg::Camera* camera_ = 0, int si = -1, bool fs = false)
- : camera(camera_), slaveIndex(si), scaleFactor(1.0f), fullscreen(fs)
- , resizable(true)
- {
- }
-
- osg::ref_ptr<osg::Camera> camera;
- AttachmentMap buffers;
- int slaveIndex;
- float scaleFactor;
- bool fullscreen;
- bool resizable;
-};
-
-enum CameraKind {
- MAIN_CAMERA,
- FAR_CAMERA,
- GEOMETRY_CAMERA,
- SHADOW_CAMERA,
- BLOOM_CAMERA_1,
- BLOOM_CAMERA_2,
- AO_CAMERA_1,
- AO_CAMERA_2,
- AO_CAMERA_3,
- LIGHTING_CAMERA,
- DISPLAY_CAMERA
-};
-typedef std::map<CameraKind,RenderStageInfo> CameraMap;
-
-/** A wrapper around osg::Camera that contains some extra information.
- */
-struct CameraInfo : public osg::Referenced
-{
- CameraInfo(unsigned flags_)
- : flags(flags_),
- x(0.0), y(0.0), width(0.0), height(0.0),
- physicalWidth(0), physicalHeight(0), bezelHeightTop(0),
- bezelHeightBottom(0), bezelWidthLeft(0), bezelWidthRight(0),
- relativeCameraParent(~0u),
- bufferSize( new osg::Uniform("fg_BufferSize", osg::Vec2f() ) ),
- projInverse( new osg::Uniform( "fg_ProjectionMatrixInverse", osg::Matrixf() ) ),
- viewInverse( new osg::Uniform( "fg_ViewMatrixInverse",osg::Matrixf() ) ),
- view( new osg::Uniform( "fg_ViewMatrix",osg::Matrixf() ) ),
- du( new osg::Uniform( "fg_du",osg::Vec4() ) ),
- dv( new osg::Uniform( "fg_dv",osg::Vec4() ) )
- {
- }
-
- /** Update and resize cameras
- */
- void updateCameras();
- void resized(double w, double h);
- /** The name as given in the config file.
- */
- std::string name;
- /** Properties of the camera. @see CameraGroup::Flags.
- */
- unsigned flags;
-
- /** Viewport parameters.
- */
- double x;
- double y;
- double width;
- double height;
- /** Physical size parameters.
- */
- double physicalWidth;
- double physicalHeight;
- double bezelHeightTop;
- double bezelHeightBottom;
- double bezelWidthLeft;
- double bezelWidthRight;
- /** The parent camera for relative camera configurations.
- */
- unsigned relativeCameraParent;
-
- /** the camera objects
- */
- CameraMap cameras;
- void addCamera( CameraKind k, osg::Camera* c, int si = -1, bool fs = false ) { cameras[k].camera = c; cameras[k].slaveIndex = si; cameras[k].fullscreen = fs; }
- void addCamera( CameraKind k, osg::Camera* c, bool fs ) { cameras[k].camera = c; cameras[k].fullscreen = fs; }
- void addCamera( CameraKind k, osg::Camera* c, float s ) { cameras[k].camera = c; cameras[k].scaleFactor = s; }
- osg::Camera* getCamera(CameraKind k) const;
- int getMainSlaveIndex() const;
- RenderStageInfo& getRenderStageInfo( CameraKind k ) { return cameras[k]; }
-
- /** the buffer objects
- */
- RenderBufferMap buffers;
- void addBuffer(RenderBufferInfo::Kind k, osg::Texture2D* tex, float scale = 1.0 ) { buffers[k] = RenderBufferInfo(tex,scale); }
- osg::Texture2D* getBuffer(RenderBufferInfo::Kind k) const;
-
- osg::ref_ptr<osg::TexGen> shadowTexGen[4];
-
- osg::ref_ptr<osg::Uniform> bufferSize;
- //osg::ref_ptr<osg::Uniform> bloomOffset[2];
- osg::ref_ptr<osg::Uniform> projInverse;
- osg::ref_ptr<osg::Uniform> viewInverse;
- osg::ref_ptr<osg::Uniform> view;
- osg::ref_ptr<osg::Uniform> du;
- osg::ref_ptr<osg::Uniform> dv;
-
- void setMatrices( osg::Camera* c );
-
- osgUtil::RenderBin::RenderBinList savedTransparentBins;
- /** The reference points in the parents projection space.
- */
- osg::Vec2d parentReference[2];
- /** The reference points in the current projection space.
- */
- osg::Vec2d thisReference[2];
-};
-
-/** Update the OSG cameras from the camera info.
- */
-void updateCameras(const CameraInfo* info);
-
-class CameraGroup : public osg::Referenced
-{
-public:
- /** properties of a camera.
- */
- enum Flags
- {
- VIEW_ABSOLUTE = 0x1, /**< The camera view is absolute, not
- relative to the master camera. */
- PROJECTION_ABSOLUTE = 0x2, /**< The projection is absolute. */
- ORTHO = 0x4, /**< The projection is orthographic */
- GUI = 0x8, /**< Camera draws the GUI. */
- DO_INTERSECTION_TEST = 0x10,/**< scene intersection tests this
- camera. */
- FIXED_NEAR_FAR = 0x20, /**< take the near far values in the
- projection for real. */
- ENABLE_MASTER_ZOOM = 0x40 /**< Can apply the zoom algorithm. */
- };
- /** Create a camera group associated with an osgViewer::Viewer.
- * @param viewer the viewer
- */
- CameraGroup(osgViewer::Viewer* viewer);
- /** Get the camera group's Viewer.
- * @return the viewer
- */
- osgViewer::Viewer* getViewer() { return _viewer.get(); }
- /** Create an osg::Camera from a property node and add it to the
- * camera group.
- * @param cameraNode the property node.
- * @return a CameraInfo object for the camera.
- */
- CameraInfo* buildCamera(SGPropertyNode* cameraNode);
- /** Create a camera from properties that will draw the GUI and add
- * it to the camera group.
- * @param cameraNode the property node. This can be 0, in which
- * case a default GUI camera is created.
- * @param window the GraphicsWindow to use for the GUI camera. If
- * this is 0, the window is determined from the property node.
- * @return a CameraInfo object for the GUI camera.
- */
- CameraInfo* buildGUICamera(SGPropertyNode* cameraNode,
- GraphicsWindow* window = 0);
- /** Update the view for the camera group.
- * @param position the world position of the view
- * @param orientation the world orientation of the view.
- */
- void update(const osg::Vec3d& position, const osg::Quat& orientation);
- /** Set the parameters of the viewer's master camera. This won't
- * affect cameras that have CameraFlags::PROJECTION_ABSOLUTE set.
- * XXX Should znear and zfar be settable?
- * @param vfov the vertical field of view angle
- * @param aspectRatio the master camera's aspect ratio. This
- * doesn't actually change the viewport, but should reflect the
- * current viewport.
- */
- void setCameraParameters(float vfov, float aspectRatio);
- /** Set the default CameraGroup, which is the only one that
- * matters at this time.
- * @param group the group to set.
- */
- static void setDefault(CameraGroup* group) { _defaultGroup = group; }
- /** Get the default CameraGroup.
- * @return the default camera group.
- */
- static CameraGroup* getDefault() { return _defaultGroup.get(); }
- typedef std::vector<osg::ref_ptr<CameraInfo> > CameraList;
- typedef CameraList::iterator CameraIterator;
- typedef CameraList::const_iterator ConstCameraIterator;
- /** Get iterator for camera vector. The iterator's value is a ref_ptr.
- */
- CameraIterator camerasBegin() { return _cameras.begin(); }
- /** Get iteator pointing to the end of the camera list.
- */
- CameraIterator camerasEnd() { return _cameras.end(); }
- ConstCameraIterator camerasBegin() const { return _cameras.begin(); }
- ConstCameraIterator camerasEnd() const { return _cameras.end(); }
- void addCamera(CameraInfo* info) { _cameras.push_back(info); }
- /** Build a complete CameraGroup from a property node.
- * @param viewer the viewer associated with this camera group.
- * @param the camera group property node.
- */
- static CameraGroup* buildCameraGroup(osgViewer::Viewer* viewer,
- SGPropertyNode* node);
- /** Set the cull mask on all non-GUI cameras
- */
- void setCameraCullMasks(osg::Node::NodeMask nm);
- /** Update camera properties after a resize event.
- */
- void resized();
-
- void buildDistortionCamera(const SGPropertyNode* psNode,
- osg::Camera* camera);
-
- /**
- * get aspect ratio of master camera's viewport
- */
- double getMasterAspectRatio() const;
-
- /**
- * find the GUI camera if one is defined
- */
- const CameraInfo* getGUICamera() const;
-protected:
- CameraList _cameras;
- osg::ref_ptr<osgViewer::Viewer> _viewer;
- static osg::ref_ptr<CameraGroup> _defaultGroup;
- // Near, far for the master camera if used.
- float _zNear;
- float _zFar;
- float _nearField;
- typedef std::map<std::string, osg::ref_ptr<osg::TextureRectangle> > TextureMap;
- TextureMap _textureTargets;
-};
-
-}
-
-namespace osgGA
-{
-class GUIEventAdapter;
-}
-
-namespace flightgear
-{
-/** Get the osg::Camera that draws the GUI, if any, from a camera
- * group.
- * @param cgroup the camera group
- * @return the GUI camera or 0
- */
-osg::Camera* getGUICamera(CameraGroup* cgroup);
-/** Choose a camera using an event and do intersection testing on its
- * view of the scene. Only cameras with the DO_INTERSECTION_TEST flag
- * set are considered.
- * @param cgroup the CameraGroup
- * @param ea the event containing a window and mouse coordinates
- * @param intersections container for the result of intersection
- * testing.
- * @return true if any intersections are found
- */
-bool computeIntersections(const CameraGroup* cgroup,
- const osgGA::GUIEventAdapter* ea,
- osgUtil::LineSegmentIntersector::Intersections&
- intersections);
-/** Warp the pointer to coordinates in the GUI camera of a camera group.
- * @param cgroup the camera group
- * @param x x window coordinate of pointer
- * @param y y window coordinate of pointer, in "y down" coordinates.
- */
-void warpGUIPointer(CameraGroup* cgroup, int x, int y);
-}
-#endif
+++ /dev/null
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include <osg/Camera>
-#include <osg/GraphicsContext>
-#include <osg/Math>
-#include <osg/Viewport>
-#include <osgViewer/Viewer>
-
-#include <plib/pu.h>
-#include <Main/fg_props.hxx>
-#include "CameraGroup.hxx"
-#include "FGEventHandler.hxx"
-#include "WindowSystemAdapter.hxx"
-#include "renderer.hxx"
-
-#if !defined(X_DISPLAY_MISSING)
-#define X_DOUBLE_SCROLL_BUG 1
-#endif
-
-#ifdef SG_MAC
-// hack - during interactive resize on Mac, OSG queues and then flushes
-// a large number of resize events, without doing any drawing.
-extern void puCleanUpJunk ( void ) ;
-#endif
-
-namespace flightgear
-{
-const int displayStatsKey = 1;
-const int printStatsKey = 2;
-
-
-// The manipulator is responsible for updating a Viewer's camera. Its
-// event handling method is also a convenient place to run the FG idle
-// and draw handlers.
-
-FGEventHandler::FGEventHandler() :
- idleHandler(0),
- keyHandler(0),
- mouseClickHandler(0),
- mouseMotionHandler(0),
- statsHandler(new FGStatsHandler),
- statsEvent(new osgGA::GUIEventAdapter),
- statsType(osgViewer::StatsHandler::NO_STATS),
- currentModifiers(0),
- resizable(true),
- mouseWarped(false),
- scrollButtonPressed(false),
- changeStatsCameraRenderOrder(false)
-{
- using namespace osgGA;
- statsHandler->setKeyEventTogglesOnScreenStats(displayStatsKey);
- statsHandler->setKeyEventPrintsOutStats(printStatsKey);
- statsEvent->setEventType(GUIEventAdapter::KEYDOWN);
-
- // OSG reports NumPad keycodes independent of the NumLock modifier.
- // Both KP-4 and KP-Left are reported as KEY_KP_Left (0xff96), so we
- // have to generate the locked keys ourselves.
- numlockKeyMap[GUIEventAdapter::KEY_KP_Insert] = '0';
- numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1';
- numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2';
- numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = '3';
- numlockKeyMap[GUIEventAdapter::KEY_KP_Left] = '4';
- numlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
- numlockKeyMap[GUIEventAdapter::KEY_KP_Right] = '6';
- numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7';
- numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8';
- numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9';
- numlockKeyMap[GUIEventAdapter::KEY_KP_Delete] = '.';
-
- // mapping when NumLock is off
- noNumlockKeyMap[GUIEventAdapter::KEY_KP_Insert] = PU_KEY_INSERT;
- noNumlockKeyMap[GUIEventAdapter::KEY_KP_End] = PU_KEY_END;
- noNumlockKeyMap[GUIEventAdapter::KEY_KP_Down] = PU_KEY_DOWN;
- noNumlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = PU_KEY_PAGE_DOWN;
- noNumlockKeyMap[GUIEventAdapter::KEY_KP_Left] = PU_KEY_LEFT;
- noNumlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
- noNumlockKeyMap[GUIEventAdapter::KEY_KP_Right] = PU_KEY_RIGHT;
- noNumlockKeyMap[GUIEventAdapter::KEY_KP_Home] = PU_KEY_HOME;
- noNumlockKeyMap[GUIEventAdapter::KEY_KP_Up] = PU_KEY_UP;
- noNumlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = PU_KEY_PAGE_UP;
- noNumlockKeyMap[GUIEventAdapter::KEY_KP_Delete] = 127;
-
- for (int i = 0; i < 128; i++)
- release_keys[i] = i;
-}
-
-namespace
-{
-// Translate OSG modifier mask to FG modifier mask.
-int osgToFGModifiers(int modifiers)
-{
- int result = 0;
- if (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT)
- result |= KEYMOD_SHIFT;
-
- if (modifiers & osgGA::GUIEventAdapter::MODKEY_CTRL)
- result |= KEYMOD_CTRL;
-
- if (modifiers & osgGA::GUIEventAdapter::MODKEY_ALT)
- result |= KEYMOD_ALT;
-
- if (modifiers & osgGA::GUIEventAdapter::MODKEY_META)
- result |= KEYMOD_META;
-
- if (modifiers & osgGA::GUIEventAdapter::MODKEY_SUPER)
- result |= KEYMOD_SUPER;
-
- if (modifiers & osgGA::GUIEventAdapter::MODKEY_HYPER)
- result |= KEYMOD_HYPER;
- return result;
-}
-}
-
-#if 0
-void FGEventHandler::init(const osgGA::GUIEventAdapter& ea,
- osgGA::GUIActionAdapter& us)
-{
- currentModifiers = osgToFGModifiers(ea.getModKeyMask());
- (void)handle(ea, us);
-}
-#endif
-
-// Calculate event coordinates in the viewport of the GUI camera, if
-// possible. Otherwise return false and (-1, -1).
-namespace
-{
-bool
-eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
- int& x, int& y)
-{
- x = -1;
- y = -1;
-
- const osg::GraphicsContext* eventGC = ea.getGraphicsContext();
- const osg::GraphicsContext::Traits* traits = eventGC->getTraits();
- osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
- if (!guiCamera)
- return false;
- osg::Viewport* vport = guiCamera->getViewport();
- if (!vport)
- return false;
-
- // Scale x, y to the dimensions of the window
- double wx = (((ea.getX() - ea.getXmin()) / (ea.getXmax() - ea.getXmin()))
- * (float)traits->width);
- double wy = (((ea.getY() - ea.getYmin()) / (ea.getYmax() - ea.getYmin()))
- * (float)traits->height);
- if (vport->x() <= wx && wx <= vport->x() + vport->width()
- && vport->y() <= wy && wy <= vport->y() + vport->height()) {
- // Finally, into viewport coordinates. Change y to "increasing
- // downwards".
- x = wx - vport->x();
- y = vport->height() - (wy - vport->y());
- return true;
- } else {
- return false;
- }
-}
-}
-
-bool FGEventHandler::handle(const osgGA::GUIEventAdapter& ea,
- osgGA::GUIActionAdapter& us)
-{
- int x = 0;
- int y = 0;
-
- switch (ea.getEventType()) {
- case osgGA::GUIEventAdapter::FRAME:
- mouseWarped = false;
- handleStats(us);
- return true;
- case osgGA::GUIEventAdapter::KEYDOWN:
- case osgGA::GUIEventAdapter::KEYUP:
- {
- int key, modmask;
- handleKey(ea, key, modmask);
- eventToViewport(ea, us, x, y);
- if (keyHandler)
- (*keyHandler)(key, modmask, x, y);
- return true;
- }
- case osgGA::GUIEventAdapter::PUSH:
- case osgGA::GUIEventAdapter::RELEASE:
- {
- bool mainWindow = eventToViewport(ea, us, x, y);
- int button = 0;
- switch (ea.getButton()) {
- case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
- button = 0;
- break;
- case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
- button = 1;
- break;
- case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
- button = 2;
- break;
- }
- if (mouseClickHandler)
- (*mouseClickHandler)(button,
- (ea.getEventType()
- == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea);
- return true;
- }
- case osgGA::GUIEventAdapter::SCROLL:
- {
- bool mainWindow = eventToViewport(ea, us, x, y);
-#ifdef X_DOUBLE_SCROLL_BUG
- scrollButtonPressed = !scrollButtonPressed;
- if (!scrollButtonPressed) // Drop the button release event
- return true;
-#endif
- int button;
- if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_2D) {
- if (ea.getScrollingDeltaY() > 0)
- button = 3;
- else if (ea.getScrollingDeltaY() < 0)
- button = 4;
- else
- button = -1;
- } else if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP)
- button = 3;
- else
- button = 4;
- if (mouseClickHandler && button != -1) {
- (*mouseClickHandler)(button, 0, x, y, mainWindow, &ea);
- (*mouseClickHandler)(button, 1, x, y, mainWindow, &ea);
- }
- return true;
- }
- case osgGA::GUIEventAdapter::MOVE:
- case osgGA::GUIEventAdapter::DRAG:
- // If we warped the mouse, then disregard all pointer motion
- // events for this frame. We really want to flush the event
- // queue of mouse events, but don't have the ability to do
- // that with osgViewer.
- if (mouseWarped)
- return true;
- if (eventToViewport(ea, us, x, y) && mouseMotionHandler)
- (*mouseMotionHandler)(x, y);
- return true;
- case osgGA::GUIEventAdapter::RESIZE:
- SG_LOG(SG_VIEW, SG_DEBUG, "FGEventHandler::handle: RESIZE event " << ea.getWindowHeight() << " x " << ea.getWindowWidth() << ", resizable: " << resizable);
- CameraGroup::getDefault()->resized();
- if (resizable)
- globals->get_renderer()->resize(ea.getWindowWidth(), ea.getWindowHeight());
- statsHandler->handle(ea, us);
- #ifdef SG_MAC
- // work around OSG Cocoa-Viewer issue with resize event handling,
- // where resize events are queued up, then dispatched in a batch, with
- // no interveningd drawing calls.
- puCleanUpJunk();
- #endif
- return true;
- case osgGA::GUIEventAdapter::CLOSE_WINDOW:
- case osgGA::GUIEventAdapter::QUIT_APPLICATION:
- fgOSExit(0);
- return true;
- default:
- return false;
- }
-}
-
-void FGEventHandler::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
- int& modifiers)
-{
- using namespace osgGA;
- key = ea.getKey();
- // XXX Probably other translations are needed too.
- switch (key) {
- case GUIEventAdapter::KEY_Escape: key = 0x1b; break;
- case GUIEventAdapter::KEY_Return: key = '\n'; break;
- case GUIEventAdapter::KEY_BackSpace: key = '\b'; break;
- case GUIEventAdapter::KEY_Delete: key = 0x7f; break;
- case GUIEventAdapter::KEY_Tab: key = '\t'; break;
- case GUIEventAdapter::KEY_Left: key = PU_KEY_LEFT; break;
- case GUIEventAdapter::KEY_Up: key = PU_KEY_UP; break;
- case GUIEventAdapter::KEY_Right: key = PU_KEY_RIGHT; break;
- case GUIEventAdapter::KEY_Down: key = PU_KEY_DOWN; break;
- case GUIEventAdapter::KEY_Page_Up: key = PU_KEY_PAGE_UP; break;
- case GUIEventAdapter::KEY_Page_Down: key = PU_KEY_PAGE_DOWN; break;
- case GUIEventAdapter::KEY_Home: key = PU_KEY_HOME; break;
- case GUIEventAdapter::KEY_End: key = PU_KEY_END; break;
- case GUIEventAdapter::KEY_Insert: key = PU_KEY_INSERT; break;
- case GUIEventAdapter::KEY_F1: key = PU_KEY_F1; break;
- case GUIEventAdapter::KEY_F2: key = PU_KEY_F2; break;
- case GUIEventAdapter::KEY_F3: key = PU_KEY_F3; break;
- case GUIEventAdapter::KEY_F4: key = PU_KEY_F4; break;
- case GUIEventAdapter::KEY_F5: key = PU_KEY_F5; break;
- case GUIEventAdapter::KEY_F6: key = PU_KEY_F6; break;
- case GUIEventAdapter::KEY_F7: key = PU_KEY_F7; break;
- case GUIEventAdapter::KEY_F8: key = PU_KEY_F8; break;
- case GUIEventAdapter::KEY_F9: key = PU_KEY_F9; break;
- case GUIEventAdapter::KEY_F10: key = PU_KEY_F10; break;
- case GUIEventAdapter::KEY_F11: key = PU_KEY_F11; break;
- case GUIEventAdapter::KEY_F12: key = PU_KEY_F12; break;
- case GUIEventAdapter::KEY_KP_Enter: key = '\r'; break;
- case GUIEventAdapter::KEY_KP_Add: key = '+'; break;
- case GUIEventAdapter::KEY_KP_Divide: key = '/'; break;
- case GUIEventAdapter::KEY_KP_Multiply: key = '*'; break;
- case GUIEventAdapter::KEY_KP_Subtract: key = '-'; break;
- }
- osgGA::GUIEventAdapter::EventType eventType = ea.getEventType();
-
-#ifdef __APPLE__
- // Num Lock is always true on Mac
- std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
- if (numPadIter != numlockKeyMap.end()) {
- key = numPadIter->second;
- }
-#else
- if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK)
- {
- // NumLock on: map to numeric keys
- std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
- if (numPadIter != numlockKeyMap.end()) {
- key = numPadIter->second;
- }
- }
- else
- {
- // NumLock off: map to PU arrow keys
- std::map<int, int>::iterator numPadIter = noNumlockKeyMap.find(key);
- if (numPadIter != noNumlockKeyMap.end()) {
- key = numPadIter->second;
- }
- }
-#endif
-
- modifiers = osgToFGModifiers(ea.getModKeyMask());
- currentModifiers = modifiers;
- if (eventType == osgGA::GUIEventAdapter::KEYUP)
- modifiers |= KEYMOD_RELEASED;
-
- // Release the letter key, for which the key press was reported. This
- // is to deal with Ctrl-press -> a-press -> Ctrl-release -> a-release
- // correctly.
- if (key >= 0 && key < 128) {
- if (modifiers & KEYMOD_RELEASED) {
- key = release_keys[key];
- } else {
- release_keys[key] = key;
- if (key >= 1 && key <= 26) {
- release_keys[key + '@'] = key;
- release_keys[key + '`'] = key;
- } else if (key >= 'A' && key <= 'Z') {
- release_keys[key - '@'] = key;
- release_keys[tolower(key)] = key;
- } else if (key >= 'a' && key <= 'z') {
- release_keys[key - '`'] = key;
- release_keys[toupper(key)] = key;
- }
- }
- }
-}
-
-void FGEventHandler::handleStats(osgGA::GUIActionAdapter& us)
-{
- static SGPropertyNode_ptr display = fgGetNode("/sim/rendering/on-screen-statistics", true);
- static SGPropertyNode_ptr print = fgGetNode("/sim/rendering/print-statistics", true);
-
- int type = display->getIntValue() % osgViewer::StatsHandler::LAST;
- if (type != statsType) {
- statsEvent->setKey(displayStatsKey);
- do {
- statsType = (statsType + 1) % osgViewer::StatsHandler::LAST;
- statsHandler->handle(*statsEvent, us);
- if (changeStatsCameraRenderOrder) {
- statsHandler->getCamera()->setRenderOrder(osg::Camera::POST_RENDER, 99999);
- changeStatsCameraRenderOrder = false;
- }
- } while (statsType != type);
-
- display->setIntValue(statsType);
- }
-
- if (print->getBoolValue()) {
- statsEvent->setKey(printStatsKey);
- statsHandler->handle(*statsEvent, us);
- print->setBoolValue(false);
- }
-}
-
-void eventToWindowCoords(const osgGA::GUIEventAdapter* ea,
- double& x, double& y)
-{
- using namespace osg;
- const GraphicsContext* gc = ea->getGraphicsContext();
- const GraphicsContext::Traits* traits = gc->getTraits() ;
- // Scale x, y to the dimensions of the window
- x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin()))
- * (double)traits->width);
- y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin()))
- * (double)traits->height);
- if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS)
- y = (double)traits->height - y;
-}
-
-void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea,
- double& x, double& y)
-{
- using namespace osg;
- const GraphicsContext* gc = ea->getGraphicsContext();
- const GraphicsContext::Traits* traits = gc->getTraits() ;
- // Scale x, y to the dimensions of the window
- x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin()))
- * (double)traits->width);
- y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin()))
- * (double)traits->height);
- if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS)
- y = (double)traits->height - y;
-}
-}
+++ /dev/null
-#ifndef FGEVENTHANDLER_H
-#define FGEVENTHANDLER_H 1
-
-#include <map>
-#include <osg/Quat>
-#include <osgGA/GUIEventHandler>
-#include <osgViewer/ViewerEventHandlers>
-#include <simgear/structure/OSGVersion.hxx>
-
-#include "fg_os.hxx"
-
-namespace flightgear
-{
- class FGStatsHandler : public osgViewer::StatsHandler
- {
- public:
- FGStatsHandler()
- {
-#if (SG_OSG_VERSION >= 30000)
- // Adjust font type/size for >=OSG3.
- // OSG defaults aren't working/available for FG.
- _font = "Fonts/helvetica_medium.txf";
- _characterSize = 12.0f;
-#endif
- }
- };
-
-class FGEventHandler : public osgGA::GUIEventHandler {
-public:
- FGEventHandler();
-
- virtual ~FGEventHandler() {}
-
- virtual const char* className() const {return "FGEventHandler"; }
-#if 0
- virtual void init(const osgGA::GUIEventAdapter& ea,
- osgGA::GUIActionAdapter& us);
-#endif
- virtual bool handle(const osgGA::GUIEventAdapter& ea,
- osgGA::GUIActionAdapter& us);
-
- void setIdleHandler(fgIdleHandler idleHandler)
- {
- this->idleHandler = idleHandler;
- }
-
- fgIdleHandler getIdleHandler() const
- {
- return idleHandler;
- }
-
- void setKeyHandler(fgKeyHandler keyHandler)
- {
- this->keyHandler = keyHandler;
- }
-
- fgKeyHandler getKeyHandler() const
- {
- return keyHandler;
- }
-
- void setMouseClickHandler(fgMouseClickHandler mouseClickHandler)
- {
- this->mouseClickHandler = mouseClickHandler;
- }
-
- fgMouseClickHandler getMouseClickHandler()
- {
- return mouseClickHandler;
- }
-
- void setMouseMotionHandler(fgMouseMotionHandler mouseMotionHandler)
- {
- this->mouseMotionHandler = mouseMotionHandler;
- }
-
- fgMouseMotionHandler getMouseMotionHandler()
- {
- return mouseMotionHandler;
- }
-
- void setChangeStatsCameraRenderOrder(bool c)
- {
- changeStatsCameraRenderOrder = c;
- }
-
- int getCurrentModifiers() const
- {
- return currentModifiers;
- }
-
- void setMouseWarped()
- {
- mouseWarped = true;
- }
-
- /** Whether or not resizing is supported. It might not be when
- * using multiple displays.
- */
- bool getResizable() { return resizable; }
- void setResizable(bool _resizable) { resizable = _resizable; }
-
-protected:
- osg::ref_ptr<osg::Node> _node;
- fgIdleHandler idleHandler;
- fgKeyHandler keyHandler;
- fgMouseClickHandler mouseClickHandler;
- fgMouseMotionHandler mouseMotionHandler;
- osg::ref_ptr<FGStatsHandler> statsHandler;
- osg::ref_ptr<osgGA::GUIEventAdapter> statsEvent;
- int statsType;
- int currentModifiers;
- std::map<int, int> numlockKeyMap;
- std::map<int, int> noNumlockKeyMap;
- void handleKey(const osgGA::GUIEventAdapter& ea, int& key, int& modifiers);
- bool resizable;
- bool mouseWarped;
- // workaround for osgViewer double scroll events
- bool scrollButtonPressed;
- int release_keys[128];
- void handleStats(osgGA::GUIActionAdapter& us);
- bool changeStatsCameraRenderOrder;
-};
-
-void eventToWindowCoords(const osgGA::GUIEventAdapter* ea, double& x, double& y);
-void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea,
- double& x, double& y);
-}
-#endif
+++ /dev/null
-// Copyright (C) 2008 Tim Moore
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program 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 GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "WindowBuilder.hxx"
-
-#include "WindowSystemAdapter.hxx"
-#include "fg_props.hxx"
-
-#include <sstream>
-
-using namespace std;
-using namespace osg;
-
-namespace flightgear
-{
-string makeName(const string& prefix, int num)
-{
- stringstream stream;
- stream << prefix << num;
- return stream.str();
-}
-
-ref_ptr<WindowBuilder> WindowBuilder::windowBuilder;
-
-const string WindowBuilder::defaultWindowName("FlightGear");
-
-void WindowBuilder::initWindowBuilder(bool stencil)
-{
- windowBuilder = new WindowBuilder(stencil);
-}
-
-WindowBuilder::WindowBuilder(bool stencil) : defaultCounter(0)
-{
- defaultTraits = makeDefaultTraits(stencil);
-}
-
-GraphicsContext::Traits*
-WindowBuilder::makeDefaultTraits(bool stencil)
-{
- GraphicsContext::WindowingSystemInterface* wsi
- = osg::GraphicsContext::getWindowingSystemInterface();
- GraphicsContext::Traits* traits = new osg::GraphicsContext::Traits;
-
- traits->readDISPLAY();
- if (traits->displayNum < 0)
- traits->displayNum = 0;
- if (traits->screenNum < 0)
- traits->screenNum = 0;
-
- int bpp = fgGetInt("/sim/rendering/bits-per-pixel");
- bool alpha = fgGetBool("/sim/rendering/clouds3d-enable");
- int cbits = (bpp <= 16) ? 5 : 8;
- int zbits = (bpp <= 16) ? 16 : 24;
- traits->red = traits->green = traits->blue = cbits;
- traits->depth = zbits;
- if (alpha)
- traits->alpha = 8;
-
- if (stencil)
- traits->stencil = 8;
-
- unsigned screenwidth = 0;
- unsigned screenheight = 0;
- wsi->getScreenResolution(*traits, screenwidth, screenheight);
-
- traits->doubleBuffer = true;
- traits->mipMapGeneration = true;
- traits->windowName = "FlightGear";
- // XXX should check per window too.
- traits->sampleBuffers = fgGetInt("/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
- traits->samples = fgGetInt("/sim/rendering/multi-samples", traits->samples);
- traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync);
- traits->windowDecoration = !fgGetBool("/sim/startup/fullscreen");
-
- if (!traits->windowDecoration) {
- // fullscreen
- traits->supportsResize = false;
- traits->width = screenwidth;
- traits->height = screenheight;
- SG_LOG(SG_VIEW,SG_DEBUG,"Using full screen size for window: " << screenwidth << " x " << screenheight);
- } else {
- // window
- int w = fgGetInt("/sim/startup/xsize");
- int h = fgGetInt("/sim/startup/ysize");
- traits->supportsResize = true;
- traits->width = w;
- traits->height = h;
- if ((w>0)&&(h>0))
- {
- traits->x = ((unsigned)w>screenwidth) ? 0 : (screenwidth-w)/3;
- traits->y = ((unsigned)h>screenheight) ? 0 : (screenheight-h)/3;
- }
- SG_LOG(SG_VIEW,SG_DEBUG,"Using initial window size: " << w << " x " << h);
- }
- return traits;
-}
-}
-
-namespace
-{
-// Helper functions that set a value based on a property if it exists,
-// returning 1 if the value was set.
-
-inline int setFromProperty(string& place, const SGPropertyNode* node,
- const char* name)
-{
- const SGPropertyNode* valNode = node->getNode(name);
- if (valNode) {
- place = valNode->getStringValue();
- return 1;
- }
- return 0;
-}
-
-inline int setFromProperty(int& place, const SGPropertyNode* node,
- const char* name)
-{
- const SGPropertyNode* valNode = node->getNode(name);
- if (valNode) {
- place = valNode->getIntValue();
- return 1;
- }
- return 0;
-}
-
-inline int setFromProperty(bool& place, const SGPropertyNode* node,
- const char* name)
-{
- const SGPropertyNode* valNode = node->getNode(name);
- if (valNode) {
- place = valNode->getBoolValue();
- return 1;
- }
- return 0;
-}
-}
-
-namespace flightgear
-{
-GraphicsWindow* WindowBuilder::buildWindow(const SGPropertyNode* winNode)
-{
- GraphicsContext::WindowingSystemInterface* wsi
- = osg::GraphicsContext::getWindowingSystemInterface();
- WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
- string windowName;
- if (winNode->hasChild("window-name"))
- windowName = winNode->getStringValue("window-name");
- else if (winNode->hasChild("name"))
- windowName = winNode->getStringValue("name");
- GraphicsWindow* result = 0;
- if (!windowName.empty()) {
- result = wsa->findWindow(windowName);
- if (result)
- return result;
- }
- GraphicsContext::Traits* traits
- = new GraphicsContext::Traits(*defaultTraits);
- int traitsSet = setFromProperty(traits->hostName, winNode, "host-name");
- traitsSet |= setFromProperty(traits->displayNum, winNode, "display");
- traitsSet |= setFromProperty(traits->screenNum, winNode, "screen");
-
- const SGPropertyNode* fullscreenNode = winNode->getNode("fullscreen");
-
- if (fullscreenNode && fullscreenNode->getBoolValue()) {
- // fullscreen mode
- unsigned width = 0;
- unsigned height = 0;
- wsi->getScreenResolution(*traits, width, height);
- traits->windowDecoration = false;
- traits->width = width;
- traits->height = height;
- traits->supportsResize = false;
- traits->x = 0;
- traits->y = 0;
- traitsSet = 1;
- } else {
- int resizable = 0;
- if (fullscreenNode && !fullscreenNode->getBoolValue())
- {
- traits->windowDecoration = true;
- resizable = 1;
- }
- resizable |= setFromProperty(traits->windowDecoration, winNode,
- "decoration");
- resizable |= setFromProperty(traits->width, winNode, "width");
- resizable |= setFromProperty(traits->height, winNode, "height");
- if (resizable) {
- traits->supportsResize = true;
- traitsSet = 1;
- }
- // Otherwise use default values.
- }
- traitsSet |= setFromProperty(traits->x, winNode, "x");
- traitsSet |= setFromProperty(traits->y, winNode, "y");
- if (!windowName.empty() && windowName != traits->windowName) {
- traits->windowName = windowName;
- traitsSet = 1;
- } else if (traitsSet) {
- traits->windowName = makeName("FlightGear", defaultCounter++);
- }
- bool drawGUI = false;
- traitsSet |= setFromProperty(drawGUI, winNode, "gui");
- if (traitsSet) {
- GraphicsContext* gc = GraphicsContext::createGraphicsContext(traits);
- if (gc) {
- GraphicsWindow* window = WindowSystemAdapter::getWSA()
- ->registerWindow(gc, traits->windowName);
- if (drawGUI)
- window->flags |= GraphicsWindow::GUI;
- return window;
- } else {
- return 0;
- }
- } else {
- // XXX What if the window has no traits, but does have a name?
- // We should create a "default window" registered with that name.
- return getDefaultWindow();
- }
-}
-
-GraphicsWindow* WindowBuilder::getDefaultWindow()
-{
- GraphicsWindow* defaultWindow
- = WindowSystemAdapter::getWSA()->findWindow(defaultWindowName);
- if (defaultWindow)
- return defaultWindow;
- GraphicsContext::Traits* traits
- = new GraphicsContext::Traits(*defaultTraits);
- traits->windowName = "FlightGear";
-
- GraphicsContext* gc = GraphicsContext::createGraphicsContext(traits);
- if (gc) {
- defaultWindow = WindowSystemAdapter::getWSA()
- ->registerWindow(gc, defaultWindowName);
- return defaultWindow;
- } else {
- SG_LOG(SG_VIEW, SG_ALERT, "getDefaultWindow: failed to create GraphicsContext");
- return 0;
- }
-}
-}
+++ /dev/null
-// Copyright (C) 2008 Tim Moore
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program 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 GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-#ifndef FLIGHTGEAR_WINDOWBUILDER_HXX
-#define FLIGHTGEAR_WINDOWBUILDER_HXX 1
-
-#include <osg/ref_ptr>
-#include <osg/Referenced>
-#include <osg/GraphicsContext>
-
-#include <string>
-
-class SGPropertyNode;
-
-namespace flightgear
-{
-class GraphicsWindow;
-/** Singleton Builder class for creating a GraphicsWindow from property
- * nodes. This involves initializing an osg::GraphicsContext::Traits
- * structure from the property node values and creating an
- * osgViewer::GraphicsWindow.
- */
-class WindowBuilder : public osg::Referenced
-{
-public:
- /** Initialize the singleton window builder.
- * @param stencil whether windows should allocate stencil planes
- */
- static void initWindowBuilder(bool stencil);
- /** Get the singleton window builder
- */
- static WindowBuilder* getWindowBuilder() { return windowBuilder.get(); }
- /** Create a window from its property node description.
- * @param winNode The window's root property node
- * @return a graphics window.
- */
- GraphicsWindow* buildWindow(const SGPropertyNode* winNode);
- /** Get a window whose properties come from FlightGear's
- * command line arguments and their defaults. The window is opened
- * if it has not been already.
- * @return the default graphics window
- */
- GraphicsWindow* getDefaultWindow();
- /** Get the name used to look up the default window.
- */
- const std::string& getDefaultWindowName() { return defaultWindowName; }
-protected:
- WindowBuilder(bool stencil);
- static osg::GraphicsContext::Traits* makeDefaultTraits(bool stencil);
- osg::ref_ptr<osg::GraphicsContext::Traits> defaultTraits;
- int defaultCounter;
- static osg::ref_ptr<WindowBuilder> windowBuilder;
- static const std::string defaultWindowName;
-};
-
-/** Silly function for making the default window and camera
- * names. This concatenates a string with in integer.
- */
-std::string makeName(const std::string& prefix, int num);
-
-}
-#endif
+++ /dev/null
-// Copyright (C) 2008 Tim Moore
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program 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 GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <plib/pu.h>
-
-#include<algorithm>
-#include <functional>
-
-#include "CameraGroup.hxx"
-#include "WindowSystemAdapter.hxx"
-
-#include <osg/Camera>
-#include <osg/GraphicsContext>
-#include <osg/Viewport>
-
-using namespace osg;
-using namespace std;
-
-namespace flightgear
-{
-ref_ptr<WindowSystemAdapter> WindowSystemAdapter::_wsa;
-
-void GraphicsContextOperation::operator()(GraphicsContext* gc)
-{
- run(gc);
- ++done;
-}
-
-WindowSystemAdapter::WindowSystemAdapter() :
- _nextWindowID(0), _isPuInitialized(false)
-{
-}
-
-GraphicsWindow*
-WindowSystemAdapter::registerWindow(GraphicsContext* gc,
- const string& windowName)
-{
- GraphicsWindow* window = new GraphicsWindow(gc, windowName,
- _nextWindowID++);
- windows.push_back(window);
- return window;
-}
-
-// The pu getWindow callback is supposed to return a window ID that
-// would allow drawing a GUI on different windows. All that stuff is
-// broken in multi-threaded OSG, and we only have one GUI "window"
-// anyway, so just return a constant.
-int WindowSystemAdapter::puGetWindow()
-{
- return 1;
-}
-
-void WindowSystemAdapter::puGetWindowSize(int* width, int* height)
-{
- *width = 0;
- *height = 0;
- Camera* camera = getGUICamera(CameraGroup::getDefault());
- if (!camera)
- return;
- Viewport* vport = camera->getViewport();
- *width = (int)vport->width();
- *height = (int)vport->height();
-}
-
-void WindowSystemAdapter::puInitialize()
-{
- puSetWindowFuncs(puGetWindow, 0, puGetWindowSize, 0);
- puRealInit();
-}
-
-GraphicsWindow* WindowSystemAdapter::findWindow(const string& name)
-{
- for (WindowVector::iterator iter = windows.begin(), e = windows.end();
- iter != e;
- ++iter) {
- if ((*iter)->name == name)
- return iter->get();
- }
- return 0;
-}
-}
+++ /dev/null
-// Copyright (C) 2008 Tim Moore
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program 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 GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-#ifndef FLIGHTGEAR_WINDOWSYSTEMADAPTER_HXX
-#define FLIGHTGEAR_WINDOWSYSTEMADAPTER_HXX 1
-
-#include <functional>
-#include <string>
-
-#include <osg/Referenced>
-#include <osg/Camera>
-#include <osg/GraphicsThread>
-#include <osg/ref_ptr>
-
-#include <simgear/structure/SGAtomic.hxx>
-
-namespace osg
-{
-class GraphicsContext;
-}
-
-// Flexible window support
-namespace flightgear
-{
-/** A window with a graphics context and an integer ID
- */
-class GraphicsWindow : public osg::Referenced
-{
-public:
- GraphicsWindow(osg::GraphicsContext* gc_, const std::string& name_,
- int id_, unsigned flags_ = 0) :
- gc(gc_), name(name_), id(id_), flags(flags_)
- {
- }
- /** The OSG graphics context for this window.
- */
- osg::ref_ptr<osg::GraphicsContext> gc;
- /** The window's internal name.
- */
- std::string name;
- /** A unique ID for the window.
- */
- int id;
- enum Flags {
- GUI = 1 /**< The GUI (and 2D cockpit) will be drawn on this window. */
- };
- /** Flags for the window.
- */
- unsigned flags;
-};
-
-typedef std::vector<osg::ref_ptr<GraphicsWindow> > WindowVector;
-
-/**
- * An operation that is run once with a particular GraphicsContext
- * current. It will probably be deferred and may run in a different
- * thread.
- */
-class GraphicsContextOperation : public osg::GraphicsOperation
-{
-public:
- GraphicsContextOperation(const std::string& name) :
- osg::GraphicsOperation(name, false)
- {
- }
- /** Don't override this!
- */
- virtual void operator()(osg::GraphicsContext* gc);
- /** The body of the operation.
- */
- virtual void run(osg::GraphicsContext* gc) = 0;
- /** Test if the operation has completed.
- * @return true if the run() method has finished.
- */
- bool isFinished() const { return done != 0; }
-private:
- SGAtomic done;
-};
-
-/** Adapter from windows system / graphics context management API to
- * functions used by flightgear. This papers over the difference
- * between osgViewer::Viewer, which handles multiple windows, graphics
- * threads, etc., and the embedded viewer used with GLUT and SDL.
- */
-class WindowSystemAdapter : public osg::Referenced
-{
-public:
- WindowSystemAdapter();
- virtual ~WindowSystemAdapter() {}
- /** Vector of all the registered windows.
- */
- WindowVector windows;
- /** Register a window, assigning it an ID.
- * @param gc graphics context
- * @param windowName internal name (not displayed)
- * @return a graphics window
- */
- GraphicsWindow* registerWindow(osg::GraphicsContext* gc,
- const std::string& windowName);
- /** Initialize the plib pui interface library. This might happen
- *in another thread and may be deferred.
- */
- virtual void puInitialize();
- /** Find a window by name.
- * @param name the window name
- * @return the window or 0
- */
- GraphicsWindow* findWindow(const std::string& name);
- /** Get the global WindowSystemAdapter
- * @return the adapter
- */
- static WindowSystemAdapter* getWSA() { return _wsa.get(); }
- /** Set the global adapter
- * @param wsa the adapter
- */
- static void setWSA(WindowSystemAdapter* wsa) { _wsa = wsa; }
-protected:
- int _nextWindowID;
- osg::ref_ptr<GraphicsContextOperation> _puInitOp;
- bool _isPuInitialized;
- static osg::ref_ptr<WindowSystemAdapter> _wsa;
- // Default callbacks for plib
- static int puGetWindow();
- static void puGetWindowSize(int* width, int* height);
-
-};
-
-/**
- * Class for testing if flags are set in an object with a flags member.
- */
-template<typename T>
-class FlagTester : public std::unary_function<osg::ref_ptr<T>, bool>
-{
-public:
- /** Initialize with flags to test for.
- * @param flags logical or of flags to test.
- */
- FlagTester(unsigned flags_) : flags(flags_) {}
- /** test operator
- * @param obj An object with a flags member
- * @return true if flags member of obj contains any of the flags
- * (bitwise and with flags is nonzero).
- */
- bool operator() (const osg::ref_ptr<T>& obj)
- {
- return (obj->flags & flags) != 0;
- }
- unsigned flags;
-};
-
-}
-#endif
using std::cerr;
using std::endl;
+#include <Viewer/fgviewer.hxx>
#include "main.hxx"
#include "globals.hxx"
#include "fg_props.hxx"
-#include "fgviewer.hxx"
#include "fg_os.hxx"
#include <Sound/sample_queue.hxx>
#include <Airports/xmlloader.hxx>
#include <Network/HTTPClient.hxx>
+#include <Viewer/viewmgr.hxx>
+#include <Viewer/viewer.hxx>
+#include <Environment/presets.hxx>
#include "fg_init.hxx"
#include "fg_io.hxx"
#include "globals.hxx"
#include "logger.hxx"
#include "util.hxx"
-#include "viewmgr.hxx"
#include "main.hxx"
-#include <Main/viewer.hxx>
-#include <Environment/presets.hxx>
#include <boost/scoped_array.hpp>
#include <FDM/fdm_shell.hxx>
#include <Environment/ephemeris.hxx>
#include <Environment/environment_mgr.hxx>
+#include <Viewer/renderer.hxx>
+#include <Viewer/viewmgr.hxx>
#include "fg_init.hxx"
#include "fg_io.hxx"
#include "options.hxx"
#include "globals.hxx"
#include "logger.hxx"
-#include "renderer.hxx"
-#include "viewmgr.hxx"
#include "main.hxx"
#include <plib/pu.h>
#include <osg/GraphicsContext>
+#include <Viewer/renderer.hxx>
+#include <Viewer/FGEventHandler.hxx>
#include "fg_os.hxx"
#include "globals.hxx"
-#include "renderer.hxx"
-#include "FGEventHandler.hxx"
// fg_os callback registration APIs
//
+++ /dev/null
-// fg_os_osgviewer.cxx -- common functions for fg_os interface
-// implemented as an osgViewer
-//
-// Copyright (C) 2007 Tim Moore timoore@redhat.com
-// Copyright (C) 2007 Mathias Froehlich
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program 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 GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <algorithm>
-#include <iostream>
-#include <sstream>
-#include <string>
-
-#include <stdlib.h>
-
-#include <boost/foreach.hpp>
-
-#include <simgear/compiler.h>
-#include <simgear/structure/exception.hxx>
-#include <simgear/debug/logstream.hxx>
-#include <simgear/props/props_io.hxx>
-
-#include <osg/Camera>
-#include <osg/GraphicsContext>
-#include <osg/Group>
-#include <osg/Matrixd>
-#include <osg/Viewport>
-#include <osg/Version>
-#include <osg/View>
-#include <osgViewer/ViewerEventHandlers>
-#include <osgViewer/Viewer>
-#include <osgViewer/GraphicsWindow>
-
-#include <Scenery/scenery.hxx>
-#include "fg_os.hxx"
-#include "fg_props.hxx"
-#include "util.hxx"
-#include "globals.hxx"
-#include "renderer.hxx"
-#include "CameraGroup.hxx"
-#include "FGEventHandler.hxx"
-#include "WindowBuilder.hxx"
-#include "WindowSystemAdapter.hxx"
-
-// Static linking of OSG needs special macros
-#ifdef OSG_LIBRARY_STATIC
-#include <osgDB/Registry>
-USE_GRAPHICSWINDOW();
-// Image formats
-USE_OSGPLUGIN(bmp);
-USE_OSGPLUGIN(dds);
-USE_OSGPLUGIN(hdr);
-USE_OSGPLUGIN(pic);
-USE_OSGPLUGIN(pnm);
-USE_OSGPLUGIN(rgb);
-USE_OSGPLUGIN(tga);
-#ifdef OSG_JPEG_ENABLED
- USE_OSGPLUGIN(jpeg);
-#endif
-#ifdef OSG_PNG_ENABLED
- USE_OSGPLUGIN(png);
-#endif
-#ifdef OSG_TIFF_ENABLED
- USE_OSGPLUGIN(tiff);
-#endif
-// Model formats
-USE_OSGPLUGIN(3ds);
-USE_OSGPLUGIN(ac);
-USE_OSGPLUGIN(ive);
-USE_OSGPLUGIN(osg);
-USE_OSGPLUGIN(txf);
-#endif
-
-// fg_os implementation using OpenSceneGraph's osgViewer::Viewer class
-// to create the graphics window and run the event/update/render loop.
-
-//
-// fg_os implementation
-//
-
-using namespace std;
-using namespace flightgear;
-using namespace osg;
-
-static osg::ref_ptr<osgViewer::Viewer> viewer;
-static osg::ref_ptr<osg::Camera> mainCamera;
-
-static void setStereoMode( const char * mode )
-{
- DisplaySettings::StereoMode stereoMode = DisplaySettings::QUAD_BUFFER;
- bool stereoOn = true;
-
- if (strcmp(mode,"QUAD_BUFFER")==0)
- {
- stereoMode = DisplaySettings::QUAD_BUFFER;
- }
- else if (strcmp(mode,"ANAGLYPHIC")==0)
- {
- stereoMode = DisplaySettings::ANAGLYPHIC;
- }
- else if (strcmp(mode,"HORIZONTAL_SPLIT")==0)
- {
- stereoMode = DisplaySettings::HORIZONTAL_SPLIT;
- }
- else if (strcmp(mode,"VERTICAL_SPLIT")==0)
- {
- stereoMode = DisplaySettings::VERTICAL_SPLIT;
- }
- else if (strcmp(mode,"LEFT_EYE")==0)
- {
- stereoMode = DisplaySettings::LEFT_EYE;
- }
- else if (strcmp(mode,"RIGHT_EYE")==0)
- {
- stereoMode = DisplaySettings::RIGHT_EYE;
- }
- else if (strcmp(mode,"HORIZONTAL_INTERLACE")==0)
- {
- stereoMode = DisplaySettings::HORIZONTAL_INTERLACE;
- }
- else if (strcmp(mode,"VERTICAL_INTERLACE")==0)
- {
- stereoMode = DisplaySettings::VERTICAL_INTERLACE;
- }
- else if (strcmp(mode,"CHECKERBOARD")==0)
- {
- stereoMode = DisplaySettings::CHECKERBOARD;
- } else {
- stereoOn = false;
- }
- DisplaySettings::instance()->setStereo( stereoOn );
- DisplaySettings::instance()->setStereoMode( stereoMode );
-}
-
-static const char * getStereoMode()
-{
- DisplaySettings::StereoMode stereoMode = DisplaySettings::instance()->getStereoMode();
- bool stereoOn = DisplaySettings::instance()->getStereo();
- if( !stereoOn ) return "OFF";
- if( stereoMode == DisplaySettings::QUAD_BUFFER ) {
- return "QUAD_BUFFER";
- } else if( stereoMode == DisplaySettings::ANAGLYPHIC ) {
- return "ANAGLYPHIC";
- } else if( stereoMode == DisplaySettings::HORIZONTAL_SPLIT ) {
- return "HORIZONTAL_SPLIT";
- } else if( stereoMode == DisplaySettings::VERTICAL_SPLIT ) {
- return "VERTICAL_SPLIT";
- } else if( stereoMode == DisplaySettings::LEFT_EYE ) {
- return "LEFT_EYE";
- } else if( stereoMode == DisplaySettings::RIGHT_EYE ) {
- return "RIGHT_EYE";
- } else if( stereoMode == DisplaySettings::HORIZONTAL_INTERLACE ) {
- return "HORIZONTAL_INTERLACE";
- } else if( stereoMode == DisplaySettings::VERTICAL_INTERLACE ) {
- return "VERTICAL_INTERLACE";
- } else if( stereoMode == DisplaySettings::CHECKERBOARD ) {
- return "CHECKERBOARD";
- }
- return "OFF";
-}
-
-void fgOSOpenWindow(bool stencil)
-{
- viewer = new osgViewer::Viewer;
- viewer->setDatabasePager(FGScenery::getPagerSingleton());
- CameraGroup* cameraGroup = 0;
- std::string mode;
- mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
- if (mode == "AutomaticSelection")
- viewer->setThreadingModel(osgViewer::Viewer::AutomaticSelection);
- else if (mode == "CullDrawThreadPerContext")
- viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
- else if (mode == "DrawThreadPerContext")
- viewer->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
- else if (mode == "CullThreadPerCameraDrawThreadPerContext")
- viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
- else
- viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
- WindowBuilder::initWindowBuilder(stencil);
- WindowBuilder *windowBuilder = WindowBuilder::getWindowBuilder();
-
- // Look for windows, camera groups, and the old syntax of
- // top-level cameras
- SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
- SGPropertyNode* cgroupNode = renderingNode->getNode("camera-group", true);
- bool oldSyntax = !cgroupNode->hasChild("camera");
- if (oldSyntax) {
- for (int i = 0; i < renderingNode->nChildren(); ++i) {
- SGPropertyNode* propNode = renderingNode->getChild(i);
- const char* propName = propNode->getName();
- if (!strcmp(propName, "window") || !strcmp(propName, "camera")) {
- SGPropertyNode* copiedNode
- = cgroupNode->getNode(propName, propNode->getIndex(), true);
- copyProperties(propNode, copiedNode);
- }
- }
- vector<SGPropertyNode_ptr> cameras = cgroupNode->getChildren("camera");
- SGPropertyNode* masterCamera = 0;
- BOOST_FOREACH(SGPropertyNode_ptr& camera, cameras) {
- if (camera->getDoubleValue("shear-x", 0.0) == 0.0
- && camera->getDoubleValue("shear-y", 0.0) == 0.0) {
- masterCamera = camera.ptr();
- break;
- }
- }
- if (!masterCamera) {
- masterCamera = cgroupNode->getChild("camera", cameras.size(), true);
- setValue(masterCamera->getNode("window/name", true),
- windowBuilder->getDefaultWindowName());
- }
- SGPropertyNode* nameNode = masterCamera->getNode("window/name");
- if (nameNode)
- setValue(cgroupNode->getNode("gui/window/name", true),
- nameNode->getStringValue());
- }
- cameraGroup = CameraGroup::buildCameraGroup(viewer.get(), cgroupNode);
- Camera* guiCamera = getGUICamera(cameraGroup);
- if (guiCamera) {
- Viewport* guiViewport = guiCamera->getViewport();
- fgSetInt("/sim/startup/xsize", guiViewport->width());
- fgSetInt("/sim/startup/ysize", guiViewport->height());
- }
- FGEventHandler* manipulator = globals->get_renderer()->getEventHandler();
- WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
- if (wsa->windows.size() != 1) {
- manipulator->setResizable(false);
- }
- viewer->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);
- viewer->addEventHandler(manipulator);
- // Let FG handle the escape key with a confirmation
- viewer->setKeyEventSetsDone(0);
- // The viewer won't start without some root.
- viewer->setSceneData(new osg::Group);
- globals->get_renderer()->setViewer(viewer.get());
- CameraGroup::setDefault(cameraGroup);
-
- DisplaySettings * displaySettings = DisplaySettings::instance();
- fgTie("/sim/rendering/osg-displaysettings/eye-separation", displaySettings, &DisplaySettings::getEyeSeparation, &DisplaySettings::setEyeSeparation );
- fgTie("/sim/rendering/osg-displaysettings/screen-distance", displaySettings, &DisplaySettings::getScreenDistance, &DisplaySettings::setScreenDistance );
- fgTie("/sim/rendering/osg-displaysettings/screen-width", displaySettings, &DisplaySettings::getScreenWidth, &DisplaySettings::setScreenWidth );
- fgTie("/sim/rendering/osg-displaysettings/screen-height", displaySettings, &DisplaySettings::getScreenHeight, &DisplaySettings::setScreenHeight );
- fgTie("/sim/rendering/osg-displaysettings/stereo-mode", getStereoMode, setStereoMode );
- fgTie("/sim/rendering/osg-displaysettings/double-buffer", displaySettings, &DisplaySettings::getDoubleBuffer, &DisplaySettings::setDoubleBuffer );
- fgTie("/sim/rendering/osg-displaysettings/depth-buffer", displaySettings, &DisplaySettings::getDepthBuffer, &DisplaySettings::setDepthBuffer );
- fgTie("/sim/rendering/osg-displaysettings/rgb", displaySettings, &DisplaySettings::getRGB, &DisplaySettings::setRGB );
-}
-
-
-static int status = 0;
-
-void fgOSExit(int code)
-{
- viewer->setDone(true);
- viewer->getDatabasePager()->cancel();
- status = code;
-}
-
-int fgOSMainLoop()
-{
- ref_ptr<FGEventHandler> manipulator
- = globals->get_renderer()->getEventHandler();
- viewer->setReleaseContextAtEndOfFrameHint(false);
- if (!viewer->isRealized())
- viewer->realize();
- while (!viewer->done()) {
- fgIdleHandler idleFunc = manipulator->getIdleHandler();
- if (idleFunc)
- (*idleFunc)();
- globals->get_renderer()->update();
- viewer->frame();
- }
-
- return status;
-}
-
-int fgGetKeyModifiers()
-{
- if (!globals->get_renderer()) { // happens during shutdown
- return 0;
- }
-
- return globals->get_renderer()->getEventHandler()->getCurrentModifiers();
-}
-
-void fgWarpMouse(int x, int y)
-{
- warpGUIPointer(CameraGroup::getDefault(), x, y);
-}
-
-void fgOSInit(int* argc, char** argv)
-{
- globals->get_renderer()->init();
- WindowSystemAdapter::setWSA(new WindowSystemAdapter);
-}
-
-// Noop
-void fgOSFullScreen()
-{
-}
-
-static void setMouseCursor(osgViewer::GraphicsWindow* gw, int cursor)
-{
- if (!gw) {
- return;
- }
-
- osgViewer::GraphicsWindow::MouseCursor mouseCursor;
- mouseCursor = osgViewer::GraphicsWindow::InheritCursor;
- if (cursor == MOUSE_CURSOR_NONE)
- mouseCursor = osgViewer::GraphicsWindow::NoCursor;
- else if(cursor == MOUSE_CURSOR_POINTER)
-#ifdef SG_MAC
- // osgViewer-Cocoa lacks RightArrowCursor, use Left
- mouseCursor = osgViewer::GraphicsWindow::LeftArrowCursor;
-#else
- mouseCursor = osgViewer::GraphicsWindow::RightArrowCursor;
-#endif
- else if(cursor == MOUSE_CURSOR_WAIT)
- mouseCursor = osgViewer::GraphicsWindow::WaitCursor;
- else if(cursor == MOUSE_CURSOR_CROSSHAIR)
- mouseCursor = osgViewer::GraphicsWindow::CrosshairCursor;
- else if(cursor == MOUSE_CURSOR_LEFTRIGHT)
- mouseCursor = osgViewer::GraphicsWindow::LeftRightCursor;
- else if(cursor == MOUSE_CURSOR_TOPSIDE)
- mouseCursor = osgViewer::GraphicsWindow::TopSideCursor;
- else if(cursor == MOUSE_CURSOR_BOTTOMSIDE)
- mouseCursor = osgViewer::GraphicsWindow::BottomSideCursor;
- else if(cursor == MOUSE_CURSOR_LEFTSIDE)
- mouseCursor = osgViewer::GraphicsWindow::LeftSideCursor;
- else if(cursor == MOUSE_CURSOR_RIGHTSIDE)
- mouseCursor = osgViewer::GraphicsWindow::RightSideCursor;
- else if(cursor == MOUSE_CURSOR_TOPLEFT)
- mouseCursor = osgViewer::GraphicsWindow::TopLeftCorner;
- else if(cursor == MOUSE_CURSOR_TOPRIGHT)
- mouseCursor = osgViewer::GraphicsWindow::TopRightCorner;
- else if(cursor == MOUSE_CURSOR_BOTTOMLEFT)
- mouseCursor = osgViewer::GraphicsWindow::BottomLeftCorner;
- else if(cursor == MOUSE_CURSOR_BOTTOMRIGHT)
- mouseCursor = osgViewer::GraphicsWindow::BottomRightCorner;
-
- gw->setCursor(mouseCursor);
-}
-
-static int _cursor = -1;
-
-void fgSetMouseCursor(int cursor)
-{
- _cursor = cursor;
-
- std::vector<osgViewer::GraphicsWindow*> windows;
- viewer->getWindows(windows);
- BOOST_FOREACH(osgViewer::GraphicsWindow* gw, windows) {
- setMouseCursor(gw, cursor);
- }
-}
-
-int fgGetMouseCursor()
-{
- return _cursor;
-}
+++ /dev/null
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <iostream>
-#include <cstdlib>
-
-#include <osg/ArgumentParser>
-#include <osg/Fog>
-#include <osgDB/ReadFile>
-#include <osgDB/Registry>
-#include <osgDB/WriteFile>
-#include <osgViewer/Renderer>
-#include <osgViewer/Viewer>
-#include <osgViewer/ViewerEventHandlers>
-#include <osgGA/KeySwitchMatrixManipulator>
-#include <osgGA/TrackballManipulator>
-#include <osgGA/FlightManipulator>
-#include <osgGA/DriveManipulator>
-#include <osgGA/TerrainManipulator>
-#include <osgGA/StateSetManipulator>
-
-#include <simgear/props/props.hxx>
-#include <simgear/props/props_io.hxx>
-#include <simgear/misc/sg_path.hxx>
-#include <simgear/scene/material/EffectCullVisitor.hxx>
-#include <simgear/scene/material/matlib.hxx>
-#include <simgear/scene/util/SGReaderWriterOptions.hxx>
-#include <simgear/scene/tgdb/userdata.hxx>
-#include <simgear/scene/model/ModelRegistry.hxx>
-#include <simgear/scene/model/modellib.hxx>
-
-#include <Scenery/scenery.hxx>
-
-#include "fg_init.hxx"
-#include "fg_props.hxx"
-#include "globals.hxx"
-#include "options.hxx"
-
-class GraphDumpHandler : public osgGA::GUIEventHandler
-{
-public:
- GraphDumpHandler() : _keyDump('d') {}
- void setKeyDump(int key) { _keyDump = key; }
- int getKeyDump() const { return _keyDump; }
- bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);
-
- /** Get the keyboard and mouse usage of this manipulator.*/
- virtual void getUsage(osg::ApplicationUsage& usage) const;
-protected:
- int _keyDump;
-};
-
-static void dumpOut(osg::Node* node)
-{
- char filename[24];
- static int count = 1;
-
- while (count < 1000) {
- FILE *fp;
- snprintf(filename, 24, "fgviewer-%03d.osg", count++);
- if ( (fp = fopen(filename, "r")) == NULL )
- break;
- fclose(fp);
- }
-
- if (osgDB::writeNodeFile(*node, filename))
- std::cerr << "Entire scene graph saved to \"" << filename << "\".\n";
- else
- std::cerr << "Failed to save to \"" << filename << "\".\n";
-}
-
-bool GraphDumpHandler::handle(const osgGA::GUIEventAdapter& ea,
- osgGA::GUIActionAdapter& aa)
-{
- osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
- if (!view)
- return false;
- if (ea.getHandled())
- return false;
- switch(ea.getEventType()) {
- case osgGA::GUIEventAdapter::KEYUP:
- if (ea.getKey() == _keyDump) {
- dumpOut(view->getScene()->getSceneData());
- return true;
- }
- break;
- default:
- return false;
- }
- return false;
-}
-
-void GraphDumpHandler::getUsage(osg::ApplicationUsage& usage) const
-{
- std::ostringstream ostr;
- ostr << char(_keyDump);
- usage.addKeyboardMouseBinding(ostr.str(),
- "Dump scene graph to file");
-}
-
-int
-fgviewerMain(int argc, char** argv)
-{
-
- sgUserDataInit(0);
-
- // use an ArgumentParser object to manage the program arguments.
- osg::ArgumentParser arguments(&argc, argv);
-
- // construct the viewer.
- osgViewer::Viewer viewer(arguments);
- osg::Camera* camera = viewer.getCamera();
- osgViewer::Renderer* renderer
- = static_cast<osgViewer::Renderer*>(camera->getRenderer());
- for (int i = 0; i < 2; ++i) {
- osgUtil::SceneView* sceneView = renderer->getSceneView(i);
- sceneView->setCullVisitor(new simgear::EffectCullVisitor);
- }
- // Shaders expect valid fog
- osg::StateSet* cameraSS = camera->getOrCreateStateSet();
- osg::Fog* fog = new osg::Fog;
- fog->setMode(osg::Fog::EXP2);
- fog->setColor(osg::Vec4(1.0, 1.0, 1.0, 1.0));
- fog->setDensity(.0000001);
- cameraSS->setAttributeAndModes(fog);
- // ... for some reason, get rid of that FIXME!
- viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
-
- // set up the camera manipulators.
- osgGA::KeySwitchMatrixManipulator* keyswitchManipulator;
- 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);
- viewer.setCameraManipulator(keyswitchManipulator);
-
- // Usefull stats
- viewer.addEventHandler(new osgViewer::HelpHandler);
- viewer.addEventHandler(new osgViewer::StatsHandler);
- viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
- // Same FIXME ...
- // viewer.addEventHandler(new osgViewer::ThreadingHandler);
- viewer.addEventHandler(new osgViewer::LODScaleHandler);
- viewer.addEventHandler(new osgViewer::ScreenCaptureHandler);
-
- viewer.addEventHandler(new GraphDumpHandler);
-
- // Extract files to load from arguments now; this way fgInitConfig
- // won't choke on them.
- string_list dataFiles;
- for (int i = arguments.argc() - 1; i >= 0; --i) {
- if (arguments.isOption(i)) {
- break;
- } else {
- dataFiles.insert(dataFiles.begin(), arguments[i]);
- arguments.remove(i);
- }
- }
-
- // A subset of full flightgear initialization.
- // Allocate global data structures. This needs to happen before
- // we parse command line options
-
- globals = new FGGlobals;
-
- if ( !fgInitConfig(arguments.argc(), arguments.argv()) ) {
- SG_LOG( SG_GENERAL, SG_ALERT, "Config option parsing failed ..." );
- exit(-1);
- }
-
- osgDB::FilePathList filePathList
- = osgDB::Registry::instance()->getDataFilePathList();
- filePathList.push_back(globals->get_fg_root());
-
- string_list path_list = globals->get_fg_scenery();
- for (unsigned i = 0; i < path_list.size(); ++i) {
- filePathList.push_back(path_list[i]);
- }
-
- globals->set_matlib( new SGMaterialLib );
- simgear::SGModelLib::init(globals->get_fg_root(), globals->get_props());
-
- // Initialize the material property subsystem.
-
- SGPath mpath( globals->get_fg_root() );
- mpath.append( fgGetString("/sim/rendering/materials-file") );
- if ( ! globals->get_matlib()->load(globals->get_fg_root(), mpath.str(),
- globals->get_props()) ) {
- SG_LOG( SG_GENERAL, SG_ALERT,
- "Error loading materials file " << mpath.str() );
- exit(-1);
- }
-
- globals->set_scenery( new FGScenery );
- globals->get_scenery()->init();
- globals->get_scenery()->bind();
-
- // The file path list must be set in the registry.
- osgDB::Registry::instance()->getDataFilePathList() = filePathList;
-
- simgear::SGReaderWriterOptions* options = new simgear::SGReaderWriterOptions;
- options->getDatabasePathList() = filePathList;
- options->setMaterialLib(globals->get_matlib());
- options->setPropertyNode(globals->get_props());
-
- // read the scene from the list of file specified command line args.
- osg::ref_ptr<osg::Node> loadedModel;
- loadedModel = osgDB::readNodeFiles(dataFiles, options);
-
- // if no model has been successfully loaded report failure.
- if (!loadedModel.valid()) {
- std::cerr << arguments.getApplicationName()
- << ": No data loaded" << std::endl;
- return EXIT_FAILURE;
- }
-
- // pass the loaded scene graph to the viewer.
- viewer.setSceneData(loadedModel.get());
-
- return viewer.run();
-}
+++ /dev/null
-#ifndef __FG_FGVIEWER_HXX
-#define __FG_FGVIEWER_HXX 1
-
-int fgviewerMain(int argc, char** argv);
-#endif
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
#include <Navaids/navlist.hxx>
+#include <Viewer/renderer.hxx>
+#include <Viewer/viewmgr.hxx>
#include "globals.hxx"
-#include "renderer.hxx"
-#include "viewmgr.hxx"
#include "locale.hxx"
#include "fg_props.hxx"
#include <GUI/gui.h>
#include <GUI/new_gui.hxx>
#include <MultiPlayer/multiplaymgr.hxx>
+#include <Viewer/CameraGroup.hxx>
+#include <Viewer/viewer.hxx>
+#include <Viewer/WindowSystemAdapter.hxx>
+#include <Viewer/splash.hxx>
+#include <Viewer/renderer.hxx>
-#include "CameraGroup.hxx"
#include "fg_commands.hxx"
#include "fg_io.hxx"
-#include "renderer.hxx"
-#include "splash.hxx"
#include "main.hxx"
#include "util.hxx"
#include "fg_init.hxx"
#include "fg_os.hxx"
-#include "WindowSystemAdapter.hxx"
-#include <Main/viewer.hxx>
-#include <Main/fg_props.hxx>
+#include "fg_props.hxx"
using namespace flightgear;
#include "fg_props.hxx"
#include "options.hxx"
#include "util.hxx"
-#include "viewmgr.hxx"
#include "main.hxx"
-#include <Main/viewer.hxx>
-#include <Main/locale.hxx>
+#include "locale.hxx"
+#include <Viewer/viewer.hxx>
+#include <Viewer/viewmgr.hxx>
#include <Environment/presets.hxx>
#include <osg/Version>
+++ /dev/null
-// renderer.cxx -- top level sim routines
-//
-// Written by Curtis Olson, started May 1997.
-// This file contains parts of main.cxx prior to october 2004
-//
-// Copyright (C) 1997 - 2002 Curtis L. Olson - http://www.flightgear.org/~curt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program 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 GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#ifdef HAVE_WINDOWS_H
-# include <windows.h>
-#endif
-
-#include <simgear/compiler.h>
-
-#include <algorithm>
-#include <iostream>
-#include <map>
-#include <vector>
-#include <typeinfo>
-
-#include <osg/ref_ptr>
-#include <osg/AlphaFunc>
-#include <osg/BlendFunc>
-#include <osg/Camera>
-#include <osg/CullFace>
-#include <osg/CullStack>
-#include <osg/Depth>
-#include <osg/Fog>
-#include <osg/Group>
-#include <osg/Hint>
-#include <osg/Light>
-#include <osg/LightModel>
-#include <osg/LightSource>
-#include <osg/Material>
-#include <osg/Math>
-#include <osg/NodeCallback>
-#include <osg/Notify>
-#include <osg/PolygonMode>
-#include <osg/PolygonOffset>
-#include <osg/Program>
-#include <osg/Version>
-#include <osg/TexEnv>
-
-#include <osgUtil/LineSegmentIntersector>
-
-#include <osg/io_utils>
-#include <osgDB/WriteFile>
-#include <osgViewer/Renderer>
-
-#include <simgear/math/SGMath.hxx>
-#include <simgear/scene/material/matlib.hxx>
-#include <simgear/scene/material/EffectCullVisitor.hxx>
-#include <simgear/scene/material/Effect.hxx>
-#include <simgear/scene/material/EffectGeode.hxx>
-#include <simgear/scene/model/animation.hxx>
-#include <simgear/scene/model/placement.hxx>
-#include <simgear/scene/sky/sky.hxx>
-#include <simgear/scene/util/SGUpdateVisitor.hxx>
-#include <simgear/scene/util/RenderConstants.hxx>
-#include <simgear/scene/util/SGSceneUserData.hxx>
-#include <simgear/scene/tgdb/GroundLightManager.hxx>
-#include <simgear/scene/tgdb/pt_lights.hxx>
-#include <simgear/structure/OSGUtils.hxx>
-#include <simgear/props/props.hxx>
-#include <simgear/timing/sg_time.hxx>
-#include <simgear/ephemeris/ephemeris.hxx>
-#include <simgear/math/sg_random.h>
-#ifdef FG_JPEG_SERVER
-#include <simgear/screen/jpgfactory.hxx>
-#endif
-
-#include <Time/light.hxx>
-#include <Time/light.hxx>
-#include <Cockpit/panel.hxx>
-
-#include <Model/panelnode.hxx>
-#include <Model/modelmgr.hxx>
-#include <Model/acmodel.hxx>
-#include <Scenery/scenery.hxx>
-#include <Scenery/redout.hxx>
-#include <GUI/new_gui.hxx>
-#include <Instrumentation/HUD/HUD.hxx>
-#include <Environment/precipitation_mgr.hxx>
-#include <Environment/environment_mgr.hxx>
-
-#include "splash.hxx"
-#include "renderer.hxx"
-#include "main.hxx"
-#include "CameraGroup.hxx"
-#include "FGEventHandler.hxx"
-#include <Main/viewer.hxx>
-#include <Main/viewmgr.hxx>
-
-using namespace osg;
-using namespace simgear;
-using namespace flightgear;
-
-class FGHintUpdateCallback : public osg::StateAttribute::Callback {
-public:
- FGHintUpdateCallback(const char* configNode) :
- mConfigNode(fgGetNode(configNode, true))
- { }
- virtual void operator()(osg::StateAttribute* stateAttribute,
- osg::NodeVisitor*)
- {
- assert(dynamic_cast<osg::Hint*>(stateAttribute));
- osg::Hint* hint = static_cast<osg::Hint*>(stateAttribute);
-
- const char* value = mConfigNode->getStringValue();
- if (!value)
- hint->setMode(GL_DONT_CARE);
- else if (0 == strcmp(value, "nicest"))
- hint->setMode(GL_NICEST);
- else if (0 == strcmp(value, "fastest"))
- hint->setMode(GL_FASTEST);
- else
- hint->setMode(GL_DONT_CARE);
- }
-private:
- SGPropertyNode_ptr mConfigNode;
-};
-
-
-class SGPuDrawable : public osg::Drawable {
-public:
- SGPuDrawable()
- {
- // Dynamic stuff, do not store geometry
- setUseDisplayList(false);
- setDataVariance(Object::DYNAMIC);
-
- osg::StateSet* stateSet = getOrCreateStateSet();
- stateSet->setRenderBinDetails(1001, "RenderBin");
- // speed optimization?
- stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
- // We can do translucent menus, so why not. :-)
- stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
- stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
- stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF);
-
- stateSet->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE));
-
- stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
- stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
- }
- virtual void drawImplementation(osg::RenderInfo& renderInfo) const
- { drawImplementation(*renderInfo.getState()); }
- void drawImplementation(osg::State& state) const
- {
- state.setActiveTextureUnit(0);
- state.setClientActiveTextureUnit(0);
-
- state.disableAllVertexArrays();
-
- glPushAttrib(GL_ALL_ATTRIB_BITS);
- glPushClientAttrib(~0u);
-
- puDisplay();
-
- glPopClientAttrib();
- glPopAttrib();
- }
-
- virtual osg::Object* cloneType() const { return new SGPuDrawable; }
- virtual osg::Object* clone(const osg::CopyOp&) const { return new SGPuDrawable; }
-
-private:
-};
-
-class SGHUDDrawable : public osg::Drawable {
-public:
- SGHUDDrawable()
- {
- // Dynamic stuff, do not store geometry
- setUseDisplayList(false);
- setDataVariance(Object::DYNAMIC);
-
- osg::StateSet* stateSet = getOrCreateStateSet();
- stateSet->setRenderBinDetails(1000, "RenderBin");
-
- // speed optimization?
- stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
- stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
- stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
- stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
- stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
-
- stateSet->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE));
- }
- virtual void drawImplementation(osg::RenderInfo& renderInfo) const
- { drawImplementation(*renderInfo.getState()); }
- void drawImplementation(osg::State& state) const
- {
- state.setActiveTextureUnit(0);
- state.setClientActiveTextureUnit(0);
- state.disableAllVertexArrays();
-
- glPushAttrib(GL_ALL_ATTRIB_BITS);
- glPushClientAttrib(~0u);
-
- HUD *hud = static_cast<HUD*>(globals->get_subsystem("hud"));
- hud->draw(state);
-
- glPopClientAttrib();
- glPopAttrib();
- }
-
- virtual osg::Object* cloneType() const { return new SGHUDDrawable; }
- virtual osg::Object* clone(const osg::CopyOp&) const { return new SGHUDDrawable; }
-
-private:
-};
-
-class FGLightSourceUpdateCallback : public osg::NodeCallback {
-public:
-
- /**
- * @param isSun true if the light is the actual sun i.e., for
- * illuminating the moon.
- */
- FGLightSourceUpdateCallback(bool isSun = false) : _isSun(isSun) {}
- FGLightSourceUpdateCallback(const FGLightSourceUpdateCallback& nc,
- const CopyOp& op)
- : NodeCallback(nc, op), _isSun(nc._isSun)
- {}
- META_Object(flightgear,FGLightSourceUpdateCallback);
-
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- assert(dynamic_cast<osg::LightSource*>(node));
- osg::LightSource* lightSource = static_cast<osg::LightSource*>(node);
- osg::Light* light = lightSource->getLight();
-
- FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
- if (_isSun) {
- light->setAmbient(Vec4(0.0f, 0.0f, 0.0f, 0.0f));
- light->setDiffuse(Vec4(1.0f, 1.0f, 1.0f, 1.0f));
- light->setSpecular(Vec4(0.0f, 0.0f, 0.0f, 0.0f));
- } else {
- light->setAmbient(toOsg(l->scene_ambient()));
- light->setDiffuse(toOsg(l->scene_diffuse()));
- light->setSpecular(toOsg(l->scene_specular()));
- }
- osg::Vec4f position(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2], 0);
- light->setPosition(position);
-
- traverse(node, nv);
- }
-private:
- const bool _isSun;
-};
-
-class FGWireFrameModeUpdateCallback : public osg::StateAttribute::Callback {
-public:
- FGWireFrameModeUpdateCallback() :
- mWireframe(fgGetNode("/sim/rendering/wireframe", true))
- { }
- virtual void operator()(osg::StateAttribute* stateAttribute,
- osg::NodeVisitor*)
- {
- assert(dynamic_cast<osg::PolygonMode*>(stateAttribute));
- osg::PolygonMode* polygonMode;
- polygonMode = static_cast<osg::PolygonMode*>(stateAttribute);
-
- if (mWireframe->getBoolValue())
- polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
- osg::PolygonMode::LINE);
- else
- polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
- osg::PolygonMode::FILL);
- }
-private:
- SGPropertyNode_ptr mWireframe;
-};
-
-class FGLightModelUpdateCallback : public osg::StateAttribute::Callback {
-public:
- FGLightModelUpdateCallback() :
- mHighlights(fgGetNode("/sim/rendering/specular-highlight", true))
- { }
- virtual void operator()(osg::StateAttribute* stateAttribute,
- osg::NodeVisitor*)
- {
- assert(dynamic_cast<osg::LightModel*>(stateAttribute));
- osg::LightModel* lightModel;
- lightModel = static_cast<osg::LightModel*>(stateAttribute);
-
-#if 0
- FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
- lightModel->setAmbientIntensity(toOsg(l->scene_ambient());
-#else
- lightModel->setAmbientIntensity(osg::Vec4(0, 0, 0, 1));
-#endif
- lightModel->setTwoSided(true);
- lightModel->setLocalViewer(false);
-
- if (mHighlights->getBoolValue()) {
- lightModel->setColorControl(osg::LightModel::SEPARATE_SPECULAR_COLOR);
- } else {
- lightModel->setColorControl(osg::LightModel::SINGLE_COLOR);
- }
- }
-private:
- SGPropertyNode_ptr mHighlights;
-};
-
-class FGFogEnableUpdateCallback : public osg::StateSet::Callback {
-public:
- FGFogEnableUpdateCallback() :
- mFogEnabled(fgGetNode("/sim/rendering/fog", true))
- { }
- virtual void operator()(osg::StateSet* stateSet, osg::NodeVisitor*)
- {
- if (strcmp(mFogEnabled->getStringValue(), "disabled") == 0) {
- stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
- } else {
- stateSet->setMode(GL_FOG, osg::StateAttribute::ON);
- }
- }
-private:
- SGPropertyNode_ptr mFogEnabled;
-};
-
-class FGFogUpdateCallback : public osg::StateAttribute::Callback {
-public:
- virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
- {
- assert(dynamic_cast<SGUpdateVisitor*>(nv));
- assert(dynamic_cast<osg::Fog*>(sa));
- SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
- osg::Fog* fog = static_cast<osg::Fog*>(sa);
- fog->setMode(osg::Fog::EXP2);
- fog->setColor(toOsg(updateVisitor->getFogColor()));
- fog->setDensity(updateVisitor->getFogExp2Density());
- }
-};
-
-// update callback for the switch node guarding that splash
-class FGScenerySwitchCallback : public osg::NodeCallback {
-public:
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- assert(dynamic_cast<osg::Switch*>(node));
- osg::Switch* sw = static_cast<osg::Switch*>(node);
-
- bool enabled = scenery_enabled;
- sw->setValue(0, enabled);
- if (!enabled)
- return;
- traverse(node, nv);
- }
-
- static bool scenery_enabled;
-};
-
-bool FGScenerySwitchCallback::scenery_enabled = false;
-
-static osg::ref_ptr<osg::FrameStamp> mFrameStamp = new osg::FrameStamp;
-static osg::ref_ptr<SGUpdateVisitor> mUpdateVisitor= new SGUpdateVisitor;
-
-static osg::ref_ptr<osg::Group> mRealRoot = new osg::Group;
-static osg::ref_ptr<osg::Group> mDeferredRealRoot = new osg::Group;
-
-static osg::ref_ptr<osg::Group> mRoot = new osg::Group;
-
-static osg::ref_ptr<osg::Switch> panelSwitch;
-
-
-// update callback for the switch node controlling the 2D panel
-class FGPanelSwitchCallback : public osg::NodeCallback {
-public:
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- assert(dynamic_cast<osg::Switch*>(node));
- osg::Switch* sw = static_cast<osg::Switch*>(node);
-
- bool enabled = fgPanelVisible();
- sw->setValue(0, enabled);
- if (!enabled)
- return;
- traverse(node, nv);
- }
-};
-
-#ifdef FG_JPEG_SERVER
-static void updateRenderer()
-{
- globals->get_renderer()->update();
-}
-#endif
-
-FGRenderer::FGRenderer() :
- _sky(NULL),
- _ambientFactor( new osg::Uniform( "fg_SunAmbientColor", osg::Vec4f() ) ),
- _sunDiffuse( new osg::Uniform( "fg_SunDiffuseColor", osg::Vec4f() ) ),
- _sunSpecular( new osg::Uniform( "fg_SunSpecularColor", osg::Vec4f() ) ),
- _sunDirection( new osg::Uniform( "fg_SunDirection", osg::Vec3f() ) ),
- _planes( new osg::Uniform( "fg_Planes", osg::Vec3f() ) ),
- _fogColor( new osg::Uniform( "fg_FogColor", osg::Vec4f(1.0, 1.0, 1.0, 1.0) ) ),
- _fogDensity( new osg::Uniform( "fg_FogDensity", 0.0001f ) ),
- _shadowNumber( new osg::Uniform( "fg_ShadowNumber", (int)4 ) ),
- _shadowDistances( new osg::Uniform( "fg_ShadowDistances", osg::Vec4f(5.0, 50.0, 500.0, 5000.0 ) ) )
-{
-#ifdef FG_JPEG_SERVER
- jpgRenderFrame = updateRenderer;
-#endif
- eventHandler = new FGEventHandler;
-
- _numCascades = 4;
- _cascadeFar[0] = 5.f;
- _cascadeFar[1] = 50.f;
- _cascadeFar[2] = 500.f;
- _cascadeFar[3] = 5000.f;
-}
-
-FGRenderer::~FGRenderer()
-{
-#ifdef FG_JPEG_SERVER
- jpgRenderFrame = NULL;
-#endif
- delete _sky;
-}
-
-// Initialize various GL/view parameters
-// XXX This should be called "preinit" or something, as it initializes
-// critical parts of the scene graph in addition to the splash screen.
-void
-FGRenderer::splashinit( void ) {
- osgViewer::Viewer* viewer = getViewer();
- mRealRoot = dynamic_cast<osg::Group*>(viewer->getSceneData());
- ref_ptr<Node> splashNode = fgCreateSplashNode();
- if (_classicalRenderer) {
- mRealRoot->addChild(splashNode.get());
- } else {
- for ( CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
- ii != CameraGroup::getDefault()->camerasEnd();
- ++ii )
- {
- CameraInfo* info = ii->get();
- Camera* camera = info->getCamera(DISPLAY_CAMERA);
- if (camera == 0) continue;
-
- camera->addChild(splashNode.get());
- }
- }
- mFrameStamp = viewer->getFrameStamp();
- // Scene doesn't seem to pass the frame stamp to the update
- // visitor automatically.
- mUpdateVisitor->setFrameStamp(mFrameStamp.get());
- viewer->setUpdateVisitor(mUpdateVisitor.get());
- fgSetDouble("/sim/startup/splash-alpha", 1.0);
-}
-
-class ShadowMapSizeListener : public SGPropertyChangeListener {
-public:
- virtual void valueChanged(SGPropertyNode* node) {
- globals->get_renderer()->updateShadowMapSize(node->getIntValue());
- }
-};
-
-class ShadowEnabledListener : public SGPropertyChangeListener {
-public:
- virtual void valueChanged(SGPropertyNode* node) {
- globals->get_renderer()->enableShadows(node->getBoolValue());
- }
-};
-
-class ShadowNumListener : public SGPropertyChangeListener {
-public:
- virtual void valueChanged(SGPropertyNode* node) {
- globals->get_renderer()->updateCascadeNumber(node->getIntValue());
- }
-};
-
-class ShadowRangeListener : public SGPropertyChangeListener {
-public:
- virtual void valueChanged(SGPropertyNode* node) {
- globals->get_renderer()->updateCascadeFar(node->getIndex(), node->getFloatValue());
- }
-};
-
-void
-FGRenderer::init( void )
-{
- _classicalRenderer = !fgGetBool("/sim/rendering/rembrandt", false);
- _shadowMapSize = fgGetInt( "/sim/rendering/shadows/map-size", 4096 );
- fgAddChangeListener( new ShadowMapSizeListener, "/sim/rendering/shadows/map-size" );
- fgAddChangeListener( new ShadowEnabledListener, "/sim/rendering/shadows/enabled" );
- ShadowRangeListener* srl = new ShadowRangeListener;
- fgAddChangeListener(srl, "/sim/rendering/shadows/cascade-far-m[0]");
- fgAddChangeListener(srl, "/sim/rendering/shadows/cascade-far-m[1]");
- fgAddChangeListener(srl, "/sim/rendering/shadows/cascade-far-m[2]");
- fgAddChangeListener(srl, "/sim/rendering/shadows/cascade-far-m[3]");
- fgAddChangeListener(new ShadowNumListener, "/sim/rendering/shadows/num-cascades");
- _numCascades = fgGetInt("/sim/rendering/shadows/num-cascades", 4);
- _cascadeFar[0] = fgGetFloat("/sim/rendering/shadows/cascade-far-m[0]", 5.0f);
- _cascadeFar[1] = fgGetFloat("/sim/rendering/shadows/cascade-far-m[1]", 50.0f);
- _cascadeFar[2] = fgGetFloat("/sim/rendering/shadows/cascade-far-m[2]", 500.0f);
- _cascadeFar[3] = fgGetFloat("/sim/rendering/shadows/cascade-far-m[3]", 5000.0f);
- _scenery_loaded = fgGetNode("/sim/sceneryloaded", true);
- _scenery_override = fgGetNode("/sim/sceneryloaded-override", true);
- _panel_hotspots = fgGetNode("/sim/panel-hotspots", true);
- _virtual_cockpit = fgGetNode("/sim/virtual-cockpit", true);
-
- _sim_delta_sec = fgGetNode("/sim/time/delta-sec", true);
-
- _xsize = fgGetNode("/sim/startup/xsize", true);
- _ysize = fgGetNode("/sim/startup/ysize", true);
- _splash_alpha = fgGetNode("/sim/startup/splash-alpha", true);
-
- _skyblend = fgGetNode("/sim/rendering/skyblend", true);
- _point_sprites = fgGetNode("/sim/rendering/point-sprites", true);
- _enhanced_lighting = fgGetNode("/sim/rendering/enhanced-lighting", true);
- _distance_attenuation = fgGetNode("/sim/rendering/distance-attenuation", true);
- _horizon_effect = fgGetNode("/sim/rendering/horizon-effect", true);
- _textures = fgGetNode("/sim/rendering/textures", true);
-
- _altitude_ft = fgGetNode("/position/altitude-ft", true);
-
- _cloud_status = fgGetNode("/environment/clouds/status", true);
- _visibility_m = fgGetNode("/environment/visibility-m", true);
-
- bool use_point_sprites = _point_sprites->getBoolValue();
- bool enhanced_lighting = _enhanced_lighting->getBoolValue();
- bool distance_attenuation = _distance_attenuation->getBoolValue();
-
- SGConfigureDirectionalLights( use_point_sprites, enhanced_lighting,
- distance_attenuation );
-
- if (const char* tc = fgGetString("/sim/rendering/texture-compression", NULL)) {
- if (strcmp(tc, "false") == 0 || strcmp(tc, "off") == 0 ||
- strcmp(tc, "0") == 0 || strcmp(tc, "no") == 0 ||
- strcmp(tc, "none") == 0) {
- SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::DoNotUseCompression);
- } else if (strcmp(tc, "arb") == 0) {
- SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseARBCompression);
- } else if (strcmp(tc, "dxt1") == 0) {
- SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseDXT1Compression);
- } else if (strcmp(tc, "dxt3") == 0) {
- SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseDXT3Compression);
- } else if (strcmp(tc, "dxt5") == 0) {
- SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseDXT5Compression);
- } else {
- SG_LOG(SG_VIEW, SG_WARN, "Unknown texture compression setting!");
- }
- }
-
-// create sky, but can't build until setupView, since we depend
-// on other subsystems to be inited, eg Ephemeris
- _sky = new SGSky;
-
- SGPath texture_path(globals->get_fg_root());
- texture_path.append("Textures");
- texture_path.append("Sky");
- for (int i = 0; i < FGEnvironmentMgr::MAX_CLOUD_LAYERS; i++) {
- SGCloudLayer * layer = new SGCloudLayer(texture_path.str());
- _sky->add_cloud_layer(layer);
- }
-
- _sky->texture_path( texture_path.str() );
-
- if (!_classicalRenderer) {
- eventHandler->setChangeStatsCameraRenderOrder( true );
- }
-}
-
-void installCullVisitor(Camera* camera)
-{
- osgViewer::Renderer* renderer
- = static_cast<osgViewer::Renderer*>(camera->getRenderer());
- for (int i = 0; i < 2; ++i) {
- osgUtil::SceneView* sceneView = renderer->getSceneView(i);
-#if SG_OSG_VERSION_LESS_THAN(3,0,0)
- sceneView->setCullVisitor(new simgear::EffectCullVisitor);
-#else
- osg::ref_ptr<osgUtil::CullVisitor::Identifier> identifier;
- identifier = sceneView->getCullVisitor()->getIdentifier();
- sceneView->setCullVisitor(new simgear::EffectCullVisitor);
- sceneView->getCullVisitor()->setIdentifier(identifier.get());
-
- identifier = sceneView->getCullVisitorLeft()->getIdentifier();
- sceneView->setCullVisitorLeft(sceneView->getCullVisitor()->clone());
- sceneView->getCullVisitorLeft()->setIdentifier(identifier.get());
-
- identifier = sceneView->getCullVisitorRight()->getIdentifier();
- sceneView->setCullVisitorRight(sceneView->getCullVisitor()->clone());
- sceneView->getCullVisitorRight()->setIdentifier(identifier.get());
-#endif
- }
-}
-
-flightgear::CameraInfo*
-FGRenderer::buildRenderingPipeline(flightgear::CameraGroup* cgroup, unsigned flags, Camera* camera,
- const Matrix& view,
- const Matrix& projection,
- osg::GraphicsContext* gc,
- bool useMasterSceneData)
-{
- flightgear::CameraInfo* info = 0;
- if (!_classicalRenderer && (flags & (CameraGroup::GUI | CameraGroup::ORTHO)) == 0)
- info = buildDeferredPipeline( cgroup, flags, camera, view, projection, gc );
-
- if (info) {
- return info;
- } else {
- if ((flags & (CameraGroup::GUI | CameraGroup::ORTHO)) == 0)
- _classicalRenderer = true;
- return buildClassicalPipeline( cgroup, flags, camera, view, projection, useMasterSceneData );
- }
-}
-
-flightgear::CameraInfo*
-FGRenderer::buildClassicalPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
- const osg::Matrix& view,
- const osg::Matrix& projection,
- bool useMasterSceneData)
-{
- CameraInfo* info = new CameraInfo(flags);
- // The camera group will always update the camera
- camera->setReferenceFrame(Transform::ABSOLUTE_RF);
-
- Camera* farCamera = 0;
- if ((flags & (CameraGroup::GUI | CameraGroup::ORTHO)) == 0) {
- farCamera = new Camera;
- farCamera->setAllowEventFocus(camera->getAllowEventFocus());
- farCamera->setGraphicsContext(camera->getGraphicsContext());
- farCamera->setCullingMode(camera->getCullingMode());
- farCamera->setInheritanceMask(camera->getInheritanceMask());
- farCamera->setReferenceFrame(Transform::ABSOLUTE_RF);
- // Each camera's viewport is written when the window is
- // resized; if the the viewport isn't copied here, it gets updated
- // twice and ends up with the wrong value.
- farCamera->setViewport(simgear::clone(camera->getViewport()));
- farCamera->setDrawBuffer(camera->getDrawBuffer());
- farCamera->setReadBuffer(camera->getReadBuffer());
- farCamera->setRenderTargetImplementation(
- camera->getRenderTargetImplementation());
- const Camera::BufferAttachmentMap& bufferMap
- = camera->getBufferAttachmentMap();
- if (bufferMap.count(Camera::COLOR_BUFFER) != 0) {
- farCamera->attach(
- Camera::COLOR_BUFFER,
- bufferMap.find(Camera::COLOR_BUFFER)->second._texture.get());
- }
- cgroup->getViewer()->addSlave(farCamera, projection, view, useMasterSceneData);
- installCullVisitor(farCamera);
- int farSlaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
- info->addCamera( FAR_CAMERA, farCamera, farSlaveIndex );
- farCamera->setRenderOrder(Camera::POST_RENDER, farSlaveIndex);
- camera->setCullMask(camera->getCullMask() & ~simgear::BACKGROUND_BIT);
- camera->setClearMask(GL_DEPTH_BUFFER_BIT);
- }
- cgroup->getViewer()->addSlave(camera, projection, view, useMasterSceneData);
- installCullVisitor(camera);
- int slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
- info->addCamera( MAIN_CAMERA, camera, slaveIndex );
- camera->setRenderOrder(Camera::POST_RENDER, slaveIndex);
- cgroup->addCamera(info);
- return info;
-}
-
-class FGDeferredRenderingCameraCullCallback : public osg::NodeCallback {
-public:
- FGDeferredRenderingCameraCullCallback( flightgear::CameraKind k, CameraInfo* i ) : kind( k ), info( i ) {}
- virtual void operator()( osg::Node *n, osg::NodeVisitor *nv) {
- simgear::EffectCullVisitor* cv = dynamic_cast<simgear::EffectCullVisitor*>(nv);
- osg::Camera* camera = static_cast<osg::Camera*>(n);
-
- cv->clearBufferList();
- cv->addBuffer(simgear::Effect::DEPTH_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::DEPTH_BUFFER ) );
- cv->addBuffer(simgear::Effect::NORMAL_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::NORMAL_BUFFER ) );
- cv->addBuffer(simgear::Effect::DIFFUSE_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::DIFFUSE_BUFFER ) );
- cv->addBuffer(simgear::Effect::SPEC_EMIS_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER ) );
- cv->addBuffer(simgear::Effect::LIGHTING_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::LIGHTING_BUFFER ) );
- cv->addBuffer(simgear::Effect::SHADOW_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::SHADOW_BUFFER ) );
- // cv->addBuffer(simgear::Effect::AO_BUFFER, info->gBuffer->aoBuffer[2]);
-
- if ( !info->getRenderStageInfo(kind).fullscreen )
- info->setMatrices( camera );
-
- cv->traverse( *camera );
-
- if ( kind == flightgear::GEOMETRY_CAMERA ) {
- // Save transparent bins to render later
- osgUtil::RenderStage* renderStage = cv->getRenderStage();
- osgUtil::RenderBin::RenderBinList& rbl = renderStage->getRenderBinList();
- for (osgUtil::RenderBin::RenderBinList::iterator rbi = rbl.begin(); rbi != rbl.end(); ) {
- if (rbi->second->getSortMode() == osgUtil::RenderBin::SORT_BACK_TO_FRONT) {
- info->savedTransparentBins.insert( std::make_pair( rbi->first, rbi->second ) );
- rbl.erase( rbi++ );
- } else {
- ++rbi;
- }
- }
- } else if ( kind == flightgear::LIGHTING_CAMERA ) {
- osg::ref_ptr<osg::Camera> mainShadowCamera = info->getCamera( SHADOW_CAMERA );
- if (mainShadowCamera.valid()) {
- osg::Group* grp = mainShadowCamera->getChild(0)->asGroup();
- for (int i = 0; i < 4; ++i ) {
- osg::TexGen* shadowTexGen = info->shadowTexGen[i];
- shadowTexGen->setMode(osg::TexGen::EYE_LINEAR);
-
- osg::Camera* cascadeCam = static_cast<osg::Camera*>( grp->getChild(i) );
- // compute the matrix which takes a vertex from view coords into tex coords
- shadowTexGen->setPlanesFromMatrix( cascadeCam->getProjectionMatrix() *
- osg::Matrix::translate(1.0,1.0,1.0) *
- osg::Matrix::scale(0.5f,0.5f,0.5f) );
-
- osg::RefMatrix * refMatrix = new osg::RefMatrix( cascadeCam->getInverseViewMatrix() * *cv->getModelViewMatrix() );
-
- cv->getRenderStage()->getPositionalStateContainer()->addPositionedTextureAttribute( i+1, refMatrix, shadowTexGen );
- }
- }
- // Render saved transparent render bins
- osgUtil::RenderStage* renderStage = cv->getRenderStage();
- osgUtil::RenderBin::RenderBinList& rbl = renderStage->getRenderBinList();
- for (osgUtil::RenderBin::RenderBinList::iterator rbi = info->savedTransparentBins.begin(); rbi != info->savedTransparentBins.end(); ++rbi ){
- rbl.insert( std::make_pair( rbi->first + 10000, rbi->second ) );
- }
- info->savedTransparentBins.clear();
- }
- }
-
-private:
- flightgear::CameraKind kind;
- CameraInfo* info;
-};
-
-osg::Texture2D* buildDeferredBuffer(GLint internalFormat, GLenum sourceFormat, GLenum sourceType, osg::Texture::WrapMode wrapMode, bool shadowComparison = false)
-{
- osg::Texture2D* tex = new osg::Texture2D;
- tex->setResizeNonPowerOfTwoHint( false );
- tex->setInternalFormat( internalFormat );
- tex->setShadowComparison(shadowComparison);
- if (shadowComparison) {
- tex->setShadowTextureMode(osg::Texture2D::LUMINANCE);
- tex->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
- }
- tex->setSourceFormat(sourceFormat);
- tex->setSourceType(sourceType);
- tex->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR );
- tex->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR );
- tex->setWrap( osg::Texture::WRAP_S, wrapMode );
- tex->setWrap( osg::Texture::WRAP_T, wrapMode );
- return tex;
-}
-
-void buildDeferredBuffers( flightgear::CameraInfo* info, int shadowMapSize, bool normal16 )
-{
- info->addBuffer(flightgear::RenderBufferInfo::DEPTH_BUFFER, buildDeferredBuffer( GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_FLOAT, osg::Texture::CLAMP_TO_BORDER) );
- if (false)
- info->addBuffer(flightgear::RenderBufferInfo::NORMAL_BUFFER, buildDeferredBuffer( 0x822C /*GL_RG16*/, 0x8227 /*GL_RG*/, GL_UNSIGNED_SHORT, osg::Texture::CLAMP_TO_BORDER) );
- else
- info->addBuffer(flightgear::RenderBufferInfo::NORMAL_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_SHORT, osg::Texture::CLAMP_TO_BORDER) );
-
- info->addBuffer(flightgear::RenderBufferInfo::DIFFUSE_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, osg::Texture::CLAMP_TO_BORDER) );
- info->addBuffer(flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, osg::Texture::CLAMP_TO_BORDER) );
- info->addBuffer(flightgear::RenderBufferInfo::LIGHTING_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, osg::Texture::CLAMP_TO_BORDER) );
- info->addBuffer(flightgear::RenderBufferInfo::SHADOW_BUFFER, buildDeferredBuffer( GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_FLOAT, osg::Texture::CLAMP_TO_BORDER, true), 0.0f );
- info->getBuffer(RenderBufferInfo::SHADOW_BUFFER)->setTextureSize(shadowMapSize,shadowMapSize);
-}
-
-void attachBufferToCamera( flightgear::CameraInfo* info, osg::Camera* camera, osg::Camera::BufferComponent c, flightgear::CameraKind ck, flightgear::RenderBufferInfo::Kind bk )
-{
- camera->attach( c, info->getBuffer(bk) );
- info->getRenderStageInfo(ck).buffers.insert( std::make_pair( c, bk ) );
-}
-
-osg::Camera* FGRenderer::buildDeferredGeometryCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc )
-{
- osg::Camera* camera = new osg::Camera;
- info->addCamera(flightgear::GEOMETRY_CAMERA, camera );
-
- camera->setCullMask( ~simgear::MODELLIGHT_BIT );
- camera->setName( "GeometryC" );
- camera->setGraphicsContext( gc );
- camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( flightgear::GEOMETRY_CAMERA, info ) );
- camera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
- camera->setClearColor( osg::Vec4( 0., 0., 0., 0. ) );
- camera->setClearDepth( 1.0 );
- camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
- camera->setViewport( new osg::Viewport );
- attachBufferToCamera( info, camera, osg::Camera::DEPTH_BUFFER, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::DEPTH_BUFFER );
- attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER0, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::NORMAL_BUFFER );
- attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER1, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::DIFFUSE_BUFFER );
- attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER2, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER );
- camera->setDrawBuffer(GL_FRONT);
- camera->setReadBuffer(GL_FRONT);
-
- camera->addChild( mDeferredRealRoot.get() );
-
- return camera;
-}
-
-static void setShadowCascadeStateSet( osg::Camera* cam ) {
- osg::StateSet* ss = cam->getOrCreateStateSet();
- ss->setAttribute( new osg::PolygonOffset( 1.1f, 5.0f ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
- ss->setMode( GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
- ss->setRenderBinDetails( 0, "RenderBin", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS );
- ss->setAttributeAndModes( new osg::AlphaFunc( osg::AlphaFunc::GREATER, 0.05 ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
- ss->setAttributeAndModes( new osg::ColorMask( false, false, false, false ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
- ss->setAttributeAndModes( new osg::CullFace( osg::CullFace::FRONT ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
- osg::Program* program = new osg::Program;
- ss->setAttribute( program, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON );
- ss->setMode( GL_LIGHTING, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
- ss->setMode( GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
- //ss->setTextureMode( 0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON );
- ss->setTextureMode( 0, GL_TEXTURE_3D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
- ss->setTextureMode( 1, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
- ss->setTextureMode( 1, GL_TEXTURE_3D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
- ss->setTextureMode( 2, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
- ss->setTextureMode( 2, GL_TEXTURE_3D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
-}
-
-static osg::Camera* createShadowCascadeCamera( int no, int cascadeSize ) {
- osg::Camera* cascadeCam = new osg::Camera;
- setShadowCascadeStateSet( cascadeCam );
-
- std::ostringstream oss;
- oss << "CascadeCamera" << (no + 1);
- cascadeCam->setName( oss.str() );
- cascadeCam->setClearMask(0);
- cascadeCam->setCullMask(~( simgear::MODELLIGHT_BIT /* | simgear::NO_SHADOW_BIT */ ) );
- cascadeCam->setCullingMode( cascadeCam->getCullingMode() & ~osg::CullSettings::SMALL_FEATURE_CULLING );
- cascadeCam->setAllowEventFocus(false);
- cascadeCam->setReferenceFrame(osg::Transform::ABSOLUTE_RF_INHERIT_VIEWPOINT);
- cascadeCam->setRenderOrder(osg::Camera::NESTED_RENDER);
- cascadeCam->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
- cascadeCam->setViewport( int( no / 2 ) * cascadeSize, (no & 1) * cascadeSize, cascadeSize, cascadeSize );
- return cascadeCam;
-}
-
-osg::Camera* FGRenderer::buildDeferredShadowCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc )
-{
- osg::Camera* mainShadowCamera = new osg::Camera;
- info->addCamera(flightgear::SHADOW_CAMERA, mainShadowCamera, 0.0f );
-
- mainShadowCamera->setName( "ShadowC" );
- mainShadowCamera->setClearMask( GL_DEPTH_BUFFER_BIT );
- mainShadowCamera->setClearDepth( 1.0 );
- mainShadowCamera->setAllowEventFocus(false);
- mainShadowCamera->setGraphicsContext(gc);
- mainShadowCamera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
- attachBufferToCamera( info, mainShadowCamera, osg::Camera::DEPTH_BUFFER, flightgear::SHADOW_CAMERA, flightgear::RenderBufferInfo::SHADOW_BUFFER );
- mainShadowCamera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
- mainShadowCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
- mainShadowCamera->setProjectionMatrix(osg::Matrix::identity());
- mainShadowCamera->setCullingMode( osg::CullSettings::NO_CULLING );
- mainShadowCamera->setViewport( 0, 0, _shadowMapSize, _shadowMapSize );
- mainShadowCamera->setDrawBuffer(GL_FRONT);
- mainShadowCamera->setReadBuffer(GL_FRONT);
-
- osg::Switch* shadowSwitch = new osg::Switch;
- mainShadowCamera->addChild( shadowSwitch );
-
- for (int i = 0; i < 4; ++i ) {
- osg::Camera* cascadeCam = createShadowCascadeCamera( i, _shadowMapSize/2 );
- cascadeCam->addChild( mDeferredRealRoot.get() );
- shadowSwitch->addChild( cascadeCam );
- info->shadowTexGen[i] = new osg::TexGen;
- }
- if (fgGetBool("/sim/rendering/shadows/enabled", true))
- shadowSwitch->setAllChildrenOn();
- else
- shadowSwitch->setAllChildrenOff();
-
- return mainShadowCamera;
-}
-
-void FGRenderer::updateShadowCascade(const CameraInfo* info, osg::Camera* camera, osg::Group* grp, int idx, double left, double right, double bottom, double top, double zNear, double f1, double f2)
-{
- osg::Camera* cascade = static_cast<osg::Camera*>( grp->getChild(idx) );
- osg::Matrixd &viewMatrix = cascade->getViewMatrix();
- osg::Matrixd &projectionMatrix = cascade->getProjectionMatrix();
-
- osg::BoundingSphere bs;
- bs.expandBy(osg::Vec3(left,bottom,-zNear) * f1);
- bs.expandBy(osg::Vec3(right,top,-zNear) * f2);
- bs.expandBy(osg::Vec3(left,bottom,-zNear) * f2);
- bs.expandBy(osg::Vec3(right,top,-zNear) * f1);
-
- osg::Vec4 aim = osg::Vec4(bs.center(), 1.0) * camera->getInverseViewMatrix();
-
- projectionMatrix.makeOrtho( -bs.radius(), bs.radius(), -bs.radius(), bs.radius(), 1., 15000.0 );
- osg::Vec3 position( aim.x(), aim.y(), aim.z() );
- viewMatrix.makeLookAt( position + (getSunDirection() * 10000.0), position, position );
-}
-
-osg::Vec3 FGRenderer::getSunDirection() const
-{
- osg::Vec3 val;
- _sunDirection->get( val );
- return val;
-}
-
-void FGRenderer::updateShadowCamera(const flightgear::CameraInfo* info, const osg::Vec3d& position)
-{
- ref_ptr<Camera> mainShadowCamera = info->getCamera( SHADOW_CAMERA );
- if (mainShadowCamera.valid()) {
- ref_ptr<Switch> shadowSwitch = mainShadowCamera->getChild( 0 )->asSwitch();
- osg::Vec3d up = position,
- dir = getSunDirection();
- up.normalize();
- dir.normalize();
- // cos(100 deg) == -0.17
- if (up * dir < -0.17 || !fgGetBool("/sim/rendering/shadows/enabled", true)) {
- shadowSwitch->setAllChildrenOff();
- } else {
- double left,right,bottom,top,zNear,zFar;
- ref_ptr<Camera> camera = info->getCamera(GEOMETRY_CAMERA);
- camera->getProjectionMatrix().getFrustum(left,right,bottom,top,zNear,zFar);
-
- shadowSwitch->setAllChildrenOn();
- if (_numCascades == 1) {
- osg::Camera* cascadeCam = static_cast<osg::Camera*>( shadowSwitch->getChild(0) );
- cascadeCam->setViewport( 0, 0, _shadowMapSize, _shadowMapSize );
- } else {
- for (int no = 0; no < 4; ++no) {
- osg::Camera* cascadeCam = static_cast<osg::Camera*>( shadowSwitch->getChild(no) );
- cascadeCam->setViewport( int( no / 2 ) * (_shadowMapSize/2), (no & 1) * (_shadowMapSize/2), (_shadowMapSize/2), (_shadowMapSize/2) );
- }
- }
- updateShadowCascade(info, camera, shadowSwitch, 0, left, right, bottom, top, zNear, 1.0, _cascadeFar[0]/zNear);
- if (_numCascades > 1) {
- shadowSwitch->setValue(1, true);
- updateShadowCascade(info, camera, shadowSwitch, 1, left, right, bottom, top, zNear, _cascadeFar[0]/zNear, _cascadeFar[1]/zNear);
- } else {
- shadowSwitch->setValue(1, false);
- }
- if (_numCascades > 2) {
- shadowSwitch->setValue(2, true);
- updateShadowCascade(info, camera, shadowSwitch, 2, left, right, bottom, top, zNear, _cascadeFar[1]/zNear, _cascadeFar[2]/zNear);
- } else {
- shadowSwitch->setValue(2, false);
- }
- if (_numCascades > 3) {
- shadowSwitch->setValue(3, true);
- updateShadowCascade(info, camera, shadowSwitch, 3, left, right, bottom, top, zNear, _cascadeFar[2]/zNear, _cascadeFar[3]/zNear);
- } else {
- shadowSwitch->setValue(3, false);
- }
- {
- osg::Matrixd &viewMatrix = mainShadowCamera->getViewMatrix();
-
- osg::Vec4 aim = osg::Vec4( 0.0, 0.0, 0.0, 1.0 ) * camera->getInverseViewMatrix();
-
- osg::Vec3 position( aim.x(), aim.y(), aim.z() );
- viewMatrix.makeLookAt( position, position + (getSunDirection() * 10000.0), position );
- }
- }
- }
-}
-
-void FGRenderer::updateShadowMapSize(int mapSize)
-{
- if ( ((~( mapSize-1 )) & mapSize) != mapSize ) {
- SG_LOG( SG_VIEW, SG_ALERT, "Map size is not a power of two" );
- return;
- }
- for ( CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
- ii != CameraGroup::getDefault()->camerasEnd();
- ++ii )
- {
- CameraInfo* info = ii->get();
- Camera* camera = info->getCamera(SHADOW_CAMERA);
- if (camera == 0) continue;
-
- Texture2D* tex = info->getBuffer(RenderBufferInfo::SHADOW_BUFFER);
- if (tex == 0) continue;
-
- tex->setTextureSize( mapSize, mapSize );
- tex->dirtyTextureObject();
-
- Viewport* vp = camera->getViewport();
- vp->width() = mapSize;
- vp->height() = mapSize;
-
- osgViewer::Renderer* renderer
- = static_cast<osgViewer::Renderer*>(camera->getRenderer());
- for (int i = 0; i < 2; ++i) {
- osgUtil::SceneView* sceneView = renderer->getSceneView(i);
- sceneView->getRenderStage()->setFrameBufferObject(0);
- sceneView->getRenderStage()->setCameraRequiresSetUp(true);
- if (sceneView->getRenderStageLeft()) {
- sceneView->getRenderStageLeft()->setFrameBufferObject(0);
- sceneView->getRenderStageLeft()->setCameraRequiresSetUp(true);
- }
- if (sceneView->getRenderStageRight()) {
- sceneView->getRenderStageRight()->setFrameBufferObject(0);
- sceneView->getRenderStageRight()->setCameraRequiresSetUp(true);
- }
- }
-
- int cascadeSize = mapSize / 2;
- Group* grp = camera->getChild(0)->asGroup();
- for (int i = 0; i < 4; ++i ) {
- Camera* cascadeCam = static_cast<Camera*>( grp->getChild(i) );
- cascadeCam->setViewport( int( i / 2 ) * cascadeSize, (i & 1) * cascadeSize, cascadeSize, cascadeSize );
- }
-
- _shadowMapSize = mapSize;
- }
-}
-
-void FGRenderer::enableShadows(bool enabled)
-{
- for ( CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
- ii != CameraGroup::getDefault()->camerasEnd();
- ++ii )
- {
- CameraInfo* info = ii->get();
- Camera* camera = info->getCamera(SHADOW_CAMERA);
- if (camera == 0) continue;
-
- osg::Switch* shadowSwitch = camera->getChild(0)->asSwitch();
- if (enabled)
- shadowSwitch->setAllChildrenOn();
- else
- shadowSwitch->setAllChildrenOff();
- }
-}
-
-void FGRenderer::updateCascadeFar(int index, float far_m)
-{
- if (index < 0 || index > 3)
- return;
- _cascadeFar[index] = far_m;
- _shadowDistances->set( osg::Vec4f(_cascadeFar[0], _cascadeFar[1], _cascadeFar[2], _cascadeFar[3]) );
-}
-
-void FGRenderer::updateCascadeNumber(size_t num)
-{
- if (num < 1 || num > 4)
- return;
- _numCascades = num;
- _shadowNumber->set( (int)_numCascades );
-}
-
-
-#define STRINGIFY(x) #x
-#define TOSTRING(x) STRINGIFY(x)
-
-const char *ambient_vert_src = ""
- "#line " TOSTRING(__LINE__) " 1\n"
- "void main() {\n"
- " gl_Position = gl_Vertex;\n"
- " gl_TexCoord[0] = gl_MultiTexCoord0;\n"
- "}\n";
-
-const char *ambient_frag_src = ""
- "#line " TOSTRING(__LINE__) " 1\n"
- "uniform sampler2D color_tex;\n"
-// "uniform sampler2D ao_tex;\n"
- "uniform sampler2D normal_tex;\n"
- "uniform sampler2D spec_emis_tex;\n"
- "uniform vec4 fg_SunAmbientColor;\n"
- "void main() {\n"
- " vec2 coords = gl_TexCoord[0].xy;\n"
- " float initialized = texture2D( spec_emis_tex, coords ).a;\n"
- " if ( initialized < 0.1 )\n"
- " discard;\n"
- " vec3 tcolor = texture2D( color_tex, coords ).rgb;\n"
-// " float ao = texture2D( ao_tex, coords ).r;\n"
-// " gl_FragColor = vec4(tcolor*fg_SunAmbientColor.rgb*ao, 1.0);\n"
- " gl_FragColor = vec4(tcolor*fg_SunAmbientColor.rgb, 1.0);\n"
- "}\n";
-
-const char *sunlight_vert_src = ""
- "#line " TOSTRING(__LINE__) " 1\n"
-// "uniform mat4 fg_ViewMatrixInverse;\n"
- "uniform mat4 fg_ProjectionMatrixInverse;\n"
- "varying vec3 ray;\n"
- "void main() {\n"
- " gl_Position = gl_Vertex;\n"
- " gl_TexCoord[0] = gl_MultiTexCoord0;\n"
-// " ray = (fg_ViewMatrixInverse * vec4((fg_ProjectionMatrixInverse * gl_Vertex).xyz, 0.0)).xyz;\n"
- " ray = (fg_ProjectionMatrixInverse * gl_Vertex).xyz;\n"
- "}\n";
-
-const char *sunlight_frag_src = ""
-#if 0
- "#version 130\n"
-#endif
- "#line " TOSTRING(__LINE__) " 1\n"
- "uniform mat4 fg_ViewMatrix;\n"
- "uniform sampler2D depth_tex;\n"
- "uniform sampler2D normal_tex;\n"
- "uniform sampler2D color_tex;\n"
- "uniform sampler2D spec_emis_tex;\n"
- "uniform sampler2DShadow shadow_tex;\n"
- "uniform vec4 fg_SunDiffuseColor;\n"
- "uniform vec4 fg_SunSpecularColor;\n"
- "uniform vec3 fg_SunDirection;\n"
- "uniform vec3 fg_Planes;\n"
- "varying vec3 ray;\n"
- "vec4 DynamicShadow( in vec4 ecPosition, out vec4 tint )\n"
- "{\n"
- " vec4 coords;\n"
- " vec2 shift = vec2( 0.0 );\n"
- " int index = 4;\n"
- " if (ecPosition.z > -5.0) {\n"
- " index = 1;\n"
- " tint = vec4(0.0,1.0,0.0,1.0);\n"
- " } else if (ecPosition.z > -50.0) {\n"
- " index = 2;\n"
- " shift = vec2( 0.0, 0.5 );\n"
- " tint = vec4(0.0,0.0,1.0,1.0);\n"
- " } else if (ecPosition.z > -512.0) {\n"
- " index = 3;\n"
- " shift = vec2( 0.5, 0.0 );\n"
- " tint = vec4(1.0,1.0,0.0,1.0);\n"
- " } else if (ecPosition.z > -10000.0) {\n"
- " shift = vec2( 0.5, 0.5 );\n"
- " tint = vec4(1.0,0.0,0.0,1.0);\n"
- " } else {\n"
- " return vec4(1.1,1.1,0.0,1.0);\n" // outside, clamp to border
- " }\n"
- " coords.s = dot( ecPosition, gl_EyePlaneS[index] );\n"
- " coords.t = dot( ecPosition, gl_EyePlaneT[index] );\n"
- " coords.p = dot( ecPosition, gl_EyePlaneR[index] );\n"
- " coords.q = dot( ecPosition, gl_EyePlaneQ[index] );\n"
- " coords.st *= .5;\n"
- " coords.st += shift;\n"
- " return coords;\n"
- "}\n"
- "void main() {\n"
- " vec2 coords = gl_TexCoord[0].xy;\n"
- " vec4 spec_emis = texture2D( spec_emis_tex, coords );\n"
- " if ( spec_emis.a < 0.1 )\n"
- " discard;\n"
- " vec3 normal;\n"
- " normal.xy = texture2D( normal_tex, coords ).rg * 2.0 - vec2(1.0,1.0);\n"
- " normal.z = sqrt( 1.0 - dot( normal.xy, normal.xy ) );\n"
- " float len = length(normal);\n"
- " normal /= len;\n"
- " vec3 viewDir = normalize(ray);\n"
- " float depth = texture2D( depth_tex, coords ).r;\n"
- " vec3 pos;\n"
- " pos.z = - fg_Planes.y / (fg_Planes.x + depth * fg_Planes.z);\n"
- " pos.xy = viewDir.xy / viewDir.z * pos.z;\n"
-
- " vec4 tint;\n"
-#if 0
- " float shadow = 1.0;\n"
-#elif 1
- " float shadow = shadow2DProj( shadow_tex, DynamicShadow( vec4( pos, 1.0 ), tint ) ).r;\n"
-#else
- " float kernel[9] = float[]( 36/256.0, 24/256.0, 6/256.0,\n"
- " 24/256.0, 16/256.0, 4/256.0,\n"
- " 6/256.0, 4/256.0, 1/256.0 );\n"
- " float shadow = 0;\n"
- " for( int x = -2; x <= 2; ++x )\n"
- " for( int y = -2; y <= 2; ++y )\n"
- " shadow += kernel[abs(x)*3 + abs(y)] * shadow2DProj( shadow_tex, DynamicShadow( vec4(pos + vec3(0.05 * x, 0.05 * y, 0), 1.0), tint ) ).r;\n"
-#endif
- " vec3 lightDir = (fg_ViewMatrix * vec4( fg_SunDirection, 0.0 )).xyz;\n"
- " lightDir = normalize( lightDir );\n"
- " vec3 color = texture2D( color_tex, coords ).rgb;\n"
- " vec3 Idiff = clamp( dot( lightDir, normal ), 0.0, 1.0 ) * color * fg_SunDiffuseColor.rgb;\n"
- " vec3 halfDir = lightDir - viewDir;\n"
- " len = length( halfDir );\n"
- " vec3 Ispec = vec3(0.0);\n"
- " vec3 Iemis = spec_emis.z * color;\n"
- " if (len > 0.0001) {\n"
- " halfDir /= len;\n"
- " Ispec = pow( clamp( dot( halfDir, normal ), 0.0, 1.0 ), spec_emis.y * 255.0 ) * spec_emis.x * fg_SunSpecularColor.rgb;\n"
- " }\n"
- " gl_FragColor = vec4(mix(vec3(0.0), Idiff + Ispec, shadow) + Iemis, 1.0);\n"
-// " gl_FragColor = mix(tint, vec4(mix(vec3(0.0), Idiff + Ispec, shadow) + Iemis, 1.0), 0.92);\n"
- "}\n";
-
-const char *fog_vert_src = ""
- "#line " TOSTRING(__LINE__) " 1\n"
- "uniform mat4 fg_ProjectionMatrixInverse;\n"
- "varying vec3 ray;\n"
- "void main() {\n"
- " gl_Position = gl_Vertex;\n"
- " gl_TexCoord[0] = gl_MultiTexCoord0;\n"
- " ray = (fg_ProjectionMatrixInverse * gl_Vertex).xyz;\n"
- "}\n";
-
-const char *fog_frag_src = ""
- "#line " TOSTRING(__LINE__) " 1\n"
- "uniform sampler2D depth_tex;\n"
- "uniform sampler2D normal_tex;\n"
- "uniform sampler2D color_tex;\n"
- "uniform sampler2D spec_emis_tex;\n"
- "uniform vec4 fg_FogColor;\n"
- "uniform float fg_FogDensity;\n"
- "uniform vec3 fg_Planes;\n"
- "varying vec3 ray;\n"
- "void main() {\n"
- " vec2 coords = gl_TexCoord[0].xy;\n"
- " float initialized = texture2D( spec_emis_tex, coords ).a;\n"
- " if ( initialized < 0.1 )\n"
- " discard;\n"
- " vec3 normal;\n"
- " normal.xy = texture2D( normal_tex, coords ).rg * 2.0 - vec2(1.0,1.0);\n"
- " normal.z = sqrt( 1.0 - dot( normal.xy, normal.xy ) );\n"
- " float len = length(normal);\n"
- " normal /= len;\n"
- " vec3 viewDir = normalize(ray);\n"
- " float depth = texture2D( depth_tex, coords ).r;\n"
- " vec3 pos;\n"
- " pos.z = - fg_Planes.y / (fg_Planes.x + depth * fg_Planes.z);\n"
- " pos.xy = viewDir.xy / viewDir.z * pos.z;\n"
-
- " float fogFactor = 0.0;\n"
- " const float LOG2 = 1.442695;\n"
- " fogFactor = exp2(-fg_FogDensity * fg_FogDensity * pos.z * pos.z * LOG2);\n"
- " fogFactor = clamp(fogFactor, 0.0, 1.0);\n"
-
- " gl_FragColor = vec4(fg_FogColor.rgb, 1.0 - fogFactor);\n"
- "}\n";
-
-osg::Camera* FGRenderer::buildDeferredLightingCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc )
-{
- osg::Camera* camera = new osg::Camera;
- info->addCamera(flightgear::LIGHTING_CAMERA, camera );
-
- camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( flightgear::LIGHTING_CAMERA, info ) );
- camera->setAllowEventFocus(false);
- camera->setGraphicsContext(gc);
- camera->setViewport(new Viewport);
- camera->setName("LightingC");
- camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
- camera->setRenderOrder(osg::Camera::POST_RENDER, 50);
- camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
- camera->setViewport( new osg::Viewport );
- attachBufferToCamera( info, camera, osg::Camera::DEPTH_BUFFER, flightgear::LIGHTING_CAMERA, flightgear::RenderBufferInfo::DEPTH_BUFFER );
- attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER, flightgear::LIGHTING_CAMERA, flightgear::RenderBufferInfo::LIGHTING_BUFFER );
- camera->setDrawBuffer(GL_FRONT);
- camera->setReadBuffer(GL_FRONT);
- camera->setClearColor( osg::Vec4( 0., 0., 0., 1. ) );
- camera->setClearMask( GL_COLOR_BUFFER_BIT );
- osg::StateSet* ss = camera->getOrCreateStateSet();
- ss->setAttribute( new osg::Depth(osg::Depth::LESS, 0.0, 1.0, false) );
-
- osg::Group* lightingGroup = new osg::Group;
-
- osg::Camera* quadCam1 = new osg::Camera;
- quadCam1->setName( "QuadCamera1" );
- quadCam1->setClearMask(0);
- quadCam1->setAllowEventFocus(false);
- quadCam1->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
- quadCam1->setRenderOrder(osg::Camera::NESTED_RENDER);
- quadCam1->setViewMatrix(osg::Matrix::identity());
- quadCam1->setProjectionMatrixAsOrtho2D(-1,1,-1,1);
- quadCam1->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
- ss = quadCam1->getOrCreateStateSet();
- ss->addUniform( _ambientFactor );
- ss->addUniform( info->projInverse );
- ss->addUniform( info->viewInverse );
- ss->addUniform( info->view );
- ss->addUniform( _sunDiffuse );
- ss->addUniform( _sunSpecular );
- ss->addUniform( _sunDirection );
- ss->addUniform( _planes );
- ss->addUniform( _shadowNumber );
- ss->addUniform( _shadowDistances );
-
- osg::Geometry* g = osg::createTexturedQuadGeometry( osg::Vec3(-1.,-1.,0.), osg::Vec3(2.,0.,0.), osg::Vec3(0.,2.,0.) );
- g->setUseDisplayList(false);
- simgear::EffectGeode* eg = new simgear::EffectGeode;
- simgear::Effect* effect = simgear::makeEffect("Effects/ambient", true);
- if (effect) {
- eg->setEffect( effect );
- } else {
- SG_LOG( SG_VIEW, SG_ALERT, "=> Using default, builtin, Effects/ambient" );
- ss = eg->getOrCreateStateSet();
- ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
- ss->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
- ss->setTextureAttributeAndModes( 0, info->getBuffer( flightgear::RenderBufferInfo::DEPTH_BUFFER ) );
- ss->setTextureAttributeAndModes( 1, info->getBuffer( flightgear::RenderBufferInfo::NORMAL_BUFFER ) );
- ss->setTextureAttributeAndModes( 2, info->getBuffer( flightgear::RenderBufferInfo::DIFFUSE_BUFFER ) );
- ss->setTextureAttributeAndModes( 3, info->getBuffer( flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER ) );
- //ss->setTextureAttributeAndModes( 4, info->gBuffer->aoBuffer[2] );
- ss->addUniform( new osg::Uniform( "depth_tex", 0 ) );
- ss->addUniform( new osg::Uniform( "normal_tex", 1 ) );
- ss->addUniform( new osg::Uniform( "color_tex", 2 ) );
- ss->addUniform( new osg::Uniform( "spec_emis_tex", 3 ) );
- //ss->addUniform( new osg::Uniform( "ao_tex", 4 ) );
- ss->setRenderBinDetails( 0, "RenderBin" );
- osg::Program* program = new osg::Program;
- program->addShader( new osg::Shader( osg::Shader::VERTEX, ambient_vert_src ) );
- program->addShader( new osg::Shader( osg::Shader::FRAGMENT, ambient_frag_src ) );
- ss->setAttributeAndModes( program );
- }
-
- g->setName( "AmbientQuad" );
- eg->setName("AmbientQuad");
- eg->setCullingActive(false);
- eg->addDrawable(g);
- quadCam1->addChild( eg );
-
- g = osg::createTexturedQuadGeometry( osg::Vec3(-1.,-1.,0.), osg::Vec3(2.,0.,0.), osg::Vec3(0.,2.,0.) );
- g->setUseDisplayList(false);
- g->setName( "SunlightQuad" );
- eg = new simgear::EffectGeode;
- effect = simgear::makeEffect("Effects/sunlight", true);
- if (effect) {
- eg->setEffect( effect );
- } else {
- SG_LOG( SG_VIEW, SG_ALERT, "=> Using default, builtin, Effects/sunlight" );
- ss = eg->getOrCreateStateSet();
- ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
- ss->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
- ss->setAttributeAndModes( new osg::BlendFunc( osg::BlendFunc::ONE, osg::BlendFunc::ONE ) );
- ss->setTextureAttribute( 0, info->getBuffer( flightgear::RenderBufferInfo::DEPTH_BUFFER ) );
- ss->setTextureAttribute( 1, info->getBuffer( flightgear::RenderBufferInfo::NORMAL_BUFFER ) );
- ss->setTextureAttribute( 2, info->getBuffer( flightgear::RenderBufferInfo::DIFFUSE_BUFFER ) );
- ss->setTextureAttribute( 3, info->getBuffer( flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER ) );
- ss->setTextureAttribute( 4, info->getBuffer( flightgear::RenderBufferInfo::SHADOW_BUFFER ) );
- ss->addUniform( new osg::Uniform( "depth_tex", 0 ) );
- ss->addUniform( new osg::Uniform( "normal_tex", 1 ) );
- ss->addUniform( new osg::Uniform( "color_tex", 2 ) );
- ss->addUniform( new osg::Uniform( "spec_emis_tex", 3 ) );
- ss->addUniform( new osg::Uniform( "shadow_tex", 4 ) );
- ss->setRenderBinDetails( 1, "RenderBin" );
- osg::Program* program = new osg::Program;
- program->addShader( new osg::Shader( osg::Shader::VERTEX, sunlight_vert_src ) );
- program->addShader( new osg::Shader( osg::Shader::FRAGMENT, sunlight_frag_src ) );
- ss->setAttributeAndModes( program );
- }
- eg->setName("SunlightQuad");
- eg->setCullingActive(false);
- eg->addDrawable(g);
- quadCam1->addChild( eg );
-
- osg::Camera* lightCam = new osg::Camera;
- ss = lightCam->getOrCreateStateSet();
- ss->addUniform( _planes );
- ss->addUniform( info->bufferSize );
- lightCam->setName( "LightCamera" );
- lightCam->setClearMask(0);
- lightCam->setAllowEventFocus(false);
- lightCam->setReferenceFrame(osg::Transform::RELATIVE_RF);
- lightCam->setRenderOrder(osg::Camera::NESTED_RENDER,1);
- lightCam->setViewMatrix(osg::Matrix::identity());
- lightCam->setProjectionMatrix(osg::Matrix::identity());
- lightCam->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
- lightCam->setCullMask( simgear::MODELLIGHT_BIT );
- lightCam->setInheritanceMask( osg::CullSettings::ALL_VARIABLES & ~osg::CullSettings::CULL_MASK );
- lightCam->addChild( mDeferredRealRoot.get() );
-
-
- osg::Camera* quadCam2 = new osg::Camera;
- quadCam2->setName( "QuadCamera1" );
- quadCam2->setClearMask(0);
- quadCam2->setAllowEventFocus(false);
- quadCam2->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
- quadCam2->setRenderOrder(osg::Camera::NESTED_RENDER,2);
- quadCam2->setViewMatrix(osg::Matrix::identity());
- quadCam2->setProjectionMatrixAsOrtho2D(-1,1,-1,1);
- quadCam2->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
- ss = quadCam2->getOrCreateStateSet();
- ss->addUniform( _ambientFactor );
- ss->addUniform( info->projInverse );
- ss->addUniform( info->viewInverse );
- ss->addUniform( info->view );
- ss->addUniform( _sunDiffuse );
- ss->addUniform( _sunSpecular );
- ss->addUniform( _sunDirection );
- ss->addUniform( _fogColor );
- ss->addUniform( _fogDensity );
- ss->addUniform( _planes );
-
- g = osg::createTexturedQuadGeometry( osg::Vec3(-1.,-1.,0.), osg::Vec3(2.,0.,0.), osg::Vec3(0.,2.,0.) );
- g->setUseDisplayList(false);
- g->setName( "FogQuad" );
- eg = new simgear::EffectGeode;
- effect = simgear::makeEffect("Effects/fog", true);
- if (effect) {
- eg->setEffect( effect );
- } else {
- SG_LOG( SG_VIEW, SG_ALERT, "=> Using default, builtin, Effects/fog" );
- ss = eg->getOrCreateStateSet();
- ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
- ss->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
- ss->setAttributeAndModes( new osg::BlendFunc( osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA ) );
- ss->setTextureAttributeAndModes( 0, info->getBuffer( flightgear::RenderBufferInfo::DEPTH_BUFFER ) );
- ss->setTextureAttributeAndModes( 1, info->getBuffer( flightgear::RenderBufferInfo::NORMAL_BUFFER ) );
- ss->setTextureAttributeAndModes( 2, info->getBuffer( flightgear::RenderBufferInfo::DIFFUSE_BUFFER ) );
- ss->setTextureAttributeAndModes( 3, info->getBuffer( flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER ) );
- ss->addUniform( new osg::Uniform( "depth_tex", 0 ) );
- ss->addUniform( new osg::Uniform( "normal_tex", 1 ) );
- ss->addUniform( new osg::Uniform( "color_tex", 2 ) );
- ss->addUniform( new osg::Uniform( "spec_emis_tex", 3 ) );
- ss->setRenderBinDetails( 10000, "RenderBin" );
- osg::Program* program = new osg::Program;
- program->addShader( new osg::Shader( osg::Shader::VERTEX, fog_vert_src ) );
- program->addShader( new osg::Shader( osg::Shader::FRAGMENT, fog_frag_src ) );
- ss->setAttributeAndModes( program );
- }
- eg->setName("FogQuad");
- eg->setCullingActive(false);
- eg->addDrawable(g);
- quadCam2->addChild( eg );
-
- lightingGroup->addChild( _sky->getPreRoot() );
- lightingGroup->addChild( _sky->getCloudRoot() );
- lightingGroup->addChild( quadCam1 );
- lightingGroup->addChild( lightCam );
- lightingGroup->addChild( quadCam2 );
-
- camera->addChild( lightingGroup );
-
- return camera;
-}
-
-flightgear::CameraInfo*
-FGRenderer::buildDeferredPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
- const osg::Matrix& view,
- const osg::Matrix& projection,
- osg::GraphicsContext* gc)
-{
- CameraInfo* info = new CameraInfo(flags);
- buildDeferredBuffers( info, _shadowMapSize, !fgGetBool("/sim/rendering/no-16bit-buffer", false ) );
-
- osg::Camera* geometryCamera = buildDeferredGeometryCamera( info, gc );
- cgroup->getViewer()->addSlave(geometryCamera, false);
- installCullVisitor(geometryCamera);
- int slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
- info->getRenderStageInfo(GEOMETRY_CAMERA).slaveIndex = slaveIndex;
-
- Camera* shadowCamera = buildDeferredShadowCamera( info, gc );
- cgroup->getViewer()->addSlave(shadowCamera, false);
- installCullVisitor(shadowCamera);
- slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
- info->getRenderStageInfo(SHADOW_CAMERA).slaveIndex = slaveIndex;
-
- osg::Camera* lightingCamera = buildDeferredLightingCamera( info, gc );
- cgroup->getViewer()->addSlave(lightingCamera, false);
- installCullVisitor(lightingCamera);
- slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
- info->getRenderStageInfo(LIGHTING_CAMERA).slaveIndex = slaveIndex;
-
- camera->setName( "DisplayC" );
- camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( flightgear::DISPLAY_CAMERA, info ) );
- camera->setReferenceFrame(Transform::ABSOLUTE_RF);
- camera->setAllowEventFocus(false);
- osg::Geometry* g = osg::createTexturedQuadGeometry( osg::Vec3(-1.,-1.,0.), osg::Vec3(2.,0.,0.), osg::Vec3(0.,2.,0.) );
- g->setUseDisplayList(false); //DEBUG
- simgear::EffectGeode* eg = new simgear::EffectGeode;
- simgear::Effect* effect = simgear::makeEffect("Effects/display", true);
- if (!effect) {
- SG_LOG(SG_VIEW, SG_ALERT, "Effects/display not found");
- return 0;
- }
- eg->setEffect(effect);
- eg->setCullingActive(false);
- eg->addDrawable(g);
- camera->setViewMatrix(osg::Matrix::identity());
- camera->setProjectionMatrixAsOrtho2D(-1,1,-1,1);
- camera->addChild(eg);
-
- cgroup->getViewer()->addSlave(camera, false);
- installCullVisitor(camera);
- slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
- info->addCamera( DISPLAY_CAMERA, camera, slaveIndex, true );
- camera->setRenderOrder(Camera::POST_RENDER, 99+slaveIndex); //FIXME
- cgroup->addCamera(info);
- return info;
-}
-
-
-void
-FGRenderer::setupView( void )
-{
- osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
- osg::initNotifyLevel();
-
- // The number of polygon-offset "units" to place between layers. In
- // principle, one is supposed to be enough. In practice, I find that
- // my hardware/driver requires many more.
- osg::PolygonOffset::setUnitsMultiplier(1);
- osg::PolygonOffset::setFactorMultiplier(1);
-
- // Go full screen if requested ...
- if ( fgGetBool("/sim/startup/fullscreen") )
- fgOSFullScreen();
-
-// build the sky
- // The sun and moon diameters are scaled down numbers of the
- // actual diameters. This was needed to fit both the sun and the
- // moon within the distance to the far clip plane.
- // Moon diameter: 3,476 kilometers
- // Sun diameter: 1,390,000 kilometers
- _sky->build( 80000.0, 80000.0,
- 463.3, 361.8,
- *globals->get_ephem(),
- fgGetNode("/environment", true));
-
- viewer->getCamera()
- ->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
-
- osg::StateSet* stateSet = mRoot->getOrCreateStateSet();
-
- stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
-
- stateSet->setAttribute(new osg::Depth(osg::Depth::LESS));
- stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
-
- stateSet->setAttribute(new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01));
- stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
- stateSet->setAttribute(new osg::BlendFunc);
- stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
-
- stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
-
- // this will be set below
- stateSet->setMode(GL_NORMALIZE, osg::StateAttribute::OFF);
-
- osg::Material* material = new osg::Material;
- stateSet->setAttribute(material);
-
- stateSet->setTextureAttribute(0, new osg::TexEnv);
- stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF);
-
- osg::Hint* hint = new osg::Hint(GL_FOG_HINT, GL_DONT_CARE);
- hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/fog"));
- stateSet->setAttribute(hint);
- hint = new osg::Hint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE);
- hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/polygon-smooth"));
- stateSet->setAttribute(hint);
- hint = new osg::Hint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
- hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/line-smooth"));
- stateSet->setAttribute(hint);
- hint = new osg::Hint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
- hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/point-smooth"));
- stateSet->setAttribute(hint);
- hint = new osg::Hint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE);
- hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/perspective-correction"));
- stateSet->setAttribute(hint);
-
- osg::Group* sceneGroup = new osg::Group;
- sceneGroup->addChild(globals->get_scenery()->get_scene_graph());
- sceneGroup->setNodeMask(~simgear::BACKGROUND_BIT);
-
- //sceneGroup->addChild(thesky->getCloudRoot());
-
- stateSet = sceneGroup->getOrCreateStateSet();
- stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
-
- // need to update the light on every frame
- // OSG LightSource objects are rather confusing. OSG only supports
- // the 10 lights specified by OpenGL itself; if more than one
- // LightSource in the scene graph have the same light number, it's
- // indeterminate which values will be used to render geometry that
- // has that light number enabled. Also, adding children to a
- // LightSource is just a shortcut for setting up a state set that
- // has the corresponding OpenGL light enabled: a LightSource will
- // affect geometry anywhere in the scene graph that has its light
- // number enabled in a state set.
- LightSource* lightSource = new LightSource;
- lightSource->getLight()->setDataVariance(Object::DYNAMIC);
- // relative because of CameraView being just a clever transform node
- lightSource->setReferenceFrame(osg::LightSource::RELATIVE_RF);
- lightSource->setLocalStateSetModes(osg::StateAttribute::ON);
- lightSource->setUpdateCallback(new FGLightSourceUpdateCallback);
- mRealRoot->addChild(lightSource);
- // we need a white diffuse light for the phase of the moon
- osg::LightSource* sunLight = new osg::LightSource;
- sunLight->getLight()->setDataVariance(Object::DYNAMIC);
- sunLight->getLight()->setLightNum(1);
- sunLight->setUpdateCallback(new FGLightSourceUpdateCallback(true));
- sunLight->setReferenceFrame(osg::LightSource::RELATIVE_RF);
- sunLight->setLocalStateSetModes(osg::StateAttribute::ON);
-
- // Hang a StateSet above the sky subgraph in order to turn off
- // light 0
- Group* skyGroup = new Group;
- StateSet* skySS = skyGroup->getOrCreateStateSet();
- skySS->setMode(GL_LIGHT0, StateAttribute::OFF);
- skyGroup->addChild(_sky->getPreRoot());
- sunLight->addChild(skyGroup);
- mRoot->addChild(sceneGroup);
- if ( _classicalRenderer )
- mRoot->addChild(sunLight);
-
- // Clouds are added to the scene graph later
- stateSet = globals->get_scenery()->get_scene_graph()->getOrCreateStateSet();
- stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
- stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
- stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
-
- // enable disable specular highlights.
- // is the place where we might plug in an other fragment shader ...
- osg::LightModel* lightModel = new osg::LightModel;
- lightModel->setUpdateCallback(new FGLightModelUpdateCallback);
- stateSet->setAttribute(lightModel);
-
- // switch to enable wireframe
- osg::PolygonMode* polygonMode = new osg::PolygonMode;
- polygonMode->setUpdateCallback(new FGWireFrameModeUpdateCallback);
- stateSet->setAttributeAndModes(polygonMode);
-
- // scene fog handling
- osg::Fog* fog = new osg::Fog;
- fog->setUpdateCallback(new FGFogUpdateCallback);
- stateSet->setAttributeAndModes(fog);
- stateSet->setUpdateCallback(new FGFogEnableUpdateCallback);
-
- // plug in the GUI
- osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
- if (guiCamera) {
-
- osg::Geode* geode = new osg::Geode;
- geode->addDrawable(new SGPuDrawable);
- geode->addDrawable(new SGHUDDrawable);
- guiCamera->addChild(geode);
-
- panelSwitch = new osg::Switch;
- osg::StateSet* stateSet = panelSwitch->getOrCreateStateSet();
- stateSet->setRenderBinDetails(1000, "RenderBin");
-
- // speed optimization?
- stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
- stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
- stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
- stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
- stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
-
-
- panelSwitch->setUpdateCallback(new FGPanelSwitchCallback);
- panelChanged();
-
- guiCamera->addChild(panelSwitch.get());
- }
-
- osg::Switch* sw = new osg::Switch;
- sw->setUpdateCallback(new FGScenerySwitchCallback);
- sw->addChild(mRoot.get());
- mRealRoot->addChild(sw);
- // The clouds are attached directly to the scene graph root
- // because, in theory, they don't want the same default state set
- // as the rest of the scene. This may not be true in practice.
- if ( _classicalRenderer ) {
- mRealRoot->addChild(_sky->getCloudRoot());
- mRealRoot->addChild(FGCreateRedoutNode());
- }
- // Attach empty program to the scene root so that shader programs
- // don't leak into state sets (effects) that shouldn't have one.
- stateSet = mRealRoot->getOrCreateStateSet();
- stateSet->setAttributeAndModes(new osg::Program, osg::StateAttribute::ON);
-
- mDeferredRealRoot->addChild( mRealRoot.get() );
-}
-
-void FGRenderer::panelChanged()
-{
- if (!panelSwitch) {
- return;
- }
-
- osg::Node* n = FGPanelNode::createNode(globals->get_current_panel());
- if (panelSwitch->getNumChildren()) {
- panelSwitch->setChild(0, n);
- } else {
- panelSwitch->addChild(n);
- }
-}
-
-// Update all Visuals (redraws anything graphics related)
-void
-FGRenderer::update( ) {
- if (!(_scenery_loaded->getBoolValue() ||
- _scenery_override->getBoolValue()))
- {
- _splash_alpha->setDoubleValue(1.0);
- return;
- }
- osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
-
- if (_splash_alpha->getDoubleValue()>0.0)
- {
- // Fade out the splash screen
- const double fade_time = 0.5;
- const double fade_steps_per_sec = 10;
- double delay_time = SGMiscd::min(fade_time/fade_steps_per_sec,
- (SGTimeStamp::now() - _splash_time).toSecs());
- _splash_time = SGTimeStamp::now();
- double sAlpha = _splash_alpha->getDoubleValue();
- sAlpha -= SGMiscd::max(0.0,delay_time/fade_time);
- FGScenerySwitchCallback::scenery_enabled = (sAlpha<1.0);
- _splash_alpha->setDoubleValue((sAlpha < 0) ? 0.0 : sAlpha);
- }
-
- FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
- if (!_classicalRenderer ) {
- _ambientFactor->set( toOsg(l->scene_ambient()) );
- _sunDiffuse->set( toOsg(l->scene_diffuse()) );
- _sunSpecular->set( toOsg(l->scene_specular()) );
- _sunDirection->set( osg::Vec3f(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]) );
- }
-
- // update fog params
- double actual_visibility;
- if (_cloud_status->getBoolValue()) {
- actual_visibility = _sky->get_visibility();
- } else {
- actual_visibility = _visibility_m->getDoubleValue();
- }
-
- // idle_state is now 1000 meaning we've finished all our
- // initializations and are running the main loop, so this will
- // now work without seg faulting the system.
-
- FGViewer *current__view = globals->get_current_view();
- // Force update of center dependent values ...
- current__view->set_dirty();
-
- osg::Camera *camera = viewer->getCamera();
-
- bool skyblend = _skyblend->getBoolValue();
- if ( skyblend ) {
-
- if ( _textures->getBoolValue() ) {
- SGVec4f clearColor(l->adj_fog_color());
- camera->setClearColor(toOsg(clearColor));
- }
- } else {
- SGVec4f clearColor(l->sky_color());
- camera->setClearColor(toOsg(clearColor));
- }
-
- // update fog params if visibility has changed
- double visibility_meters = _visibility_m->getDoubleValue();
- _sky->set_visibility(visibility_meters);
-
- double altitude_m = _altitude_ft->getDoubleValue() * SG_FEET_TO_METER;
- _sky->modify_vis( altitude_m, 0.0 /* time factor, now unused */);
-
- // update the sky dome
- if ( skyblend ) {
-
- // The sun and moon distances are scaled down versions
- // of the actual distance to get both the moon and the sun
- // within the range of the far clip plane.
- // Moon distance: 384,467 kilometers
- // Sun distance: 150,000,000 kilometers
-
- double sun_horiz_eff, moon_horiz_eff;
- if (_horizon_effect->getBoolValue()) {
- sun_horiz_eff
- = 0.67 + pow(osg::clampAbove(0.5 + cos(l->get_sun_angle()),
- 0.0),
- 0.33) / 3.0;
- moon_horiz_eff
- = 0.67 + pow(osg::clampAbove(0.5 + cos(l->get_moon_angle()),
- 0.0),
- 0.33)/3.0;
- } else {
- sun_horiz_eff = moon_horiz_eff = 1.0;
- }
-
- SGSkyState sstate;
- sstate.pos = current__view->getViewPosition();
- sstate.pos_geod = current__view->getPosition();
- sstate.ori = current__view->getViewOrientation();
- sstate.spin = l->get_sun_rotation();
- sstate.gst = globals->get_time_params()->getGst();
- sstate.sun_dist = 50000.0 * sun_horiz_eff;
- sstate.moon_dist = 40000.0 * moon_horiz_eff;
- sstate.sun_angle = l->get_sun_angle();
-
- SGSkyColor scolor;
- scolor.sky_color = SGVec3f(l->sky_color().data());
- scolor.adj_sky_color = SGVec3f(l->adj_sky_color().data());
- scolor.fog_color = SGVec3f(l->adj_fog_color().data());
- scolor.cloud_color = SGVec3f(l->cloud_color().data());
- scolor.sun_angle = l->get_sun_angle();
- scolor.moon_angle = l->get_moon_angle();
-
- double delta_time_sec = _sim_delta_sec->getDoubleValue();
- _sky->reposition( sstate, *globals->get_ephem(), delta_time_sec );
- _sky->repaint( scolor, *globals->get_ephem() );
-
- //OSGFIXME
-// shadows->setupShadows(
-// current__view->getLongitude_deg(),
-// current__view->getLatitude_deg(),
-// globals->get_time_params()->getGst(),
-// globals->get_ephem()->getSunRightAscension(),
-// globals->get_ephem()->getSunDeclination(),
-// l->get_sun_angle());
-
- }
-
-// sgEnviro.setLight(l->adj_fog_color());
-// sgEnviro.startOfFrame(current__view->get_view_pos(),
-// current__view->get_world_up(),
-// current__view->getLongitude_deg(),
-// current__view->getLatitude_deg(),
-// current__view->getAltitudeASL_ft() * SG_FEET_TO_METER,
-// delta_time_sec);
-
- // OSGFIXME
-// sgEnviro.drawLightning();
-
-// double current_view_origin_airspeed_horiz_kt =
-// fgGetDouble("/velocities/airspeed-kt", 0.0)
-// * cos( fgGetDouble("/orientation/pitch-deg", 0.0)
-// * SGD_DEGREES_TO_RADIANS);
-
- // OSGFIXME
-// if( is_internal )
-// shadows->endOfFrame();
-
- // need to call the update visitor once
- mFrameStamp->setCalendarTime(*globals->get_time_params()->getGmt());
- mUpdateVisitor->setViewData(current__view->getViewPosition(),
- current__view->getViewOrientation());
- SGVec3f direction(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]);
- mUpdateVisitor->setLight(direction, l->scene_ambient(),
- l->scene_diffuse(), l->scene_specular(),
- l->adj_fog_color(),
- l->get_sun_angle()*SGD_RADIANS_TO_DEGREES);
- mUpdateVisitor->setVisibility(actual_visibility);
- simgear::GroundLightManager::instance()->update(mUpdateVisitor.get());
- osg::Node::NodeMask cullMask = ~simgear::LIGHTS_BITS & ~simgear::PICK_BIT;
- cullMask |= simgear::GroundLightManager::instance()
- ->getLightNodeMask(mUpdateVisitor.get());
- if (_panel_hotspots->getBoolValue())
- cullMask |= simgear::PICK_BIT;
- CameraGroup::getDefault()->setCameraCullMasks(cullMask);
- if ( !_classicalRenderer ) {
- _fogColor->set( toOsg( l->adj_fog_color() ) );
- _fogDensity->set( float( mUpdateVisitor->getFogExp2Density() ) );
- }
-}
-
-void
-FGRenderer::resize( int width, int height )
-{
- int curWidth = _xsize->getIntValue(),
- curHeight = _ysize->getIntValue();
- SG_LOG(SG_VIEW, SG_DEBUG, "FGRenderer::resize: new size " << width << " x " << height);
- if ((curHeight != height) || (curWidth != width)) {
- // must guard setting these, or PLIB-PUI fails with too many live interfaces
- _xsize->setIntValue(width);
- _ysize->setIntValue(height);
- }
-}
-
-bool
-FGRenderer::pick(std::vector<SGSceneryPick>& pickList,
- const osgGA::GUIEventAdapter* ea)
-{
- // wipe out the return ...
- pickList.clear();
- typedef osgUtil::LineSegmentIntersector::Intersections Intersections;
- Intersections intersections;
-
- if (!computeIntersections(CameraGroup::getDefault(), ea, intersections))
- return false;
- for (Intersections::iterator hit = intersections.begin(),
- e = intersections.end();
- hit != e;
- ++hit) {
- const osg::NodePath& np = hit->nodePath;
- osg::NodePath::const_reverse_iterator npi;
- for (npi = np.rbegin(); npi != np.rend(); ++npi) {
- SGSceneUserData* ud = SGSceneUserData::getSceneUserData(*npi);
- if (!ud)
- continue;
- for (unsigned i = 0; i < ud->getNumPickCallbacks(); ++i) {
- SGPickCallback* pickCallback = ud->getPickCallback(i);
- if (!pickCallback)
- continue;
- SGSceneryPick sceneryPick;
- sceneryPick.info.local = toSG(hit->getLocalIntersectPoint());
- sceneryPick.info.wgs84 = toSG(hit->getWorldIntersectPoint());
- sceneryPick.callback = pickCallback;
- pickList.push_back(sceneryPick);
- }
- }
- }
- return !pickList.empty();
-}
-
-void
-FGRenderer::setViewer(osgViewer::Viewer* viewer_)
-{
- viewer = viewer_;
-}
-
-void
-FGRenderer::setEventHandler(FGEventHandler* eventHandler_)
-{
- eventHandler = eventHandler_;
-}
-
-void
-FGRenderer::addCamera(osg::Camera* camera, bool useSceneData)
-{
- mRealRoot->addChild(camera);
-}
-
-void
-FGRenderer::removeCamera(osg::Camera* camera)
-{
- mRealRoot->removeChild(camera);
-}
-
-void
-FGRenderer::setPlanes( double zNear, double zFar )
-{
- _planes->set( osg::Vec3f( - zFar, - zFar * zNear, zFar - zNear ) );
-}
-
-bool
-fgDumpSceneGraphToFile(const char* filename)
-{
- return osgDB::writeNodeFile(*mRealRoot.get(), filename);
-}
-
-bool
-fgDumpTerrainBranchToFile(const char* filename)
-{
- return osgDB::writeNodeFile( *globals->get_scenery()->get_terrain_branch(),
- filename );
-}
-
-// For debugging
-bool
-fgDumpNodeToFile(osg::Node* node, const char* filename)
-{
- return osgDB::writeNodeFile(*node, filename);
-}
-
-namespace flightgear
-{
-using namespace osg;
-
-class VisibleSceneInfoVistor : public NodeVisitor, CullStack
-{
-public:
- VisibleSceneInfoVistor()
- : NodeVisitor(CULL_VISITOR, TRAVERSE_ACTIVE_CHILDREN)
- {
- setCullingMode(CullSettings::SMALL_FEATURE_CULLING
- | CullSettings::VIEW_FRUSTUM_CULLING);
- setComputeNearFarMode(CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
- }
-
- VisibleSceneInfoVistor(const VisibleSceneInfoVistor& rhs)
- {
- }
-
- META_NodeVisitor("flightgear","VisibleSceneInfoVistor")
-
- typedef std::map<const std::string,int> InfoMap;
-
- void getNodeInfo(Node* node)
- {
- const char* typeName = typeid(*node).name();
- classInfo[typeName]++;
- const std::string& nodeName = node->getName();
- if (!nodeName.empty())
- nodeInfo[nodeName]++;
- }
-
- void dumpInfo()
- {
- using namespace std;
- typedef vector<InfoMap::iterator> FreqVector;
- cout << "class info:\n";
- FreqVector classes;
- for (InfoMap::iterator itr = classInfo.begin(), end = classInfo.end();
- itr != end;
- ++itr)
- classes.push_back(itr);
- sort(classes.begin(), classes.end(), freqComp);
- for (FreqVector::iterator itr = classes.begin(), end = classes.end();
- itr != end;
- ++itr) {
- cout << (*itr)->first << " " << (*itr)->second << "\n";
- }
- cout << "\nnode info:\n";
- FreqVector nodes;
- for (InfoMap::iterator itr = nodeInfo.begin(), end = nodeInfo.end();
- itr != end;
- ++itr)
- nodes.push_back(itr);
-
- sort (nodes.begin(), nodes.end(), freqComp);
- for (FreqVector::iterator itr = nodes.begin(), end = nodes.end();
- itr != end;
- ++itr) {
- cout << (*itr)->first << " " << (*itr)->second << "\n";
- }
- cout << endl;
- }
-
- void doTraversal(Camera* camera, Node* root, Viewport* viewport)
- {
- ref_ptr<RefMatrix> projection
- = createOrReuseMatrix(camera->getProjectionMatrix());
- ref_ptr<RefMatrix> mv = createOrReuseMatrix(camera->getViewMatrix());
- if (!viewport)
- viewport = camera->getViewport();
- if (viewport)
- pushViewport(viewport);
- pushProjectionMatrix(projection.get());
- pushModelViewMatrix(mv.get(), Transform::ABSOLUTE_RF);
- root->accept(*this);
- popModelViewMatrix();
- popProjectionMatrix();
- if (viewport)
- popViewport();
- dumpInfo();
- }
-
- void apply(Node& node)
- {
- if (isCulled(node))
- return;
- pushCurrentMask();
- getNodeInfo(&node);
- traverse(node);
- popCurrentMask();
- }
- void apply(Group& node)
- {
- if (isCulled(node))
- return;
- pushCurrentMask();
- getNodeInfo(&node);
- traverse(node);
- popCurrentMask();
- }
-
- void apply(Transform& node)
- {
- if (isCulled(node))
- return;
- pushCurrentMask();
- ref_ptr<RefMatrix> matrix = createOrReuseMatrix(*getModelViewMatrix());
- node.computeLocalToWorldMatrix(*matrix,this);
- pushModelViewMatrix(matrix.get(), node.getReferenceFrame());
- getNodeInfo(&node);
- traverse(node);
- popModelViewMatrix();
- popCurrentMask();
- }
-
- void apply(Camera& camera)
- {
- // Save current cull settings
- CullSettings saved_cull_settings(*this);
-
- // set cull settings from this Camera
- setCullSettings(camera);
- // inherit the settings from above
- inheritCullSettings(saved_cull_settings, camera.getInheritanceMask());
-
- // set the cull mask.
- unsigned int savedTraversalMask = getTraversalMask();
- bool mustSetCullMask = (camera.getInheritanceMask()
- & osg::CullSettings::CULL_MASK) == 0;
- if (mustSetCullMask)
- setTraversalMask(camera.getCullMask());
-
- osg::RefMatrix* projection = 0;
- osg::RefMatrix* modelview = 0;
-
- if (camera.getReferenceFrame()==osg::Transform::RELATIVE_RF) {
- if (camera.getTransformOrder()==osg::Camera::POST_MULTIPLY) {
- projection = createOrReuseMatrix(*getProjectionMatrix()
- *camera.getProjectionMatrix());
- modelview = createOrReuseMatrix(*getModelViewMatrix()
- * camera.getViewMatrix());
- }
- else { // pre multiply
- projection = createOrReuseMatrix(camera.getProjectionMatrix()
- * (*getProjectionMatrix()));
- modelview = createOrReuseMatrix(camera.getViewMatrix()
- * (*getModelViewMatrix()));
- }
- } else {
- // an absolute reference frame
- projection = createOrReuseMatrix(camera.getProjectionMatrix());
- modelview = createOrReuseMatrix(camera.getViewMatrix());
- }
- if (camera.getViewport())
- pushViewport(camera.getViewport());
-
- pushProjectionMatrix(projection);
- pushModelViewMatrix(modelview, camera.getReferenceFrame());
-
- traverse(camera);
-
- // restore the previous model view matrix.
- popModelViewMatrix();
-
- // restore the previous model view matrix.
- popProjectionMatrix();
-
- if (camera.getViewport()) popViewport();
-
- // restore the previous traversal mask settings
- if (mustSetCullMask)
- setTraversalMask(savedTraversalMask);
-
- // restore the previous cull settings
- setCullSettings(saved_cull_settings);
- }
-
-protected:
- // sort in reverse
- static bool freqComp(const InfoMap::iterator& lhs, const InfoMap::iterator& rhs)
- {
- return lhs->second > rhs->second;
- }
- InfoMap classInfo;
- InfoMap nodeInfo;
-};
-
-bool printVisibleSceneInfo(FGRenderer* renderer)
-{
- osgViewer::Viewer* viewer = renderer->getViewer();
- VisibleSceneInfoVistor vsv;
- Viewport* vp = 0;
- if (!viewer->getCamera()->getViewport() && viewer->getNumSlaves() > 0) {
- const View::Slave& slave = viewer->getSlave(0);
- vp = slave._camera->getViewport();
- }
- vsv.doTraversal(viewer->getCamera(), viewer->getSceneData(), vp);
- return true;
-}
-
-}
-// end of renderer.cxx
-
+++ /dev/null
-
-#ifndef __FG_RENDERER_HXX
-#define __FG_RENDERER_HXX 1
-
-#include <simgear/scene/util/SGPickCallback.hxx>
-#include <simgear/props/props.hxx>
-#include <simgear/timing/timestamp.hxx>
-
-#include <osg/ref_ptr>
-#include <osg/Matrix>
-#include <osg/Vec3>
-
-namespace osg
-{
-class Camera;
-class Group;
-class GraphicsContext;
-}
-
-namespace osgGA
-{
-class GUIEventAdapter;
-}
-
-namespace osgShadow
-{
-class ShadowedScene;
-}
-
-namespace osgViewer
-{
-class Viewer;
-}
-
-namespace flightgear
-{
-class FGEventHandler;
-struct CameraInfo;
-class CameraGroup;
-}
-
-class SGSky;
-
-class FGRenderer {
-
-public:
-
- FGRenderer();
- ~FGRenderer();
-
- void splashinit();
- void init();
-
- void setupView();
-
- void resize(int width, int height );
-
- void update();
-
- /** Just pick into the scene and return the pick callbacks on the way ...
- */
- bool pick( std::vector<SGSceneryPick>& pickList,
- const osgGA::GUIEventAdapter* ea );
-
- /** Get and set the OSG Viewer object, if any.
- */
- osgViewer::Viewer* getViewer() { return viewer.get(); }
- const osgViewer::Viewer* getViewer() const { return viewer.get(); }
- void setViewer(osgViewer::Viewer* viewer);
- /** Get and set the manipulator object, if any.
- */
- flightgear::FGEventHandler* getEventHandler() { return eventHandler.get(); }
- const flightgear::FGEventHandler* getEventHandler() const { return eventHandler.get(); }
- void setEventHandler(flightgear::FGEventHandler* manipulator);
-
- /** Add a top level camera.
- */
- void addCamera(osg::Camera* camera, bool useSceneData);
-
- void removeCamera(osg::Camera* camera);
-
- /** Add a camera to the group. The camera is added to the viewer
- * as a slave. See osgViewer::Viewer::addSlave.
- * @param flags properties of the camera; see CameraGroup::Flags
- * @param projection slave projection matrix
- * @param view slave view matrix
- * @param useMasterSceneData whether the camera displays the
- * viewer's scene data.
- * @return a CameraInfo object for the camera.
- */
- flightgear::CameraInfo* buildRenderingPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
- const osg::Matrix& view,
- const osg::Matrix& projection,
- osg::GraphicsContext* gc,
- bool useMasterSceneData);
-
- /**
- */
- flightgear::CameraInfo* buildClassicalPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
- const osg::Matrix& view,
- const osg::Matrix& projection,
- bool useMasterSceneData);
-
- /**
- */
- flightgear::CameraInfo* buildDeferredPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
- const osg::Matrix& view, const osg::Matrix& projection, osg::GraphicsContext* gc);
-
- void updateShadowCamera(const flightgear::CameraInfo* info, const osg::Vec3d& position);
- void updateShadowMapSize(int mapSize);
- void enableShadows(bool enabled);
- void updateCascadeFar(int index, float far_m);
- void updateCascadeNumber(size_t num);
-
- SGSky* getSky() const { return _sky; }
-
- void setPlanes( double zNear, double zFar );
-
- /**
- * inform the renderer when the global (2D) panel is changed
- */
- void panelChanged();
-protected:
- osg::ref_ptr<osgViewer::Viewer> viewer;
- osg::ref_ptr<flightgear::FGEventHandler> eventHandler;
- SGPropertyNode_ptr _scenery_loaded,_scenery_override;
- SGPropertyNode_ptr _skyblend, _splash_alpha;
- SGPropertyNode_ptr _point_sprites, _enhanced_lighting, _distance_attenuation;
- SGPropertyNode_ptr _textures;
- SGPropertyNode_ptr _cloud_status, _visibility_m;
- SGPropertyNode_ptr _xsize, _ysize;
- SGPropertyNode_ptr _panel_hotspots, _sim_delta_sec, _horizon_effect, _altitude_ft;
- SGPropertyNode_ptr _virtual_cockpit;
- SGTimeStamp _splash_time;
- SGSky* _sky;
- bool _classicalRenderer;
- int _shadowMapSize;
- size_t _numCascades;
- float _cascadeFar[4];
-
- osg::Camera* buildDeferredGeometryCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc );
- osg::Camera* buildDeferredShadowCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc );
- osg::Camera* buildDeferredLightingCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc );
- void updateShadowCascade(const flightgear::CameraInfo* info, osg::Camera* camera, osg::Group* grp, int idx, double left, double right, double bottom, double top, double zNear, double f1, double f2);
- osg::Vec3 getSunDirection() const;
- osg::ref_ptr<osg::Uniform> _ambientFactor;
- osg::ref_ptr<osg::Uniform> _sunDiffuse;
- osg::ref_ptr<osg::Uniform> _sunSpecular;
- osg::ref_ptr<osg::Uniform> _sunDirection;
- osg::ref_ptr<osg::Uniform> _planes;
- osg::ref_ptr<osg::Uniform> _fogColor;
- osg::ref_ptr<osg::Uniform> _fogDensity;
- osg::ref_ptr<osg::Uniform> _shadowNumber;
- osg::ref_ptr<osg::Uniform> _shadowDistances;
-};
-
-bool fgDumpSceneGraphToFile(const char* filename);
-bool fgDumpTerrainBranchToFile(const char* filename);
-
-namespace flightgear
-{
-bool printVisibleSceneInfo(FGRenderer* renderer);
-}
-
-#endif
+++ /dev/null
-// splash.cxx -- draws the initial splash screen
-//
-// Written by Curtis Olson, started July 1998. (With a little looking
-// at Freidemann's panel code.) :-)
-//
-// Copyright (C) 1997 Michele F. America - nomimarketing@mail.telepac.pt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program 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 GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// $Id$
-
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <osg/BlendFunc>
-#include <osg/Camera>
-#include <osg/Depth>
-#include <osg/Geometry>
-#include <osg/Node>
-#include <osg/NodeCallback>
-#include <osg/NodeVisitor>
-#include <osg/StateSet>
-#include <osg/Switch>
-#include <osg/Texture2D>
-#include <osgUtil/CullVisitor>
-#include <osgText/Text>
-#include <osgDB/ReadFile>
-
-#include <simgear/compiler.h>
-
-#include <simgear/debug/logstream.hxx>
-#include <simgear/math/sg_random.h>
-#include <simgear/misc/sg_path.hxx>
-
-#include <plib/fnt.h>
-
-#include "GUI/FGFontCache.hxx"
-#include "GUI/FGColor.hxx"
-
-#include "globals.hxx"
-#include "fg_props.hxx"
-#include "splash.hxx"
-#include "renderer.hxx"
-#include "fg_os.hxx"
-
-class FGSplashUpdateCallback : public osg::Drawable::UpdateCallback {
-public:
- FGSplashUpdateCallback(osg::Vec4Array* colorArray, SGPropertyNode* prop) :
- _colorArray(colorArray),
- _colorProperty(prop),
- _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true))
- { }
- virtual void update(osg::NodeVisitor*, osg::Drawable*)
- {
- FGColor c(0, 0, 0);
- if (_colorProperty) {
- c.merge(_colorProperty);
- (*_colorArray)[0][0] = c.red();
- (*_colorArray)[0][1] = c.green();
- (*_colorArray)[0][2] = c.blue();
- }
- (*_colorArray)[0][3] = _alphaProperty->getFloatValue();
- _colorArray->dirty();
- }
-private:
- osg::ref_ptr<osg::Vec4Array> _colorArray;
- SGSharedPtr<const SGPropertyNode> _colorProperty;
- SGSharedPtr<const SGPropertyNode> _alphaProperty;
-};
-
-class FGSplashTextUpdateCallback : public osg::Drawable::UpdateCallback {
-public:
- FGSplashTextUpdateCallback(const SGPropertyNode* prop) :
- _textProperty(prop),
- _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true)),
- _styleProperty(fgGetNode("/sim/gui/style[0]", true))
- {}
- virtual void update(osg::NodeVisitor*, osg::Drawable* drawable)
- {
- assert(dynamic_cast<osgText::Text*>(drawable));
- osgText::Text* text = static_cast<osgText::Text*>(drawable);
-
- FGColor c(1.0, 0.9, 0.0);
- c.merge(_styleProperty->getNode("colors/splash-font"));
- float alpha = _alphaProperty->getFloatValue();
- text->setColor(osg::Vec4(c.red(), c.green(), c.blue(), alpha));
-
- const char* s = _textProperty->getStringValue();
- if (s && fgGetBool("/sim/startup/splash-progress", true))
- text->setText(s);
- else
- text->setText("");
- }
-private:
- SGSharedPtr<const SGPropertyNode> _textProperty;
- SGSharedPtr<const SGPropertyNode> _alphaProperty;
- SGSharedPtr<const SGPropertyNode> _styleProperty;
-};
-
-
-
-class FGSplashContentProjectionCalback : public osg::NodeCallback {
-public:
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- assert(dynamic_cast<osgUtil::CullVisitor*>(nv));
- osgUtil::CullVisitor* cullVisitor = static_cast<osgUtil::CullVisitor*>(nv);
-
- // adjust the projection matrix in a way that preserves the aspect ratio
- // of the content ...
- const osg::Viewport* viewport = cullVisitor->getViewport();
- float viewportAspect = float(viewport->height())/float(viewport->width());
-
- float height, width;
- if (viewportAspect < 1) {
- height = 1;
- width = 1/viewportAspect;
- } else {
- height = viewportAspect;
- width = 1;
- }
-
- osg::RefMatrix* matrix = new osg::RefMatrix;
- matrix->makeOrtho2D(-width, width, -height, height);
-
- // The trick is to have the projection matrix adapted independent
- // of the scenegraph but dependent on the viewport of this current
- // camera we cull for. Therefore we do not put that projection matrix into
- // an additional camera rather than from within that cull callback.
- cullVisitor->pushProjectionMatrix(matrix);
- traverse(node, nv);
- cullVisitor->popProjectionMatrix();
- }
-};
-
-char *genNameString()
-{
- std::string website = "http://www.flightgear.org";
- std::string programName = "FlightGear";
- char *name = new char[26];
- name[20] = 114;
- name[8] = 119;
- name[5] = 47;
- name[12] = 108;
- name[2] = 116;
- name[1] = 116;
- name[16] = 116;
- name[13] = 105;
- name[17] = 103;
- name[19] = 97;
- name[25] = 0;
- name[0] = 104;
- name[24] = 103;
- name[21] = 46;
- name[15] = 104;
- name[3] = 112;
- name[22] = 111;
- name[18] = 101;
- name[7] = 119;
- name[14] = 103;
- name[23] = 114;
- name[4] = 58;
- name[11] = 102;
- name[9] = 119;
- name[10] = 46;
- name[6] = 47;
- return name;
-}
-
-static osg::Node* fgCreateSplashCamera()
-{
- const char* splash_texture = fgGetString("/sim/startup/splash-texture");
- SGSharedPtr<SGPropertyNode> style = fgGetNode("/sim/gui/style[0]", true);
-
- char *namestring = genNameString();
- fgSetString("/sim/startup/program-name", namestring);
- delete[] namestring;
-
- SGPath tpath;
- if (splash_texture && strcmp(splash_texture, "")) {
- tpath = globals->resolve_maybe_aircraft_path(splash_texture);
- if (tpath.isNull())
- {
- SG_LOG( SG_VIEW, SG_ALERT, "Cannot find splash screen file '" << splash_texture
- << "'. Using default." );
- }
- }
-
- if (tpath.isNull()) {
- // no splash screen specified - select random image
- tpath = globals->get_fg_root();
- // load in the texture data
- int num = (int)(sg_random() * 5.0 + 1.0);
- char num_str[5];
- snprintf(num_str, 4, "%d", num);
-
- tpath.append( "Textures/Splash" );
- tpath.concat( num_str );
- tpath.concat( ".png" );
- }
-
- osg::Texture2D* splashTexture = new osg::Texture2D;
- splashTexture->setImage(osgDB::readImageFile(tpath.c_str()));
-
- osg::Camera* camera = new osg::Camera;
- camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
- camera->setProjectionMatrix(osg::Matrix::ortho2D(-1, 1, -1, 1));
- camera->setViewMatrix(osg::Matrix::identity());
- camera->setRenderOrder(osg::Camera::POST_RENDER, 10000);
- camera->setClearMask(0);
- camera->setAllowEventFocus(false);
- camera->setCullingActive(false);
-
- osg::StateSet* stateSet = camera->getOrCreateStateSet();
- stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
- stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
- stateSet->setAttribute(new osg::BlendFunc);
- stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
- stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
- stateSet->setAttribute(new osg::Depth(osg::Depth::ALWAYS, 0, 1, false));
- stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
-
-
- osg::Geometry* geometry = new osg::Geometry;
- geometry->setSupportsDisplayList(false);
-
- osg::Vec3Array* vertexArray = new osg::Vec3Array;
- vertexArray->push_back(osg::Vec3(-1, -1, 0));
- vertexArray->push_back(osg::Vec3( 1, -1, 0));
- vertexArray->push_back(osg::Vec3( 1, 1, 0));
- vertexArray->push_back(osg::Vec3(-1, 1, 0));
- geometry->setVertexArray(vertexArray);
- osg::Vec4Array* colorArray = new osg::Vec4Array;
- colorArray->push_back(osg::Vec4(0, 0, 0, 1));
- geometry->setColorArray(colorArray);
- geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
- geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
- geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray,
- style->getNode("colors/splash-screen")));
-
- osg::Geode* geode = new osg::Geode;
- geode->addDrawable(geometry);
-
- stateSet = geode->getOrCreateStateSet();
- stateSet->setRenderBinDetails(1, "RenderBin");
- camera->addChild(geode);
-
-
- // The group is needed because of osg is handling the cull callbacks in a
- // different way for groups than for a geode. It does not hurt here ...
- osg::Group* group = new osg::Group;
- group->setCullCallback(new FGSplashContentProjectionCalback);
- camera->addChild(group);
-
- geode = new osg::Geode;
- stateSet = geode->getOrCreateStateSet();
- stateSet->setRenderBinDetails(2, "RenderBin");
- group->addChild(geode);
-
-
- geometry = new osg::Geometry;
- geometry->setSupportsDisplayList(false);
-
- vertexArray = new osg::Vec3Array;
- vertexArray->push_back(osg::Vec3(-0.84, -0.84, 0));
- vertexArray->push_back(osg::Vec3( 0.84, -0.84, 0));
- vertexArray->push_back(osg::Vec3( 0.84, 0.84, 0));
- vertexArray->push_back(osg::Vec3(-0.84, 0.84, 0));
- geometry->setVertexArray(vertexArray);
- osg::Vec2Array* texCoordArray = new osg::Vec2Array;
- texCoordArray->push_back(osg::Vec2(0, 0));
- texCoordArray->push_back(osg::Vec2(1, 0));
- texCoordArray->push_back(osg::Vec2(1, 1));
- texCoordArray->push_back(osg::Vec2(0, 1));
- geometry->setTexCoordArray(0, texCoordArray);
- colorArray = new osg::Vec4Array;
- colorArray->push_back(osg::Vec4(1, 1, 1, 1));
- geometry->setColorArray(colorArray);
- geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
- geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
- geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray, 0));
- stateSet = geometry->getOrCreateStateSet();
- stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
- stateSet->setTextureAttribute(0, splashTexture);
- geode->addDrawable(geometry);
-
-
- osgText::Text* text = new osgText::Text;
- std::string fn = style->getStringValue("fonts/splash", "");
- text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
- text->setCharacterSize(0.06);
- text->setColor(osg::Vec4(1, 1, 1, 1));
- text->setPosition(osg::Vec3(0, -0.92, 0));
- text->setAlignment(osgText::Text::CENTER_CENTER);
- SGPropertyNode* prop = fgGetNode("/sim/startup/splash-progress-text", true);
- prop->setStringValue("initializing");
- text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
- geode->addDrawable(text);
-
- text = new osgText::Text;
- text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
- text->setCharacterSize(0.08);
- text->setColor(osg::Vec4(1, 1, 1, 1));
- text->setPosition(osg::Vec3(0, 0.92, 0));
- text->setAlignment(osgText::Text::CENTER_CENTER);
- prop = fgGetNode("/sim/startup/program-name", "FlightGear");
- text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
- geode->addDrawable(text);
-
-
- text = new osgText::Text;
- text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
- text->setCharacterSize(0.06);
- text->setColor(osg::Vec4(1, 1, 1, 1));
- text->setPosition(osg::Vec3(0, 0.82, 0));
- text->setAlignment(osgText::Text::CENTER_CENTER);
- prop = fgGetNode("/sim/startup/splash-title", true);
- text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
- geode->addDrawable(text);
-
- return camera;
-}
-
-// update callback for the switch node guarding that splash
-class FGSplashGroupUpdateCallback : public osg::NodeCallback {
-public:
- FGSplashGroupUpdateCallback() :
- _splashAlphaNode(fgGetNode("/sim/startup/splash-alpha", true))
- { }
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- assert(dynamic_cast<osg::Group*>(node));
- osg::Group* group = static_cast<osg::Group*>(node);
-
- double alpha = _splashAlphaNode->getDoubleValue();
- if (alpha <= 0 || !fgGetBool("/sim/startup/splash-screen"))
- group->removeChild(0, group->getNumChildren());
- else if (group->getNumChildren() == 0)
- group->addChild(fgCreateSplashCamera());
-
- traverse(node, nv);
- }
-private:
- SGSharedPtr<const SGPropertyNode> _splashAlphaNode;
-};
-
-osg::Node* fgCreateSplashNode() {
- osg::Group* group = new osg::Group;
- group->setUpdateCallback(new FGSplashGroupUpdateCallback);
- return group;
-}
-
-// Initialize the splash screen
-void fgSplashInit () {
- SG_LOG( SG_VIEW, SG_INFO, "Initializing splash screen" );
- globals->get_renderer()->splashinit();
-}
-
-void fgSplashProgress ( const char *text ) {
- SG_LOG( SG_VIEW, SG_INFO, "Splash screen progress " << text );
- fgSetString("/sim/startup/splash-progress-text", text);
-}
+++ /dev/null
-// splash.hxx -- draws the initial splash screen
-//
-// Written by Curtis Olson, started July 1998. (With a little looking
-// at Freidemann's panel code.) :-)
-//
-// Copyright (C) 1997 Michele F. America - nomimarketing@mail.telepac.pt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program 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 GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// $Id$
-
-
-#ifndef _SPLASH_HXX
-#define _SPLASH_HXX
-
-#include <osg/Node>
-
-#ifndef __cplusplus
-# error This library requires C++
-#endif
-
-// Initialize the splash screen
-void fgSplashInit ();
-
-// Set progress information
-void fgSplashProgress ( const char *text );
-
-// Retrieve the splash screen node ...
-osg::Node* fgCreateSplashNode();
-
-#endif // _SPLASH_HXX
-
-
+++ /dev/null
-// viewer.cxx -- class for managing a viewer in the flightgear world.
-//
-// Written by Curtis Olson, started August 1997.
-// overhaul started October 2000.
-// partially rewritten by Jim Wilson jim@kelcomaine.com using interface
-// by David Megginson March 2002
-//
-// Copyright (C) 1997 - 2000 Curtis L. Olson - http://www.flightgear.org/~curt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program 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 GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// $Id$
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <simgear/compiler.h>
-#include <cassert>
-
-#include "fg_props.hxx"
-
-#include <simgear/debug/logstream.hxx>
-#include <simgear/constants.h>
-#include <simgear/scene/model/placement.hxx>
-#include <simgear/scene/util/OsgMath.hxx>
-
-#include <Main/globals.hxx>
-#include <Scenery/scenery.hxx>
-#include <Model/acmodel.hxx>
-
-#include "viewer.hxx"
-
-#include "CameraGroup.hxx"
-
-using namespace flightgear;
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGViewer.
-////////////////////////////////////////////////////////////////////////
-
-// Constructor...
-FGViewer::FGViewer( fgViewType Type, bool from_model, int from_model_index,
- bool at_model, int at_model_index,
- double damp_roll, double damp_pitch, double damp_heading,
- double x_offset_m, double y_offset_m, double z_offset_m,
- double heading_offset_deg, double pitch_offset_deg,
- double roll_offset_deg,
- double fov_deg, double aspect_ratio_multiplier,
- double target_x_offset_m, double target_y_offset_m,
- double target_z_offset_m, double near_m, bool internal ):
- _dirty(true),
- _roll_deg(0),
- _pitch_deg(0),
- _heading_deg(0),
- _scaling_type(FG_SCALING_MAX),
- _cameraGroup(CameraGroup::getDefault())
-{
- _absolute_view_pos = SGVec3d(0, 0, 0);
- _type = Type;
- _from_model = from_model;
- _from_model_index = from_model_index;
- _at_model = at_model;
- _at_model_index = at_model_index;
-
- _internal = internal;
-
- _dampFactor = SGVec3d::zeros();
- _dampOutput = SGVec3d::zeros();
- _dampTarget = SGVec3d::zeros();
-
- if (damp_roll > 0.0)
- _dampFactor[0] = 1.0 / pow(10.0, fabs(damp_roll));
- if (damp_pitch > 0.0)
- _dampFactor[1] = 1.0 / pow(10.0, fabs(damp_pitch));
- if (damp_heading > 0.0)
- _dampFactor[2] = 1.0 / pow(10.0, fabs(damp_heading));
-
- _offset_m.x() = x_offset_m;
- _offset_m.y() = y_offset_m;
- _offset_m.z() = z_offset_m;
- _heading_offset_deg = heading_offset_deg;
- _pitch_offset_deg = pitch_offset_deg;
- _roll_offset_deg = roll_offset_deg;
- _goal_heading_offset_deg = heading_offset_deg;
- _goal_pitch_offset_deg = pitch_offset_deg;
- _goal_roll_offset_deg = roll_offset_deg;
- if (fov_deg > 0) {
- _fov_deg = fov_deg;
- } else {
- _fov_deg = 55;
- }
-
- _aspect_ratio_multiplier = aspect_ratio_multiplier;
- _target_offset_m.x() = target_x_offset_m;
- _target_offset_m.y() = target_y_offset_m;
- _target_offset_m.z() = target_z_offset_m;
- _ground_level_nearplane_m = near_m;
- // a reasonable guess for init, so that the math doesn't blow up
-}
-
-
-// Destructor
-FGViewer::~FGViewer( void ) {
-}
-
-void
-FGViewer::init ()
-{
-}
-
-void
-FGViewer::bind ()
-{
-}
-
-void
-FGViewer::unbind ()
-{
-}
-
-void
-FGViewer::setType ( int type )
-{
- if (type == 0)
- _type = FG_LOOKFROM;
- if (type == 1)
- _type = FG_LOOKAT;
-}
-
-void
-FGViewer::setInternal ( bool internal )
-{
- _internal = internal;
-}
-
-void
-FGViewer::setPosition (double lon_deg, double lat_deg, double alt_ft)
-{
- _dirty = true;
- _position = SGGeod::fromDegFt(lon_deg, lat_deg, alt_ft);
-}
-
-void
-FGViewer::setTargetPosition (double lon_deg, double lat_deg, double alt_ft)
-{
- _dirty = true;
- _target = SGGeod::fromDegFt(lon_deg, lat_deg, alt_ft);
-}
-
-void
-FGViewer::setRoll_deg (double roll_deg)
-{
- _dirty = true;
- _roll_deg = roll_deg;
-}
-
-void
-FGViewer::setPitch_deg (double pitch_deg)
-{
- _dirty = true;
- _pitch_deg = pitch_deg;
-}
-
-void
-FGViewer::setHeading_deg (double heading_deg)
-{
- _dirty = true;
- _heading_deg = heading_deg;
-}
-
-void
-FGViewer::setOrientation (double roll_deg, double pitch_deg, double heading_deg)
-{
- _dirty = true;
- _roll_deg = roll_deg;
- _pitch_deg = pitch_deg;
- _heading_deg = heading_deg;
-}
-
-void
-FGViewer::setTargetRoll_deg (double target_roll_deg)
-{
- _dirty = true;
- _target_roll_deg = target_roll_deg;
-}
-
-void
-FGViewer::setTargetPitch_deg (double target_pitch_deg)
-{
- _dirty = true;
- _target_pitch_deg = target_pitch_deg;
-}
-
-void
-FGViewer::setTargetHeading_deg (double target_heading_deg)
-{
- _dirty = true;
- _target_heading_deg = target_heading_deg;
-}
-
-void
-FGViewer::setTargetOrientation (double target_roll_deg, double target_pitch_deg, double target_heading_deg)
-{
- _dirty = true;
- _target_roll_deg = target_roll_deg;
- _target_pitch_deg = target_pitch_deg;
- _target_heading_deg = target_heading_deg;
-}
-
-void
-FGViewer::setXOffset_m (double x_offset_m)
-{
- _dirty = true;
- _offset_m.x() = x_offset_m;
-}
-
-void
-FGViewer::setYOffset_m (double y_offset_m)
-{
- _dirty = true;
- _offset_m.y() = y_offset_m;
-}
-
-void
-FGViewer::setZOffset_m (double z_offset_m)
-{
- _dirty = true;
- _offset_m.z() = z_offset_m;
-}
-
-void
-FGViewer::setTargetXOffset_m (double target_x_offset_m)
-{
- _dirty = true;
- _target_offset_m.x() = target_x_offset_m;
-}
-
-void
-FGViewer::setTargetYOffset_m (double target_y_offset_m)
-{
- _dirty = true;
- _target_offset_m.y() = target_y_offset_m;
-}
-
-void
-FGViewer::setTargetZOffset_m (double target_z_offset_m)
-{
- _dirty = true;
- _target_offset_m.z() = target_z_offset_m;
-}
-
-void
-FGViewer::setPositionOffsets (double x_offset_m, double y_offset_m, double z_offset_m)
-{
- _dirty = true;
- _offset_m.x() = x_offset_m;
- _offset_m.y() = y_offset_m;
- _offset_m.z() = z_offset_m;
-}
-
-void
-FGViewer::setRollOffset_deg (double roll_offset_deg)
-{
- _dirty = true;
- _roll_offset_deg = roll_offset_deg;
-}
-
-void
-FGViewer::setPitchOffset_deg (double pitch_offset_deg)
-{
- _dirty = true;
- _pitch_offset_deg = pitch_offset_deg;
-}
-
-void
-FGViewer::setHeadingOffset_deg (double heading_offset_deg)
-{
- _dirty = true;
- if (_at_model && (_offset_m.x() == 0.0)&&(_offset_m.z() == 0.0))
- {
- /* avoid optical effects (e.g. rotating sky) when "looking at" with
- * heading offsets x==z==0 (view heading cannot change). */
- _heading_offset_deg = 0.0;
- }
- else
- _heading_offset_deg = heading_offset_deg;
-}
-
-void
-FGViewer::setGoalRollOffset_deg (double goal_roll_offset_deg)
-{
- _dirty = true;
- _goal_roll_offset_deg = goal_roll_offset_deg;
-}
-
-void
-FGViewer::setGoalPitchOffset_deg (double goal_pitch_offset_deg)
-{
- _dirty = true;
- _goal_pitch_offset_deg = goal_pitch_offset_deg;
- if ( _goal_pitch_offset_deg < -90 ) {
- _goal_pitch_offset_deg = -90.0;
- }
- if ( _goal_pitch_offset_deg > 90.0 ) {
- _goal_pitch_offset_deg = 90.0;
- }
-
-}
-
-void
-FGViewer::setGoalHeadingOffset_deg (double goal_heading_offset_deg)
-{
- _dirty = true;
- if (_at_model && (_offset_m.x() == 0.0)&&(_offset_m.z() == 0.0))
- {
- /* avoid optical effects (e.g. rotating sky) when "looking at" with
- * heading offsets x==z==0 (view heading cannot change). */
- _goal_heading_offset_deg = 0.0;
- return;
- }
-
- _goal_heading_offset_deg = goal_heading_offset_deg;
- while ( _goal_heading_offset_deg < 0.0 ) {
- _goal_heading_offset_deg += 360;
- }
- while ( _goal_heading_offset_deg > 360 ) {
- _goal_heading_offset_deg -= 360;
- }
-}
-
-void
-FGViewer::setOrientationOffsets (double roll_offset_deg, double pitch_offset_deg, double heading_offset_deg)
-{
- _dirty = true;
- _roll_offset_deg = roll_offset_deg;
- _pitch_offset_deg = pitch_offset_deg;
- _heading_offset_deg = heading_offset_deg;
-}
-
-// recalc() is done every time one of the setters is called (making the
-// cached data "dirty") on the next "get". It calculates all the outputs
-// for viewer.
-void
-FGViewer::recalc ()
-{
- if (_type == FG_LOOKFROM) {
- recalcLookFrom();
- } else {
- recalcLookAt();
- }
-
- set_clean();
-}
-
-// recalculate for LookFrom view type...
-void
-FGViewer::recalcLookFrom ()
-{
- // Update location data ...
- if ( _from_model ) {
- SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
- _position = placement->getPosition();
-
- _heading_deg = placement->getHeadingDeg();
- _pitch_deg = placement->getPitchDeg();
- _roll_deg = placement->getRollDeg();
- }
-
- double head = _heading_deg;
- double pitch = _pitch_deg;
- double roll = _roll_deg;
- if ( !_from_model ) {
- // update from our own data...
- setDampTarget(roll, pitch, head);
- getDampOutput(roll, pitch, head);
- }
-
- // The rotation rotating from the earth centerd frame to
- // the horizontal local frame
- SGQuatd hlOr = SGQuatd::fromLonLat(_position);
-
- // The rotation from the horizontal local frame to the basic view orientation
- SGQuatd hlToBody = SGQuatd::fromYawPitchRollDeg(head, pitch, roll);
-
- // The rotation offset, don't know why heading is negative here ...
- mViewOffsetOr
- = SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg, _pitch_offset_deg,
- _roll_offset_deg);
-
- // Compute the eyepoints orientation and position
- // wrt the earth centered frame - that is global coorinates
- SGQuatd ec2body = hlOr*hlToBody;
-
- // The cartesian position of the basic view coordinate
- SGVec3d position = SGVec3d::fromGeod(_position);
-
- // This is rotates the x-forward, y-right, z-down coordinate system the where
- // simulation runs into the OpenGL camera system with x-right, y-up, z-back.
- SGQuatd q(-0.5, -0.5, 0.5, 0.5);
-
- _absolute_view_pos = position + (ec2body*q).backTransform(_offset_m);
- mViewOrientation = ec2body*mViewOffsetOr*q;
-}
-
-void
-FGViewer::recalcLookAt ()
-{
- // The geodetic position of our target to look at
- if ( _at_model ) {
- SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
- _target = placement->getPosition();
- _target_heading_deg = placement->getHeadingDeg();
- _target_pitch_deg = placement->getPitchDeg();
- _target_roll_deg = placement->getRollDeg();
- } else {
- // if not model then calculate our own target position...
- setDampTarget(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
- getDampOutput(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
- }
-
- SGQuatd geodTargetOr = SGQuatd::fromYawPitchRollDeg(_target_heading_deg,
- _target_pitch_deg,
- _target_roll_deg);
- SGQuatd geodTargetHlOr = SGQuatd::fromLonLat(_target);
-
-
- if ( _from_model ) {
- SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
- _position = placement->getPosition();
- _heading_deg = placement->getHeadingDeg();
- _pitch_deg = placement->getPitchDeg();
- _roll_deg = placement->getRollDeg();
- } else {
- // update from our own data, just the rotation here...
- setDampTarget(_roll_deg, _pitch_deg, _heading_deg);
- getDampOutput(_roll_deg, _pitch_deg, _heading_deg);
- }
- SGQuatd geodEyeOr = SGQuatd::fromYawPitchRollDeg(_heading_deg, _pitch_deg, _roll_deg);
- SGQuatd geodEyeHlOr = SGQuatd::fromLonLat(_position);
-
- // the rotation offset, don't know why heading is negative here ...
- mViewOffsetOr =
- SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg + 180, _pitch_offset_deg,
- _roll_offset_deg);
-
- // Offsets to the eye position
- SGVec3d eyeOff(-_offset_m.z(), _offset_m.x(), -_offset_m.y());
- SGQuatd ec2eye = geodEyeHlOr*geodEyeOr;
- SGVec3d eyeCart = SGVec3d::fromGeod(_position);
- eyeCart += (ec2eye*mViewOffsetOr).backTransform(eyeOff);
-
- SGVec3d atCart = SGVec3d::fromGeod(_target);
-
- // add target offsets to at_position...
- SGVec3d target_pos_off(-_target_offset_m.z(), _target_offset_m.x(),
- -_target_offset_m.y());
- target_pos_off = (geodTargetHlOr*geodTargetOr).backTransform(target_pos_off);
- atCart += target_pos_off;
- eyeCart += target_pos_off;
-
- // Compute the eyepoints orientation and position
- // wrt the earth centered frame - that is global coorinates
- _absolute_view_pos = eyeCart;
-
- // the view direction
- SGVec3d dir = normalize(atCart - eyeCart);
- // the up directon
- SGVec3d up = ec2eye.backTransform(SGVec3d(0, 0, -1));
- // rotate -dir to the 2-th unit vector
- // rotate up to 1-th unit vector
- // Note that this matches the OpenGL camera coordinate system
- // with x-right, y-up, z-back.
- mViewOrientation = SGQuatd::fromRotateTo(-dir, 2, up, 1);
-}
-
-void
-FGViewer::setDampTarget(double roll, double pitch, double heading)
-{
- _dampTarget = SGVec3d(roll, pitch, heading);
-}
-
-void
-FGViewer::getDampOutput(double& roll, double& pitch, double& heading)
-{
- roll = _dampOutput[0];
- pitch = _dampOutput[1];
- heading = _dampOutput[2];
-}
-
-
-void
-FGViewer::updateDampOutput(double dt)
-{
- static FGViewer *last_view = 0;
- if ((last_view != this) || (dt > 1.0)) {
- _dampOutput = _dampTarget;
- last_view = this;
- return;
- }
-
- const double interval = 0.01;
- while (dt > interval) {
-
- for (unsigned int i=0; i<3; ++i) {
- if (_dampFactor[i] <= 0.0) {
- // axis is un-damped, set output to target directly
- _dampOutput[i] = _dampTarget[i];
- continue;
- }
-
- double d = _dampOutput[i] - _dampTarget[i];
- if (d > 180.0) {
- _dampOutput[i] -= 360.0;
- } else if (d < -180.0) {
- _dampOutput[i] += 360.0;
- }
-
- _dampOutput[i] = (_dampTarget[i] * _dampFactor[i]) +
- (_dampOutput[i] * (1.0 - _dampFactor[i]));
- } // of axis iteration
-
- dt -= interval;
- } // of dt subdivision by interval
-}
-
-double
-FGViewer::get_h_fov()
-{
- double aspectRatio = _cameraGroup->getMasterAspectRatio();
- switch (_scaling_type) {
- case FG_SCALING_WIDTH: // h_fov == fov
- return _fov_deg;
- case FG_SCALING_MAX:
- if (aspectRatio < 1.0) {
- // h_fov == fov
- return _fov_deg;
- } else {
- // v_fov == fov
- return
- atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
- / (aspectRatio*_aspect_ratio_multiplier))
- * SG_RADIANS_TO_DEGREES * 2;
- }
- default:
- assert(false);
- }
- return 0.0;
-}
-
-
-
-double
-FGViewer::get_v_fov()
-{
- double aspectRatio = _cameraGroup->getMasterAspectRatio();
- switch (_scaling_type) {
- case FG_SCALING_WIDTH: // h_fov == fov
- return
- atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
- * (aspectRatio*_aspect_ratio_multiplier))
- * SG_RADIANS_TO_DEGREES * 2;
- case FG_SCALING_MAX:
- if (aspectRatio < 1.0) {
- // h_fov == fov
- return
- atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
- * (aspectRatio*_aspect_ratio_multiplier))
- * SG_RADIANS_TO_DEGREES * 2;
- } else {
- // v_fov == fov
- return _fov_deg;
- }
- default:
- assert(false);
- }
- return 0.0;
-}
-
-void
-FGViewer::update (double dt)
-{
- updateDampOutput(dt);
-
- int i;
- int dt_ms = int(dt * 1000);
- for ( i = 0; i < dt_ms; i++ ) {
- if ( fabs( _goal_heading_offset_deg - _heading_offset_deg) < 1 ) {
- setHeadingOffset_deg( _goal_heading_offset_deg );
- break;
- } else {
- // move current_view.headingoffset towards
- // current_view.goal_view_offset
- if ( _goal_heading_offset_deg > _heading_offset_deg )
- {
- if ( _goal_heading_offset_deg - _heading_offset_deg < 180 ){
- incHeadingOffset_deg( 0.5 );
- } else {
- incHeadingOffset_deg( -0.5 );
- }
- } else {
- if ( _heading_offset_deg - _goal_heading_offset_deg < 180 ){
- incHeadingOffset_deg( -0.5 );
- } else {
- incHeadingOffset_deg( 0.5 );
- }
- }
- if ( _heading_offset_deg > 360 ) {
- incHeadingOffset_deg( -360 );
- } else if ( _heading_offset_deg < 0 ) {
- incHeadingOffset_deg( 360 );
- }
- }
- }
-
- for ( i = 0; i < dt_ms; i++ ) {
- if ( fabs( _goal_pitch_offset_deg - _pitch_offset_deg ) < 1 ) {
- setPitchOffset_deg( _goal_pitch_offset_deg );
- break;
- } else {
- // move current_view.pitch_offset_deg towards
- // current_view.goal_pitch_offset
- if ( _goal_pitch_offset_deg > _pitch_offset_deg )
- {
- incPitchOffset_deg( 1.0 );
- } else {
- incPitchOffset_deg( -1.0 );
- }
- if ( _pitch_offset_deg > 90 ) {
- setPitchOffset_deg(90);
- } else if ( _pitch_offset_deg < -90 ) {
- setPitchOffset_deg( -90 );
- }
- }
- }
-
-
- for ( i = 0; i < dt_ms; i++ ) {
- if ( fabs( _goal_roll_offset_deg - _roll_offset_deg ) < 1 ) {
- setRollOffset_deg( _goal_roll_offset_deg );
- break;
- } else {
- // move current_view.roll_offset_deg towards
- // current_view.goal_roll_offset
- if ( _goal_roll_offset_deg > _roll_offset_deg )
- {
- incRollOffset_deg( 1.0 );
- } else {
- incRollOffset_deg( -1.0 );
- }
- if ( _roll_offset_deg > 90 ) {
- setRollOffset_deg(90);
- } else if ( _roll_offset_deg < -90 ) {
- setRollOffset_deg( -90 );
- }
- }
- }
- recalc();
- if( fgGetBool( "/sim/rendering/draw-otw", true ) ) {
- _cameraGroup->update(toOsg(_absolute_view_pos), toOsg(mViewOrientation));
- _cameraGroup->setCameraParameters(get_v_fov(), get_aspect_ratio());
- }
-}
-
-double FGViewer::get_aspect_ratio() const
-{
- return _cameraGroup->getMasterAspectRatio();
-}
+++ /dev/null
-// viewer.hxx -- class for managing a viewer in the flightgear world.
-//
-// Written by Curtis Olson, started August 1997.
-// overhaul started October 2000.
-// partially rewritten by Jim Wilson jim@kelcomaine.com using interface
-// by David Megginson March 2002
-//
-// Copyright (C) 1997 - 2000 Curtis L. Olson - http://www.flightgear.org/~curt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program 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 GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// $Id$
-
-
-#ifndef _VIEWER_HXX
-#define _VIEWER_HXX
-
-namespace flightgear
-{
-class CameraGroup;
-}
-
-#include <osg/ref_ptr>
-
-#include <simgear/compiler.h>
-#include <simgear/constants.h>
-#include <simgear/structure/subsystem_mgr.hxx>
-#include <simgear/math/SGMath.hxx>
-
-#define FG_FOV_MIN 0.1
-#define FG_FOV_MAX 179.9
-
-enum fgViewType {
- FG_LOOKFROM = 0,
- FG_LOOKAT = 1
-};
-
-// Define a structure containing view information
-class FGViewer : public SGSubsystem {
-
-public:
-
- enum fgScalingType { // nominal Field Of View actually applies to ...
- FG_SCALING_WIDTH, // window width
- FG_SCALING_MAX // max(width, height)
- // FG_SCALING_G_MEAN, // geometric_mean(width, height)
- // FG_SCALING_INDEPENDENT // whole screen
- };
-
- // Constructor
- FGViewer( fgViewType Type, bool from_model, int from_model_index,
- bool at_model, int at_model_index,
- double damp_roll, double damp_pitch, double damp_heading,
- double x_offset_m, double y_offset_m, double z_offset_m,
- double heading_offset_deg, double pitch_offset_deg,
- double roll_offset_deg,
- double fov_deg, double aspect_ratio_multiplier,
- double target_x_offset_m, double target_y_offset_m,
- double target_z_offset_m, double near_m, bool internal );
-
- // Destructor
- virtual ~FGViewer( void );
-
- //////////////////////////////////////////////////////////////////////
- // Part 1: standard SGSubsystem implementation.
- //////////////////////////////////////////////////////////////////////
-
- virtual void init ();
- virtual void bind ();
- virtual void unbind ();
- void update (double dt);
-
-
- //////////////////////////////////////////////////////////////////////
- // Part 2: user settings.
- //////////////////////////////////////////////////////////////////////
-
- virtual fgViewType getType() const { return _type; }
- virtual void setType( int type );
-
- virtual bool getInternal() const { return _internal; }
- virtual void setInternal( bool internal );
-
- // Reference geodetic position of view from position...
- // These are the actual aircraft position (pilot in
- // pilot view, model in model view).
- // FIXME: the model view position (ie target positions)
- // should be in the model class.
- virtual void setPosition (double lon_deg, double lat_deg, double alt_ft);
- const SGGeod& getPosition() const { return _position; }
-
- // Reference geodetic target position...
- virtual void setTargetPosition (double lon_deg, double lat_deg, double alt_ft);
- const SGGeod& getTargetPosition() const { return _target; }
-
-
-
- // Position offsets from reference
- // These offsets position they "eye" in the scene according to a given
- // location. For example in pilot view they are used to position the
- // head inside the aircraft.
- // Note that in pilot view these are applied "before" the orientation
- // rotations (see below) so that the orientation rotations have the
- // effect of the pilot staying in his seat and "looking out" in
- // different directions.
- // In chase view these are applied "after" the application of the
- // orientation rotations listed below. This has the effect of the
- // eye moving around and "looking at" the object (model) from
- // different angles.
- virtual SGVec3d getOffset_m () const { return _offset_m; }
- virtual double getXOffset_m () const { return _offset_m.x(); }
- virtual double getYOffset_m () const { return _offset_m.y(); }
- virtual double getZOffset_m () const { return _offset_m.z(); }
- virtual double getTargetXOffset_m () const { return _target_offset_m.x(); }
- virtual double getTargetYOffset_m () const { return _target_offset_m.y(); }
- virtual double getTargetZOffset_m () const { return _target_offset_m.z(); }
- virtual void setXOffset_m (double x_offset_m);
- virtual void setYOffset_m (double y_offset_m);
- virtual void setZOffset_m (double z_offset_m);
- virtual void setTargetXOffset_m (double x_offset_m);
- virtual void setTargetYOffset_m (double y_offset_m);
- virtual void setTargetZOffset_m (double z_offset_m);
- virtual void setPositionOffsets (double x_offset_m,
- double y_offset_m,
- double z_offset_m);
-
-
-
-
- // Reference orientation rotations...
- // These are rotations that represent the plane attitude effect on
- // the view (in Pilot view). IE The view frustrum rotates as the plane
- // turns, pitches, and rolls.
- // In model view (lookat/chaseview) these end up changing the angle that
- // the eye is looking at the ojbect (ie the model).
- // FIXME: the FGModel class should have its own version of these so that
- // it can generate it's own model rotations.
- virtual double getRoll_deg () const { return _roll_deg; }
- virtual double getPitch_deg () const {return _pitch_deg; }
- virtual double getHeading_deg () const {return _heading_deg; }
- virtual void setRoll_deg (double roll_deg);
- virtual void setPitch_deg (double pitch_deg);
- virtual void setHeading_deg (double heading_deg);
- virtual void setOrientation (double roll_deg, double pitch_deg, double heading_deg);
- virtual double getTargetRoll_deg () const { return _target_roll_deg; }
- virtual double getTargetPitch_deg () const {return _target_pitch_deg; }
- virtual double getTargetHeading_deg () const {return _target_heading_deg; }
- virtual void setTargetRoll_deg (double roll_deg);
- virtual void setTargetPitch_deg (double pitch_deg);
- virtual void setTargetHeading_deg (double heading_deg);
- virtual void setTargetOrientation (double roll_deg, double pitch_deg, double heading_deg);
-
-
-
-
- // Orientation offsets rotations from reference orientation.
- // Goal settings are for smooth transition from prior
- // offset when changing view direction.
- // These offsets are in ADDITION to the orientation rotations listed
- // above.
- // In pilot view they are applied after the position offsets in order to
- // give the effect of the pilot looking around.
- // In lookat view they are applied before the position offsets so that
- // the effect is the eye moving around looking at the object (ie the model)
- // from different angles.
- virtual double getRollOffset_deg () const { return _roll_offset_deg; }
- virtual double getPitchOffset_deg () const { return _pitch_offset_deg; }
- virtual double getHeadingOffset_deg () const { return _heading_offset_deg; }
- virtual double getGoalRollOffset_deg () const { return _goal_roll_offset_deg; }
- virtual double getGoalPitchOffset_deg () const { return _goal_pitch_offset_deg; }
- virtual double getGoalHeadingOffset_deg () const {return _goal_heading_offset_deg; }
- virtual void setRollOffset_deg (double roll_offset_deg);
- virtual void setPitchOffset_deg (double pitch_offset_deg);
- virtual void setHeadingOffset_deg (double heading_offset_deg);
- virtual void setGoalRollOffset_deg (double goal_roll_offset_deg);
- virtual void setGoalPitchOffset_deg (double goal_pitch_offset_deg);
- virtual void setGoalHeadingOffset_deg (double goal_heading_offset_deg);
- virtual void setOrientationOffsets (double roll_offset_deg,
- double heading_offset_deg,
- double pitch_offset_deg);
-
-
-
- //////////////////////////////////////////////////////////////////////
- // Part 3: output vectors and matrices in FlightGear coordinates.
- //////////////////////////////////////////////////////////////////////
-
- // Vectors and positions...
-
- const SGVec3d& get_view_pos() { if ( _dirty ) { recalc(); } return _absolute_view_pos; }
- const SGVec3d& getViewPosition() { if ( _dirty ) { recalc(); } return _absolute_view_pos; }
- const SGQuatd& getViewOrientation() { if ( _dirty ) { recalc(); } return mViewOrientation; }
- const SGQuatd& getViewOrientationOffset() { if ( _dirty ) { recalc(); } return mViewOffsetOr; }
-
- //////////////////////////////////////////////////////////////////////
- // Part 4: View and frustrum data setters and getters
- //////////////////////////////////////////////////////////////////////
-
- virtual void set_fov( double fov_deg ) {
- _fov_deg = fov_deg;
- }
- virtual double get_fov() const { return _fov_deg; }
- virtual double get_h_fov(); // Get horizontal fov, in degrees.
- virtual double get_v_fov(); // Get vertical fov, in degrees.
-
- virtual double get_aspect_ratio() const;
-
- virtual void set_aspect_ratio_multiplier( double m ) {
- _aspect_ratio_multiplier = m;
- }
- virtual double get_aspect_ratio_multiplier() const {
- return _aspect_ratio_multiplier;
- }
-
- virtual double getNear_m () const { return _ground_level_nearplane_m; }
- inline void setNear_m (double near_m) {
- _ground_level_nearplane_m = near_m;
- }
-
- //////////////////////////////////////////////////////////////////////
- // Part 5: misc setters and getters
- //////////////////////////////////////////////////////////////////////
-
- inline void set_dirty() { _dirty = true; }
- inline void set_clean() { _dirty = false; }
-
-private:
-
- //////////////////////////////////////////////////////////////////
- // private data //
- //////////////////////////////////////////////////////////////////
-
- // flag forcing a recalc of derived view parameters
- bool _dirty;
-
- SGQuatd mViewOrientation;
- SGQuatd mViewOffsetOr;
- SGVec3d _absolute_view_pos;
-
- SGGeod _position;
- SGGeod _target;
-
- double _roll_deg;
- double _pitch_deg;
- double _heading_deg;
- double _target_roll_deg;
- double _target_pitch_deg;
- double _target_heading_deg;
-
- SGVec3d _dampTarget; ///< current target value we are damping towards
- SGVec3d _dampOutput; ///< current output of damping filter
- SGVec3d _dampFactor; ///< weighting of the damping filter
-
- // Position offsets from FDM origin. The X axis is positive
- // out the tail, Y is out the right wing, and Z is positive up.
- // distance in meters
- SGVec3d _offset_m;
-
- // Target offsets from FDM origin (for "lookat" targets) The X
- // axis is positive out the tail, Y is out the right wing, and Z
- // is positive up. distance in meters
- SGVec3d _target_offset_m;
-
-
- // orientation offsets from reference (_goal* are for smoothed transitions)
- double _roll_offset_deg;
- double _pitch_offset_deg;
- double _heading_offset_deg;
- double _goal_roll_offset_deg;
- double _goal_pitch_offset_deg;
- double _goal_heading_offset_deg;
-
- // used to set nearplane when at ground level for this view
- double _ground_level_nearplane_m;
-
- fgViewType _type;
- fgScalingType _scaling_type;
-
- // internal view (e.g. cockpit) flag
- bool _internal;
-
- // view is looking from a model
- bool _from_model;
- int _from_model_index; // number of model (for multi model)
-
- // view is looking at a model
- bool _at_model;
- int _at_model_index; // number of model (for multi model)
-
- // the nominal field of view (angle, in degrees)
- double _fov_deg;
-
- // default = 1.0, this value is user configurable and is
- // multiplied into the aspect_ratio to get the actual vertical fov
- double _aspect_ratio_multiplier;
-
- // camera group controled by this view
- osg::ref_ptr<flightgear::CameraGroup> _cameraGroup;
- //////////////////////////////////////////////////////////////////
- // private functions //
- //////////////////////////////////////////////////////////////////
-
- void recalc ();
- void recalcLookFrom();
- void recalcLookAt();
-
- void setDampTarget(double h, double p, double r);
- void getDampOutput(double& roll, double& pitch, double& heading);
-
- void updateDampOutput(double dt);
-
- // add to _heading_offset_deg
- inline void incHeadingOffset_deg( double amt ) {
- set_dirty();
- _heading_offset_deg += amt;
- }
-
- // add to _pitch_offset_deg
- inline void incPitchOffset_deg( double amt ) {
- set_dirty();
- _pitch_offset_deg += amt;
- }
-
- // add to _roll_offset_deg
- inline void incRollOffset_deg( double amt ) {
- set_dirty();
- _roll_offset_deg += amt;
- }
-
-};
-
-
-#endif // _VIEWER_HXX
+++ /dev/null
-// viewmgr.cxx -- class for managing all the views in the flightgear world.
-//
-// Written by Curtis Olson, started October 2000.
-// partially rewritten by Jim Wilson March 2002
-//
-// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program 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 GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// $Id$
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "viewmgr.hxx"
-
-#include <string.h> // strcmp
-
-#include <simgear/compiler.h>
-#include <simgear/sound/soundmgr_openal.hxx>
-#include <Model/acmodel.hxx>
-#include <Main/viewer.hxx>
-#include <Main/fg_props.hxx>
-
-// Constructor
-FGViewMgr::FGViewMgr( void ) :
- axis_long(0),
- axis_lat(0),
- inited(false),
- view_number(fgGetNode("/sim/current-view/view-number", true)),
- config_list(fgGetNode("/sim", true)->getChildren("view")),
- abs_viewer_position(SGVec3d::zeros()),
- current(0),
- current_view_orientation(SGQuatd::zeros()),
- current_view_or_offset(SGQuatd::zeros()),
- smgr(globals->get_soundmgr())
-{
-}
-
-// Destructor
-FGViewMgr::~FGViewMgr( void ) {
-}
-
-void
-FGViewMgr::init ()
-{
- if (inited) {
- SG_LOG(SG_VIEW, SG_WARN, "duplicate init of view manager");
- return;
- }
-
- inited = true;
-
- double aspect_ratio_multiplier
- = fgGetDouble("/sim/current-view/aspect-ratio-multiplier");
-
- for (unsigned int i = 0; i < config_list.size(); i++) {
- SGPropertyNode *n = config_list[i];
-
- // find out if this is an internal view (e.g. in cockpit, low near plane)
- bool internal = n->getBoolValue("internal", false);
-
- // FIXME:
- // this is assumed to be an aircraft model...we will need to read
- // model-from-type as well.
-
- // find out if this is a model we are looking from...
- bool from_model = n->getBoolValue("config/from-model");
- int from_model_index = n->getIntValue("config/from-model-idx");
-
- double x_offset_m = n->getDoubleValue("config/x-offset-m");
- double y_offset_m = n->getDoubleValue("config/y-offset-m");
- double z_offset_m = n->getDoubleValue("config/z-offset-m");
-
- double heading_offset_deg = n->getDoubleValue("config/heading-offset-deg");
- n->setDoubleValue("config/heading-offset-deg", heading_offset_deg);
- double pitch_offset_deg = n->getDoubleValue("config/pitch-offset-deg");
- n->setDoubleValue("config/pitch-offset-deg", pitch_offset_deg);
- double roll_offset_deg = n->getDoubleValue("config/roll-offset-deg");
- n->setDoubleValue("config/roll-offset-deg", roll_offset_deg);
-
- double fov_deg = n->getDoubleValue("config/default-field-of-view-deg");
- double near_m = n->getDoubleValue("config/ground-level-nearplane-m");
-
- // supporting two types "lookat" = 1 and "lookfrom" = 0
- const char *type = n->getStringValue("type");
- if (!strcmp(type, "lookat")) {
-
- bool at_model = n->getBoolValue("config/at-model");
- int at_model_index = n->getIntValue("config/at-model-idx");
-
- double damp_roll = n->getDoubleValue("config/at-model-roll-damping");
- double damp_pitch = n->getDoubleValue("config/at-model-pitch-damping");
- double damp_heading = n->getDoubleValue("config/at-model-heading-damping");
-
- double target_x_offset_m = n->getDoubleValue("config/target-x-offset-m");
- double target_y_offset_m = n->getDoubleValue("config/target-y-offset-m");
- double target_z_offset_m = n->getDoubleValue("config/target-z-offset-m");
-
- add_view(new FGViewer ( FG_LOOKAT, from_model, from_model_index,
- at_model, at_model_index,
- damp_roll, damp_pitch, damp_heading,
- x_offset_m, y_offset_m,z_offset_m,
- heading_offset_deg, pitch_offset_deg,
- roll_offset_deg, fov_deg, aspect_ratio_multiplier,
- target_x_offset_m, target_y_offset_m,
- target_z_offset_m, near_m, internal ));
- } else {
- add_view(new FGViewer ( FG_LOOKFROM, from_model, from_model_index,
- false, 0, 0.0, 0.0, 0.0,
- x_offset_m, y_offset_m, z_offset_m,
- heading_offset_deg, pitch_offset_deg,
- roll_offset_deg, fov_deg, aspect_ratio_multiplier,
- 0, 0, 0, near_m, internal ));
- }
- }
-
- copyToCurrent();
- do_bind();
-}
-
-void
-FGViewMgr::reinit ()
-{
- // reset offsets and fov to configuration defaults
- for (unsigned int i = 0; i < config_list.size(); i++) {
- SGPropertyNode *n = config_list[i];
- setView(i);
-
- fgSetDouble("/sim/current-view/x-offset-m",
- n->getDoubleValue("config/x-offset-m"));
- fgSetDouble("/sim/current-view/y-offset-m",
- n->getDoubleValue("config/y-offset-m"));
- fgSetDouble("/sim/current-view/z-offset-m",
- n->getDoubleValue("config/z-offset-m"));
- fgSetDouble("/sim/current-view/pitch-offset-deg",
- n->getDoubleValue("config/pitch-offset-deg"));
- fgSetDouble("/sim/current-view/heading-offset-deg",
- n->getDoubleValue("config/heading-offset-deg"));
- fgSetDouble("/sim/current-view/roll-offset-deg",
- n->getDoubleValue("config/roll-offset-deg"));
-
- double fov_deg = n->getDoubleValue("config/default-field-of-view-deg");
- if (fov_deg < 10.0)
- fov_deg = 55.0;
- fgSetDouble("/sim/current-view/field-of-view", fov_deg);
-
- // target offsets for lookat mode only...
- fgSetDouble("/sim/current-view/target-x-offset-m",
- n->getDoubleValue("config/target-x-offset-m"));
- fgSetDouble("/sim/current-view/target-y-offset-m",
- n->getDoubleValue("config/target-y-offset-m"));
- fgSetDouble("/sim/current-view/target-z-offset-m",
- n->getDoubleValue("config/target-z-offset-m"));
- }
- setView(0);
-}
-
-typedef double (FGViewMgr::*double_getter)() const;
-
-void
-FGViewMgr::bind()
-{
- // view-manager code was designed to init before bind, so
- // this is a no-op; init() calls the real bind() impl below
-}
-
-void
-FGViewMgr::do_bind()
-{
- // these are bound to the current view properties
- _tiedProperties.setRoot(fgGetNode("/sim/current-view", true));
- _tiedProperties.Tie("heading-offset-deg", this,
- &FGViewMgr::getViewHeadingOffset_deg,
- &FGViewMgr::setViewHeadingOffset_deg);
- fgSetArchivable("/sim/current-view/heading-offset-deg");
- _tiedProperties.Tie("goal-heading-offset-deg", this,
- &FGViewMgr::getViewGoalHeadingOffset_deg,
- &FGViewMgr::setViewGoalHeadingOffset_deg);
- fgSetArchivable("/sim/current-view/goal-heading-offset-deg");
- _tiedProperties.Tie("pitch-offset-deg", this,
- &FGViewMgr::getViewPitchOffset_deg,
- &FGViewMgr::setViewPitchOffset_deg);
- fgSetArchivable("/sim/current-view/pitch-offset-deg");
- _tiedProperties.Tie("goal-pitch-offset-deg", this,
- &FGViewMgr::getGoalViewPitchOffset_deg,
- &FGViewMgr::setGoalViewPitchOffset_deg);
- fgSetArchivable("/sim/current-view/goal-pitch-offset-deg");
- _tiedProperties.Tie("roll-offset-deg", this,
- &FGViewMgr::getViewRollOffset_deg,
- &FGViewMgr::setViewRollOffset_deg);
- fgSetArchivable("/sim/current-view/roll-offset-deg");
- _tiedProperties.Tie("goal-roll-offset-deg", this,
- &FGViewMgr::getGoalViewRollOffset_deg,
- &FGViewMgr::setGoalViewRollOffset_deg);
- fgSetArchivable("/sim/current-view/goal-roll-offset-deg");
-
- _tiedProperties.Tie("view-number", this,
- &FGViewMgr::getView, &FGViewMgr::setView);
- fgSetArchivable("/sim/current-view/view-number", false);
-
- _tiedProperties.Tie("axes/long", this,
- (double_getter)0, &FGViewMgr::setViewAxisLong);
- fgSetArchivable("/sim/current-view/axes/long");
-
- _tiedProperties.Tie("axes/lat", this,
- (double_getter)0, &FGViewMgr::setViewAxisLat);
- fgSetArchivable("/sim/current-view/axes/lat");
-
- _tiedProperties.Tie("field-of-view", this,
- &FGViewMgr::getFOV_deg, &FGViewMgr::setFOV_deg);
- fgSetArchivable("/sim/current-view/field-of-view");
-
- _tiedProperties.Tie("aspect-ratio-multiplier", this,
- &FGViewMgr::getARM_deg, &FGViewMgr::setARM_deg);
- fgSetArchivable("/sim/current-view/field-of-view");
-
- _tiedProperties.Tie("ground-level-nearplane-m", this,
- &FGViewMgr::getNear_m, &FGViewMgr::setNear_m);
- fgSetArchivable("/sim/current-view/ground-level-nearplane-m");
-
- SGPropertyNode *n = fgGetNode("/sim/current-view", true);
- _tiedProperties.Tie(n->getNode("viewer-x-m", true),SGRawValuePointer<double>(&abs_viewer_position[0]));
- _tiedProperties.Tie(n->getNode("viewer-y-m", true),SGRawValuePointer<double>(&abs_viewer_position[1]));
- _tiedProperties.Tie(n->getNode("viewer-z-m", true),SGRawValuePointer<double>(&abs_viewer_position[2]));
-
- _tiedProperties.Tie("debug/orientation-w", this,
- &FGViewMgr::getCurrentViewOrientation_w);
- _tiedProperties.Tie("debug/orientation-x", this,
- &FGViewMgr::getCurrentViewOrientation_x);
- _tiedProperties.Tie("debug/orientation-y", this,
- &FGViewMgr::getCurrentViewOrientation_y);
- _tiedProperties.Tie("debug/orientation-z", this,
- &FGViewMgr::getCurrentViewOrientation_z);
-
- _tiedProperties.Tie("debug/orientation_offset-w", this,
- &FGViewMgr::getCurrentViewOrOffset_w);
- _tiedProperties.Tie("debug/orientation_offset-x", this,
- &FGViewMgr::getCurrentViewOrOffset_x);
- _tiedProperties.Tie("debug/orientation_offset-y", this,
- &FGViewMgr::getCurrentViewOrOffset_y);
- _tiedProperties.Tie("debug/orientation_offset-z", this,
- &FGViewMgr::getCurrentViewOrOffset_z);
-
- _tiedProperties.Tie("debug/frame-w", this,
- &FGViewMgr::getCurrentViewFrame_w);
- _tiedProperties.Tie("debug/frame-x", this,
- &FGViewMgr::getCurrentViewFrame_x);
- _tiedProperties.Tie("debug/frame-y", this,
- &FGViewMgr::getCurrentViewFrame_y);
- _tiedProperties.Tie("debug/frame-z", this,
- &FGViewMgr::getCurrentViewFrame_z);
-}
-
-void
-FGViewMgr::unbind ()
-{
- _tiedProperties.Untie();
-}
-
-void
-FGViewMgr::update (double dt)
-{
- FGViewer *loop_view = (FGViewer *)get_current_view();
- if (loop_view == 0) return;
-
- SGPropertyNode *n = config_list[current];
- double lon_deg, lat_deg, alt_ft, roll_deg, pitch_deg, heading_deg;
-
- // Set up view location and orientation
-
- if (!n->getBoolValue("config/from-model")) {
- lon_deg = fgGetDouble(n->getStringValue("config/eye-lon-deg-path"));
- lat_deg = fgGetDouble(n->getStringValue("config/eye-lat-deg-path"));
- alt_ft = fgGetDouble(n->getStringValue("config/eye-alt-ft-path"));
- roll_deg = fgGetDouble(n->getStringValue("config/eye-roll-deg-path"));
- pitch_deg = fgGetDouble(n->getStringValue("config/eye-pitch-deg-path"));
- heading_deg = fgGetDouble(n->getStringValue("config/eye-heading-deg-path"));
-
- loop_view->setPosition(lon_deg, lat_deg, alt_ft);
- loop_view->setOrientation(roll_deg, pitch_deg, heading_deg);
- } else {
- // force recalc in viewer
- loop_view->set_dirty();
- }
-
- // if lookat (type 1) then get target data...
- if (loop_view->getType() == FG_LOOKAT) {
- if (!n->getBoolValue("config/from-model")) {
- lon_deg = fgGetDouble(n->getStringValue("config/target-lon-deg-path"));
- lat_deg = fgGetDouble(n->getStringValue("config/target-lat-deg-path"));
- alt_ft = fgGetDouble(n->getStringValue("config/target-alt-ft-path"));
- roll_deg = fgGetDouble(n->getStringValue("config/target-roll-deg-path"));
- pitch_deg = fgGetDouble(n->getStringValue("config/target-pitch-deg-path"));
- heading_deg = fgGetDouble(n->getStringValue("config/target-heading-deg-path"));
-
- loop_view->setTargetPosition(lon_deg, lat_deg, alt_ft);
- loop_view->setTargetOrientation(roll_deg, pitch_deg, heading_deg);
- } else {
- loop_view->set_dirty();
- }
- }
-
- setViewXOffset_m(fgGetDouble("/sim/current-view/x-offset-m"));
- setViewYOffset_m(fgGetDouble("/sim/current-view/y-offset-m"));
- setViewZOffset_m(fgGetDouble("/sim/current-view/z-offset-m"));
-
- setViewTargetXOffset_m(fgGetDouble("/sim/current-view/target-x-offset-m"));
- setViewTargetYOffset_m(fgGetDouble("/sim/current-view/target-y-offset-m"));
- setViewTargetZOffset_m(fgGetDouble("/sim/current-view/target-z-offset-m"));
-
- current_view_orientation = loop_view->getViewOrientation();
- current_view_or_offset = loop_view->getViewOrientationOffset();
-
- // Update the current view
- do_axes();
- loop_view->update(dt);
- abs_viewer_position = loop_view->getViewPosition();
-
- // update audio listener values
- // set the viewer position in Cartesian coordinates in meters
- smgr->set_position( abs_viewer_position, loop_view->getPosition() );
- smgr->set_orientation( current_view_orientation );
-
- // get the model velocity
- SGVec3d velocity = SGVec3d::zeros();
- if ( !stationary() ) {
- velocity = globals->get_aircraft_model()->getVelocity();
- }
- smgr->set_velocity( velocity );
-}
-
-void
-FGViewMgr::copyToCurrent()
-{
- if (!inited) {
- return;
- }
-
- SGPropertyNode *n = config_list[current];
- fgSetString("/sim/current-view/name", n->getStringValue("name"));
- fgSetString("/sim/current-view/type", n->getStringValue("type"));
-
- // copy certain view config data for default values
- fgSetDouble("/sim/current-view/config/heading-offset-deg",
- n->getDoubleValue("config/default-heading-offset-deg"));
- fgSetDouble("/sim/current-view/config/pitch-offset-deg",
- n->getDoubleValue("config/pitch-offset-deg"));
- fgSetDouble("/sim/current-view/config/roll-offset-deg",
- n->getDoubleValue("config/roll-offset-deg"));
- fgSetDouble("/sim/current-view/config/default-field-of-view-deg",
- n->getDoubleValue("config/default-field-of-view-deg"));
- fgSetBool("/sim/current-view/config/from-model",
- n->getBoolValue("config/from-model"));
-
- // copy view data
- fgSetDouble("/sim/current-view/x-offset-m", getViewXOffset_m());
- fgSetDouble("/sim/current-view/y-offset-m", getViewYOffset_m());
- fgSetDouble("/sim/current-view/z-offset-m", getViewZOffset_m());
-
- fgSetDouble("/sim/current-view/goal-heading-offset-deg",
- get_current_view()->getGoalHeadingOffset_deg());
- fgSetDouble("/sim/current-view/goal-pitch-offset-deg",
- get_current_view()->getGoalPitchOffset_deg());
- fgSetDouble("/sim/current-view/goal-roll-offset-deg",
- get_current_view()->getRollOffset_deg());
- fgSetDouble("/sim/current-view/heading-offset-deg",
- get_current_view()->getHeadingOffset_deg());
- fgSetDouble("/sim/current-view/pitch-offset-deg",
- get_current_view()->getPitchOffset_deg());
- fgSetDouble("/sim/current-view/roll-offset-deg",
- get_current_view()->getRollOffset_deg());
- fgSetDouble("/sim/current-view/target-x-offset-m",
- get_current_view()->getTargetXOffset_m());
- fgSetDouble("/sim/current-view/target-y-offset-m",
- get_current_view()->getTargetYOffset_m());
- fgSetDouble("/sim/current-view/target-z-offset-m",
- get_current_view()->getTargetZOffset_m());
- fgSetBool("/sim/current-view/internal",
- get_current_view()->getInternal());
-}
-
-void FGViewMgr::clear()
-{
- views.clear();
-}
-
-FGViewer*
-FGViewMgr::get_current_view()
-{
- if ( current < (int)views.size() ) {
- return views[current];
- } else {
- return NULL;
- }
-}
-
-const FGViewer*
-FGViewMgr::get_current_view() const
-{
- if ( current < (int)views.size() ) {
- return views[current];
- } else {
- return NULL;
- }
-}
-
-
-FGViewer*
-FGViewMgr::get_view( int i )
-{
- if ( i < 0 ) { i = 0; }
- if ( i >= (int)views.size() ) { i = views.size() - 1; }
- return views[i];
-}
-
-const FGViewer*
-FGViewMgr::get_view( int i ) const
-{
- if ( i < 0 ) { i = 0; }
- if ( i >= (int)views.size() ) { i = views.size() - 1; }
- return views[i];
-}
-
-FGViewer*
-FGViewMgr::next_view()
-{
- setView((current+1 < (int)views.size()) ? (current + 1) : 0);
- view_number->fireValueChanged();
- return views[current];
-}
-
-FGViewer*
-FGViewMgr::prev_view()
-{
- setView((0 < current) ? (current - 1) : (views.size() - 1));
- view_number->fireValueChanged();
- return views[current];
-}
-
-void
-FGViewMgr::add_view( FGViewer * v )
-{
- views.push_back(v);
- v->init();
-}
-
-double
-FGViewMgr::getViewHeadingOffset_deg () const
-{
- const FGViewer * view = get_current_view();
- return (view == 0 ? 0 : view->getHeadingOffset_deg());
-}
-
-void
-FGViewMgr::setViewHeadingOffset_deg (double offset)
-{
- FGViewer * view = get_current_view();
- if (view != 0) {
- view->setGoalHeadingOffset_deg(offset);
- view->setHeadingOffset_deg(offset);
- }
-}
-
-double
-FGViewMgr::getViewGoalHeadingOffset_deg () const
-{
- const FGViewer * view = get_current_view();
- return (view == 0 ? 0 : view->getGoalHeadingOffset_deg());
-}
-
-void
-FGViewMgr::setViewGoalHeadingOffset_deg (double offset)
-{
- FGViewer * view = get_current_view();
- if (view != 0)
- view->setGoalHeadingOffset_deg(offset);
-}
-
-double
-FGViewMgr::getViewPitchOffset_deg () const
-{
- const FGViewer * view = get_current_view();
- return (view == 0 ? 0 : view->getPitchOffset_deg());
-}
-
-void
-FGViewMgr::setViewPitchOffset_deg (double tilt)
-{
- FGViewer * view = get_current_view();
- if (view != 0) {
- view->setGoalPitchOffset_deg(tilt);
- view->setPitchOffset_deg(tilt);
- }
-}
-
-double
-FGViewMgr::getGoalViewPitchOffset_deg () const
-{
- const FGViewer * view = get_current_view();
- return (view == 0 ? 0 : view->getGoalPitchOffset_deg());
-}
-
-void
-FGViewMgr::setGoalViewPitchOffset_deg (double tilt)
-{
- FGViewer * view = get_current_view();
- if (view != 0)
- view->setGoalPitchOffset_deg(tilt);
-}
-
-double
-FGViewMgr::getViewRollOffset_deg () const
-{
- const FGViewer * view = get_current_view();
- return (view == 0 ? 0 : view->getRollOffset_deg());
-}
-
-void
-FGViewMgr::setViewRollOffset_deg (double tilt)
-{
- FGViewer * view = get_current_view();
- if (view != 0) {
- view->setGoalRollOffset_deg(tilt);
- view->setRollOffset_deg(tilt);
- }
-}
-
-double
-FGViewMgr::getGoalViewRollOffset_deg () const
-{
- const FGViewer * view = get_current_view();
- return (view == 0 ? 0 : view->getGoalRollOffset_deg());
-}
-
-void
-FGViewMgr::setGoalViewRollOffset_deg (double tilt)
-{
- FGViewer * view = get_current_view();
- if (view != 0)
- view->setGoalRollOffset_deg(tilt);
-}
-
-double
-FGViewMgr::getViewXOffset_m () const
-{
- const FGViewer * view = get_current_view();
- if (view != 0) {
- return ((FGViewer *)view)->getXOffset_m();
- } else {
- return 0;
- }
-}
-
-void
-FGViewMgr::setViewXOffset_m (double x)
-{
- FGViewer * view = get_current_view();
- if (view != 0) {
- view->setXOffset_m(x);
- }
-}
-
-double
-FGViewMgr::getViewYOffset_m () const
-{
- const FGViewer * view = get_current_view();
- if (view != 0) {
- return ((FGViewer *)view)->getYOffset_m();
- } else {
- return 0;
- }
-}
-
-void
-FGViewMgr::setViewYOffset_m (double y)
-{
- FGViewer * view = get_current_view();
- if (view != 0) {
- view->setYOffset_m(y);
- }
-}
-
-double
-FGViewMgr::getViewZOffset_m () const
-{
- const FGViewer * view = get_current_view();
- if (view != 0) {
- return ((FGViewer *)view)->getZOffset_m();
- } else {
- return 0;
- }
-}
-
-void
-FGViewMgr::setViewZOffset_m (double z)
-{
- FGViewer * view = get_current_view();
- if (view != 0) {
- view->setZOffset_m(z);
- }
-}
-
-bool
-FGViewMgr::stationary () const
-{
- const FGViewer * view = get_current_view();
- if (view != 0) {
- if (((FGViewer *)view)->getXOffset_m() == 0.0 &&
- ((FGViewer *)view)->getYOffset_m() == 0.0 &&
- ((FGViewer *)view)->getZOffset_m() == 0.0)
- return true;
- }
-
- return false;
-}
-
-double
-FGViewMgr::getViewTargetXOffset_m () const
-{
- const FGViewer * view = get_current_view();
- if (view != 0) {
- return ((FGViewer *)view)->getTargetXOffset_m();
- } else {
- return 0;
- }
-}
-
-void
-FGViewMgr::setViewTargetXOffset_m (double x)
-{
- FGViewer * view = get_current_view();
- if (view != 0) {
- view->setTargetXOffset_m(x);
- }
-}
-
-double
-FGViewMgr::getViewTargetYOffset_m () const
-{
- const FGViewer * view = get_current_view();
- if (view != 0) {
- return ((FGViewer *)view)->getTargetYOffset_m();
- } else {
- return 0;
- }
-}
-
-void
-FGViewMgr::setViewTargetYOffset_m (double y)
-{
- FGViewer * view = get_current_view();
- if (view != 0) {
- view->setTargetYOffset_m(y);
- }
-}
-
-double
-FGViewMgr::getViewTargetZOffset_m () const
-{
- const FGViewer * view = get_current_view();
- if (view != 0) {
- return ((FGViewer *)view)->getTargetZOffset_m();
- } else {
- return 0;
- }
-}
-
-void
-FGViewMgr::setViewTargetZOffset_m (double z)
-{
- FGViewer * view = get_current_view();
- if (view != 0) {
- view->setTargetZOffset_m(z);
- }
-}
-
-int
-FGViewMgr::getView () const
-{
- return ( current );
-}
-
-void
-FGViewMgr::setView (int newview)
-{
- // negative numbers -> set view with node index -newview
- if (newview < 0) {
- for (int i = 0; i < (int)config_list.size(); i++) {
- int index = -config_list[i]->getIndex();
- if (index == newview)
- newview = i;
- }
- if (newview < 0)
- return;
- }
-
- // if newview number too low wrap to last view...
- if (newview < 0)
- newview = (int)views.size() - 1;
-
- // if newview number to high wrap to zero...
- if (newview >= (int)views.size())
- newview = 0;
-
- // set new view
- current = newview;
- // copy in view data
- copyToCurrent();
-}
-
-
-double
-FGViewMgr::getFOV_deg () const
-{
- const FGViewer * view = get_current_view();
- return (view == 0 ? 0 : view->get_fov());
-}
-
-void
-FGViewMgr::setFOV_deg (double fov)
-{
- FGViewer * view = get_current_view();
- if (view != 0)
- view->set_fov(fov);
-}
-
-double
-FGViewMgr::getARM_deg () const
-{
- const FGViewer * view = get_current_view();
- return (view == 0 ? 0 : view->get_aspect_ratio_multiplier());
-}
-
-void
-FGViewMgr::setARM_deg (double aspect_ratio_multiplier)
-{
- FGViewer * view = get_current_view();
- if (view != 0)
- view->set_aspect_ratio_multiplier(aspect_ratio_multiplier);
-}
-
-double
-FGViewMgr::getNear_m () const
-{
- const FGViewer * view = get_current_view();
- return (view == 0 ? 0.5f : view->getNear_m());
-}
-
-void
-FGViewMgr::setNear_m (double near_m)
-{
- FGViewer * view = get_current_view();
- if (view != 0)
- view->setNear_m(near_m);
-}
-
-void
-FGViewMgr::setViewAxisLong (double axis)
-{
- axis_long = axis;
-}
-
-void
-FGViewMgr::setViewAxisLat (double axis)
-{
- axis_lat = axis;
-}
-
-// reference frame orientation.
-// This is the view orientation you get when you have no
-// view offset, i.e. the offset operator is the identity.
-//
-// For example, in the familiar "cockpit lookfrom" view,
-// the reference frame is equal to the aircraft attitude,
-// i.e. it is the view looking towards 12:00 straight ahead.
-//
-// FIXME: Somebody needs to figure out what is the reference
-// frame view for the other view modes.
-//
-// Conceptually, this quat represents a rotation relative
-// to the ECEF reference orientation, as described at
-// http://www.av8n.com/physics/coords.htm#sec-orientation
-//
-// See the NOTE concerning reference orientations, below.
-//
-// The components of this quat are expressed in
-// the conventional aviation basis set,
-// i.e. x=forward, y=starboard, z=bottom
-double FGViewMgr::getCurrentViewFrame_w() const{
- return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).w();
-}
-double FGViewMgr::getCurrentViewFrame_x() const{
- return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).x();
-}
-double FGViewMgr::getCurrentViewFrame_y() const{
- return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).y();
-}
-double FGViewMgr::getCurrentViewFrame_z() const{
- return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).z();
-}
-
-
-// view offset.
-// This rotation takes you from the aforementioned
-// reference frame view orientation to whatever
-// actual current view orientation is.
-//
-// The components of this quaternion are expressed in
-// the conventional aviation basis set,
-// i.e. x=forward, y=starboard, z=bottom
-double FGViewMgr::getCurrentViewOrOffset_w() const{
- return current_view_or_offset.w();
-}
-double FGViewMgr::getCurrentViewOrOffset_x() const{
- return current_view_or_offset.x();
-}
-double FGViewMgr::getCurrentViewOrOffset_y() const{
- return current_view_or_offset.y();
-}
-double FGViewMgr::getCurrentViewOrOffset_z() const{
- return current_view_or_offset.z();
-}
-
-
-// current view orientation.
-// This is a rotation relative to the earth-centered (ec)
-// reference frame.
-//
-// NOTE: Here we remove a factor of fsb2sta so that
-// the components of this quat are displayed using the
-// conventional ECEF basis set. This is *not* the way
-// the view orientation is stored in the views[] array,
-// but is easier for non-graphics hackers to understand.
-// If we did not remove this factor of fsb2sta here and
-// in getCurrentViewFrame, that would be equivalent to
-// the following peculiar reference orientation:
-// Suppose you are over the Gulf of Guinea, at (lat,lon) = (0,0).
-// Then the reference frame orientation can be achieved via:
-// -- The aircraft X-axis (nose) headed south.
-// -- The aircraft Y-axis (starboard wingtip) pointing up.
-// -- The aircraft Z-axis (belly) pointing west.
-// To say the same thing in other words, and perhaps more to the
-// point: If we use the OpenGL camera orientation conventions,
-// i.e. Xprime=starboard, Yprime=top, Zprime=aft, then the
-// aforementioned peculiar reference orientation at (lat,lon)
-// = (0,0) can be described as:
-// -- aircraft Xprime axis (starboard) pointed up
-// -- aircraft Yprime axis (top) pointed east
-// -- aircraft Zprime axis (aft) pointed north
-// meaning the OpenGL axes are aligned with the ECEF axes.
-double FGViewMgr::getCurrentViewOrientation_w() const{
- return (current_view_orientation * conj(fsb2sta())).w();
-}
-double FGViewMgr::getCurrentViewOrientation_x() const{
- return (current_view_orientation * conj(fsb2sta())).x();
-}
-double FGViewMgr::getCurrentViewOrientation_y() const{
- return (current_view_orientation * conj(fsb2sta())).y();
-}
-double FGViewMgr::getCurrentViewOrientation_z() const{
- return (current_view_orientation * conj(fsb2sta())).z();
-}
-
-void
-FGViewMgr::do_axes ()
-{
- // Take no action when hat is centered
- if ( ( axis_long < 0.01 ) &&
- ( axis_long > -0.01 ) &&
- ( axis_lat < 0.01 ) &&
- ( axis_lat > -0.01 )
- )
- return;
-
- double viewDir = 999;
-
- /* Do all the quick and easy cases */
- if (axis_long < 0) { // Longitudinal axis forward
- if (axis_lat == axis_long)
- viewDir = fgGetDouble("/sim/view/config/front-left-direction-deg");
- else if (axis_lat == - axis_long)
- viewDir = fgGetDouble("/sim/view/config/front-right-direction-deg");
- else if (axis_lat == 0)
- viewDir = fgGetDouble("/sim/view/config/front-direction-deg");
- } else if (axis_long > 0) { // Longitudinal axis backward
- if (axis_lat == - axis_long)
- viewDir = fgGetDouble("/sim/view/config/back-left-direction-deg");
- else if (axis_lat == axis_long)
- viewDir = fgGetDouble("/sim/view/config/back-right-direction-deg");
- else if (axis_lat == 0)
- viewDir = fgGetDouble("/sim/view/config/back-direction-deg");
- } else if (axis_long == 0) { // Longitudinal axis neutral
- if (axis_lat < 0)
- viewDir = fgGetDouble("/sim/view/config/left-direction-deg");
- else if (axis_lat > 0)
- viewDir = fgGetDouble("/sim/view/config/right-direction-deg");
- else return; /* And assertion failure maybe? */
- }
-
- // Do all the difficult cases
- if ( viewDir > 900 )
- viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axis_lat, -axis_long );
- if ( viewDir < -1 ) viewDir += 360;
-
- get_current_view()->setGoalHeadingOffset_deg(viewDir);
-}
+++ /dev/null
-// viewmgr.hxx -- class for managing all the views in the flightgear world.
-//
-// Written by Curtis Olson, started October 2000.
-//
-// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program 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 GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// $Id$
-
-
-#ifndef _VIEWMGR_HXX
-#define _VIEWMGR_HXX
-
-#include <vector>
-
-#include <simgear/compiler.h>
-#include <simgear/structure/subsystem_mgr.hxx>
-#include <simgear/props/props.hxx>
-#include <simgear/props/tiedpropertylist.hxx>
-#include <simgear/math/SGMath.hxx>
-
-// forward decls
-class FGViewer;
-class SGSoundMgr;
-typedef SGSharedPtr<FGViewer> FGViewerPtr;
-
-// Define a structure containing view information
-class FGViewMgr : public SGSubsystem
-{
-
-public:
-
- // Constructor
- FGViewMgr( void );
-
- // Destructor
- ~FGViewMgr( void );
-
- virtual void init ();
- virtual void bind ();
- virtual void unbind ();
- virtual void update (double dt);
- virtual void reinit ();
-
- // getters
- inline int size() const { return views.size(); }
- inline int get_current() const { return current; }
-
- FGViewer *get_current_view();
- const FGViewer *get_current_view() const;
-
- FGViewer *get_view( int i );
- const FGViewer *get_view( int i ) const;
-
- FGViewer *next_view();
- FGViewer *prev_view();
-
- // setters
- void clear();
-
- void add_view( FGViewer * v );
-
-private:
- void do_bind();
-
- simgear::TiedPropertyList _tiedProperties;
-
- double axis_long;
- double axis_lat;
-
- void do_axes ();
-
- // callbacks in manager to access viewer methods
- double getViewHeadingOffset_deg () const;
- void setViewHeadingOffset_deg (double offset);
- double getViewGoalHeadingOffset_deg () const;
- void setViewGoalHeadingOffset_deg (double offset);
- double getViewPitchOffset_deg () const;
- void setViewPitchOffset_deg (double tilt);
- double getGoalViewPitchOffset_deg () const;
- void setGoalViewRollOffset_deg (double tilt);
- double getViewRollOffset_deg () const;
- void setViewRollOffset_deg (double tilt);
- double getGoalViewRollOffset_deg () const;
- void setGoalViewPitchOffset_deg (double tilt);
- double getViewXOffset_m () const;
- void setViewXOffset_m (double x);
- double getViewYOffset_m () const;
- void setViewYOffset_m (double y);
- double getViewZOffset_m () const;
- void setViewZOffset_m (double z);
- double getViewTargetXOffset_m () const;
- void setViewTargetXOffset_m (double x);
- double getViewTargetYOffset_m () const;
- void setViewTargetYOffset_m (double y);
- double getViewTargetZOffset_m () const;
- void setViewTargetZOffset_m (double z);
- double getFOV_deg () const;
- void setFOV_deg (double fov);
- double getARM_deg () const; // Aspect Ratio Multiplier
- void setARM_deg (double fov);
- double getNear_m () const;
- void setNear_m (double near_m);
- void setViewAxisLong (double axis);
- void setViewAxisLat (double axis);
- int getView () const;
- void setView (int newview);
-
-// quaternion accessors, for debugging:
- double getCurrentViewOrientation_w() const;
- double getCurrentViewOrientation_x() const;
- double getCurrentViewOrientation_y() const;
- double getCurrentViewOrientation_z() const;
- double getCurrentViewOrOffset_w() const;
- double getCurrentViewOrOffset_x() const;
- double getCurrentViewOrOffset_y() const;
- double getCurrentViewOrOffset_z() const;
- double getCurrentViewFrame_w() const;
- double getCurrentViewFrame_x() const;
- double getCurrentViewFrame_y() const;
- double getCurrentViewFrame_z() const;
-
- bool stationary () const;
-
- // copies current offset settings to current-view path...
- void copyToCurrent ();
-
- bool inited;
- SGPropertyNode_ptr view_number;
- std::vector<SGPropertyNode_ptr> config_list;
- typedef std::vector<FGViewerPtr> viewer_list;
- viewer_list views;
- SGVec3d abs_viewer_position;
-
- int current;
- SGQuatd current_view_orientation, current_view_or_offset;
-
- SGSoundMgr *smgr;
-
-};
-
-// This takes the conventional aviation XYZ body system
-// i.e. x=forward, y=starboard, z=bottom
-// which is widely used in FGFS
-// and rotates it into the OpenGL camera system
-// i.e. Xprime=starboard, Yprime=top, Zprime=aft.
-inline const SGQuatd fsb2sta()
-{
- return SGQuatd(-0.5, -0.5, 0.5, 0.5);
-}
-
-#endif // _VIEWMGR_HXX
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
-#include <Main/renderer.hxx>
-#include <Main/viewmgr.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/renderer.hxx>
+#include <Viewer/viewmgr.hxx>
+#include <Viewer/viewer.hxx>
#include <Scenery/scenery.hxx>
#include <Sound/fg_fx.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
-#include <Main/renderer.hxx>
+#include <Viewer/renderer.hxx>
#include "jpg-httpd.hxx"
#include <errno.h>
#include <Main/globals.hxx>
-#include <Main/viewmgr.hxx>
+#include <Viewer/viewmgr.hxx>
#include <simgear/io/sg_netChat.hxx>
#include <simgear/scene/bvh/BVHNode.hxx>
#include <simgear/scene/bvh/BVHLineSegmentVisitor.hxx>
-#include <Main/renderer.hxx>
+#include <Viewer/renderer.hxx>
#include <Main/fg_props.hxx>
#include "tilemgr.hxx"
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
-#include <Main/renderer.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/renderer.hxx>
+#include <Viewer/viewer.hxx>
#include <Scripting/NasalSys.hxx>
#include "scenery.hxx"
#include <Main/main.hxx>
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
-#include <Main/renderer.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/renderer.hxx>
+#include <Viewer/viewer.hxx>
#include "light.hxx"
#include "sunsolver.hxx"
--- /dev/null
+include(FlightGearComponent)
+
+set(SOURCES
+ CameraGroup.cxx
+ FGEventHandler.cxx
+ WindowBuilder.cxx
+ WindowSystemAdapter.cxx
+ fg_os_osgviewer.cxx
+ fgviewer.cxx
+ renderer.cxx
+ splash.cxx
+ viewer.cxx
+ viewmgr.cxx
+ )
+
+set(HEADERS
+ CameraGroup.hxx
+ FGEventHandler.hxx
+ WindowBuilder.hxx
+ WindowSystemAdapter.hxx
+ fgviewer.hxx
+ renderer.hxx
+ splash.hxx
+ viewer.hxx
+ viewmgr.hxx
+ )
+
+flightgear_component(Viewer "${SOURCES}" "${HEADERS}")
--- /dev/null
+// Copyright (C) 2008 Tim Moore
+// Copyright (C) 2011 Mathias Froehlich
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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 GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "CameraGroup.hxx"
+
+#include <Main/fg_props.hxx>
+#include <Main/globals.hxx>
+#include "renderer.hxx"
+#include "FGEventHandler.hxx"
+#include "WindowBuilder.hxx"
+#include "WindowSystemAdapter.hxx"
+#include <simgear/props/props.hxx>
+#include <simgear/structure/OSGUtils.hxx>
+#include <simgear/structure/OSGVersion.hxx>
+#include <simgear/scene/material/EffectCullVisitor.hxx>
+#include <simgear/scene/util/RenderConstants.hxx>
+#include <simgear/scene/tgdb/userdata.hxx>
+
+#include <algorithm>
+#include <cstring>
+#include <string>
+
+#include <osg/Camera>
+#include <osg/Geometry>
+#include <osg/GraphicsContext>
+#include <osg/io_utils>
+#include <osg/Math>
+#include <osg/Matrix>
+#include <osg/Notify>
+#include <osg/Program>
+#include <osg/Quat>
+#include <osg/TexMat>
+#include <osg/Vec3d>
+#include <osg/Viewport>
+
+#include <osgUtil/IntersectionVisitor>
+
+#include <osgViewer/GraphicsWindow>
+#include <osgViewer/Renderer>
+
+static osg::Matrix
+invert(const osg::Matrix& matrix)
+{
+ return osg::Matrix::inverse(matrix);
+}
+
+/// Returns the zoom factor of the master camera.
+/// The reference fov is the historic 55 deg
+static double
+zoomFactor()
+{
+ double fov = fgGetDouble("/sim/current-view/field-of-view", 55);
+ if (fov < 1)
+ fov = 1;
+ return tan(55*0.5*SG_DEGREES_TO_RADIANS)/tan(fov*0.5*SG_DEGREES_TO_RADIANS);
+}
+
+static osg::Vec2d
+preMult(const osg::Vec2d& v, const osg::Matrix& m)
+{
+ osg::Vec3d tmp = m.preMult(osg::Vec3(v, 0));
+ return osg::Vec2d(tmp[0], tmp[1]);
+}
+
+static osg::Matrix
+relativeProjection(const osg::Matrix& P0, const osg::Matrix& R, const osg::Vec2d ref[2],
+ const osg::Matrix& pP, const osg::Matrix& pR, const osg::Vec2d pRef[2])
+{
+ // Track the way from one projection space to the other:
+ // We want
+ // P = T*S*P0
+ // where P0 is the projection template sensible for the given window size,
+ // T is a translation matrix and S a scale matrix.
+ // We need to determine T and S so that the reference points in the parents
+ // projection space match the two reference points in this cameras projection space.
+
+ // Starting from the parents camera projection space, we get into this cameras
+ // projection space by the transform matrix:
+ // P*R*inv(pP*pR) = T*S*P0*R*inv(pP*pR)
+ // So, at first compute that matrix without T*S and determine S and T from that
+
+ // Ok, now osg uses the inverse matrix multiplication order, thus:
+ osg::Matrix PtoPwithoutTS = invert(pR*pP)*R*P0;
+ // Compute the parents reference points in the current projection space
+ // without the yet unknown T and S
+ osg::Vec2d pRefInThis[2] = {
+ preMult(pRef[0], PtoPwithoutTS),
+ preMult(pRef[1], PtoPwithoutTS)
+ };
+
+ // To get the same zoom, rescale to match the parents size
+ double s = (ref[0] - ref[1]).length()/(pRefInThis[0] - pRefInThis[1]).length();
+ osg::Matrix S = osg::Matrix::scale(s, s, 1);
+
+ // For the translation offset, incorporate the now known scale
+ // and recompute the position ot the first reference point in the
+ // currents projection space without the yet unknown T.
+ pRefInThis[0] = preMult(pRef[0], PtoPwithoutTS*S);
+ // The translation is then the difference of the reference points
+ osg::Matrix T = osg::Matrix::translate(osg::Vec3d(ref[0] - pRefInThis[0], 0));
+
+ // Compose and return the desired final projection matrix
+ return P0*S*T;
+}
+
+namespace flightgear
+{
+using namespace osg;
+
+using std::strcmp;
+using std::string;
+
+ref_ptr<CameraGroup> CameraGroup::_defaultGroup;
+
+CameraGroup::CameraGroup(osgViewer::Viewer* viewer) :
+ _viewer(viewer)
+{
+}
+
+}
+
+namespace
+{
+using namespace osg;
+
+// Given a projection matrix, return a new one with the same frustum
+// sides and new near / far values.
+
+void makeNewProjMat(Matrixd& oldProj, double znear,
+ double zfar, Matrixd& projection)
+{
+ projection = oldProj;
+ // Slightly inflate the near & far planes to avoid objects at the
+ // extremes being clipped out.
+ znear *= 0.999;
+ zfar *= 1.001;
+
+ // Clamp the projection matrix z values to the range (near, far)
+ double epsilon = 1.0e-6;
+ if (fabs(projection(0,3)) < epsilon &&
+ fabs(projection(1,3)) < epsilon &&
+ fabs(projection(2,3)) < epsilon) {
+ // Projection is Orthographic
+ epsilon = -1.0/(zfar - znear); // Used as a temp variable
+ projection(2,2) = 2.0*epsilon;
+ projection(3,2) = (zfar + znear)*epsilon;
+ } else {
+ // Projection is Perspective
+ double trans_near = (-znear*projection(2,2) + projection(3,2)) /
+ (-znear*projection(2,3) + projection(3,3));
+ double trans_far = (-zfar*projection(2,2) + projection(3,2)) /
+ (-zfar*projection(2,3) + projection(3,3));
+ double ratio = fabs(2.0/(trans_near - trans_far));
+ double center = -0.5*(trans_near + trans_far);
+
+ projection.postMult(osg::Matrixd(1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, ratio, 0.0,
+ 0.0, 0.0, center*ratio, 1.0));
+ }
+}
+}
+
+namespace flightgear
+{
+void CameraInfo::updateCameras()
+{
+ bufferSize->set( osg::Vec2f( width, height ) );
+
+ for (CameraMap::iterator ii = cameras.begin(); ii != cameras.end(); ++ii ) {
+ float f = ii->second.scaleFactor;
+ if ( f == 0.0f ) continue;
+ ii->second.camera->getViewport()->setViewport(x*f, y*f, width*f, height*f);
+ }
+
+ for (RenderBufferMap::iterator ii = buffers.begin(); ii != buffers.end(); ++ii ) {
+ float f = ii->second.scaleFactor;
+ if ( f == 0.0f ) continue;
+ osg::Texture2D* texture = ii->second.texture.get();
+ if ( texture->getTextureHeight() != height*f || texture->getTextureWidth() != width*f ) {
+ texture->setTextureSize( width*f, height*f );
+ texture->dirtyTextureObject();
+ }
+ }
+}
+
+void CameraInfo::resized(double w, double h)
+{
+ bufferSize->set( osg::Vec2f( w, h ) );
+
+ for (RenderBufferMap::iterator ii = buffers.begin(); ii != buffers.end(); ++ii) {
+ float s = ii->second.scaleFactor;
+ if ( s == 0.0f ) continue;
+ ii->second.texture->setTextureSize( w * s, h * s );
+ ii->second.texture->dirtyTextureObject();
+ }
+
+ for (CameraMap::iterator ii = cameras.begin(); ii != cameras.end(); ++ii) {
+ RenderStageInfo& rsi = ii->second;
+ if (!rsi.resizable ||
+ rsi.camera->getRenderTargetImplementation() != osg::Camera::FRAME_BUFFER_OBJECT ||
+ rsi.scaleFactor == 0.0f )
+ continue;
+
+ Viewport* vp = rsi.camera->getViewport();
+ vp->width() = w * rsi.scaleFactor;
+ vp->height() = h * rsi.scaleFactor;
+
+ osgViewer::Renderer* renderer
+ = static_cast<osgViewer::Renderer*>(rsi.camera->getRenderer());
+ for (int i = 0; i < 2; ++i) {
+ osgUtil::SceneView* sceneView = renderer->getSceneView(i);
+ sceneView->getRenderStage()->setFrameBufferObject(0);
+ sceneView->getRenderStage()->setCameraRequiresSetUp(true);
+ if (sceneView->getRenderStageLeft()) {
+ sceneView->getRenderStageLeft()->setFrameBufferObject(0);
+ sceneView->getRenderStageLeft()->setCameraRequiresSetUp(true);
+ }
+ if (sceneView->getRenderStageRight()) {
+ sceneView->getRenderStageRight()->setFrameBufferObject(0);
+ sceneView->getRenderStageRight()->setCameraRequiresSetUp(true);
+ }
+ }
+ }
+}
+
+osg::Camera* CameraInfo::getCamera(CameraKind k) const
+{
+ CameraMap::const_iterator ii = cameras.find( k );
+ if (ii == cameras.end())
+ return 0;
+ return ii->second.camera.get();
+}
+
+osg::Texture2D* CameraInfo::getBuffer(RenderBufferInfo::Kind k) const
+{
+ RenderBufferMap::const_iterator ii = buffers.find(k);
+ if (ii == buffers.end())
+ return 0;
+ return ii->second.texture.get();
+}
+
+int CameraInfo::getMainSlaveIndex() const
+{
+ return cameras.find( MAIN_CAMERA )->second.slaveIndex;
+}
+
+void CameraInfo::setMatrices(osg::Camera* c)
+{
+ view->set( c->getViewMatrix() );
+ viewInverse->set( osg::Matrix::inverse( c->getViewMatrix() ) );
+ projInverse->set( osg::Matrix::inverse( c->getProjectionMatrix() ) );
+}
+
+void CameraGroup::update(const osg::Vec3d& position,
+ const osg::Quat& orientation)
+{
+ const Matrix masterView(osg::Matrix::translate(-position)
+ * osg::Matrix::rotate(orientation.inverse()));
+ _viewer->getCamera()->setViewMatrix(masterView);
+ const Matrix& masterProj = _viewer->getCamera()->getProjectionMatrix();
+ double masterZoomFactor = zoomFactor();
+ for (CameraList::iterator i = _cameras.begin(); i != _cameras.end(); ++i) {
+ const CameraInfo* info = i->get();
+
+ Camera* camera = info->getCamera(MAIN_CAMERA);
+ if ( camera ) {
+ const View::Slave& slave = _viewer->getSlave(info->getMainSlaveIndex());
+#if SG_OSG_VERSION_LESS_THAN(3,0,0)
+ // refreshes camera viewports (for now)
+ info->updateCameras();
+#endif
+ Matrix viewMatrix;
+ if (info->flags & GUI) {
+ viewMatrix = osg::Matrix(); // identifty transform on the GUI camera
+ } else if ((info->flags & VIEW_ABSOLUTE) != 0)
+ viewMatrix = slave._viewOffset;
+ else
+ viewMatrix = masterView * slave._viewOffset;
+ camera->setViewMatrix(viewMatrix);
+ Matrix projectionMatrix;
+ if (info->flags & GUI) {
+ projectionMatrix = osg::Matrix::ortho2D(0, info->width, 0, info->height);
+ } else if ((info->flags & PROJECTION_ABSOLUTE) != 0) {
+ if (info->flags & ENABLE_MASTER_ZOOM) {
+ if (info->relativeCameraParent < _cameras.size()) {
+ // template projection matrix and view matrix of the current camera
+ osg::Matrix P0 = slave._projectionOffset;
+ osg::Matrix R = viewMatrix;
+
+ // The already known projection and view matrix of the parent camera
+ const CameraInfo* parentInfo = _cameras[info->relativeCameraParent].get();
+ RenderStageInfo prsi = parentInfo->cameras.find(MAIN_CAMERA)->second;
+ osg::Matrix pP = prsi.camera->getProjectionMatrix();
+ osg::Matrix pR = prsi.camera->getViewMatrix();
+
+ // And the projection matrix derived from P0 so that the reference points match
+ projectionMatrix = relativeProjection(P0, R, info->thisReference,
+ pP, pR, info->parentReference);
+
+ } else {
+ // We want to zoom, so take the original matrix and apply the zoom to it.
+ projectionMatrix = slave._projectionOffset;
+ projectionMatrix.postMultScale(osg::Vec3d(masterZoomFactor, masterZoomFactor, 1));
+ }
+ } else {
+ projectionMatrix = slave._projectionOffset;
+ }
+ } else {
+ projectionMatrix = masterProj * slave._projectionOffset;
+ }
+
+ CameraMap::const_iterator ii = info->cameras.find(FAR_CAMERA);
+ if (ii == info->cameras.end() || !ii->second.camera.valid()) {
+ camera->setProjectionMatrix(projectionMatrix);
+ } else {
+ Camera* farCamera = ii->second.camera;
+ farCamera->setViewMatrix(viewMatrix);
+ double left, right, bottom, top, parentNear, parentFar;
+ projectionMatrix.getFrustum(left, right, bottom, top,
+ parentNear, parentFar);
+ if ((info->flags & FIXED_NEAR_FAR) == 0) {
+ parentNear = _zNear;
+ parentFar = _zFar;
+ }
+ if (parentFar < _nearField || _nearField == 0.0f) {
+ camera->setProjectionMatrix(projectionMatrix);
+ camera->setCullMask(camera->getCullMask()
+ | simgear::BACKGROUND_BIT);
+ camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ farCamera->setNodeMask(0);
+ } else {
+ Matrix nearProj, farProj;
+ makeNewProjMat(projectionMatrix, parentNear, _nearField,
+ nearProj);
+ makeNewProjMat(projectionMatrix, _nearField, parentFar,
+ farProj);
+ camera->setProjectionMatrix(nearProj);
+ camera->setCullMask(camera->getCullMask()
+ & ~simgear::BACKGROUND_BIT);
+ camera->setClearMask(GL_DEPTH_BUFFER_BIT);
+ farCamera->setProjectionMatrix(farProj);
+ farCamera->setNodeMask(camera->getNodeMask());
+ }
+ }
+ } else {
+ bool viewDone = false;
+ Matrix viewMatrix;
+ bool projectionDone = false;
+ Matrix projectionMatrix;
+ for ( CameraMap::const_iterator ii = info->cameras.begin(); ii != info->cameras.end(); ++ii ) {
+ if ( ii->first == SHADOW_CAMERA ) {
+ globals->get_renderer()->updateShadowCamera(info, position);
+ continue;
+ }
+ if ( ii->second.fullscreen )
+ continue;
+
+ Camera* camera = ii->second.camera.get();
+ int slaveIndex = ii->second.slaveIndex;
+ const View::Slave& slave = _viewer->getSlave(slaveIndex);
+
+ if ( !viewDone ) {
+ if ((info->flags & VIEW_ABSOLUTE) != 0)
+ viewMatrix = slave._viewOffset;
+ else
+ viewMatrix = masterView * slave._viewOffset;
+ viewDone = true;
+ }
+
+ camera->setViewMatrix( viewMatrix );
+
+ if ( !projectionDone ) {
+ if ((info->flags & PROJECTION_ABSOLUTE) != 0) {
+ if (info->flags & ENABLE_MASTER_ZOOM) {
+ if (info->relativeCameraParent < _cameras.size()) {
+ // template projection matrix and view matrix of the current camera
+ osg::Matrix P0 = slave._projectionOffset;
+ osg::Matrix R = viewMatrix;
+
+ // The already known projection and view matrix of the parent camera
+ const CameraInfo* parentInfo = _cameras[info->relativeCameraParent].get();
+ RenderStageInfo prsi = parentInfo->cameras.find(MAIN_CAMERA)->second;
+ osg::Matrix pP = prsi.camera->getProjectionMatrix();
+ osg::Matrix pR = prsi.camera->getViewMatrix();
+
+ // And the projection matrix derived from P0 so that the reference points match
+ projectionMatrix = relativeProjection(P0, R, info->thisReference,
+ pP, pR, info->parentReference);
+
+ } else {
+ // We want to zoom, so take the original matrix and apply the zoom to it.
+ projectionMatrix = slave._projectionOffset;
+ projectionMatrix.postMultScale(osg::Vec3d(masterZoomFactor, masterZoomFactor, 1));
+ }
+ } else {
+ projectionMatrix = slave._projectionOffset;
+ }
+ } else {
+ projectionMatrix = masterProj * slave._projectionOffset;
+ }
+ projectionDone = true;
+ }
+
+ camera->setProjectionMatrix(projectionMatrix);
+ }
+ }
+ }
+
+ globals->get_renderer()->setPlanes( _zNear, _zFar );
+}
+
+void CameraGroup::setCameraParameters(float vfov, float aspectRatio)
+{
+ if (vfov != 0.0f && aspectRatio != 0.0f)
+ _viewer->getCamera()
+ ->setProjectionMatrixAsPerspective(vfov,
+ 1.0f / aspectRatio,
+ _zNear, _zFar);
+}
+
+double CameraGroup::getMasterAspectRatio() const
+{
+ if (_cameras.empty())
+ return 0.0;
+
+ const CameraInfo* info = _cameras.front();
+
+ osg::Camera* camera = info->getCamera(MAIN_CAMERA);
+ if ( !camera )
+ camera = info->getCamera( GEOMETRY_CAMERA );
+ const osg::Viewport* viewport = camera->getViewport();
+ if (!viewport) {
+ return 0.0;
+ }
+
+ return static_cast<double>(viewport->height()) / viewport->width();
+}
+
+}
+
+namespace
+{
+// A raw value for property nodes that references a class member via
+// an osg::ref_ptr.
+template<class C, class T>
+class RefMember : public SGRawValue<T>
+{
+public:
+ RefMember (C *obj, T C::*ptr)
+ : _obj(obj), _ptr(ptr) {}
+ virtual ~RefMember () {}
+ virtual T getValue () const
+ {
+ return _obj.get()->*_ptr;
+ }
+ virtual bool setValue (T value)
+ {
+ _obj.get()->*_ptr = value;
+ return true;
+ }
+ virtual SGRawValue<T> * clone () const
+ {
+ return new RefMember(_obj.get(), _ptr);
+ }
+private:
+ ref_ptr<C> _obj;
+ T C::* const _ptr;
+};
+
+template<typename C, typename T>
+RefMember<C, T> makeRefMember(C *obj, T C::*ptr)
+{
+ return RefMember<C, T>(obj, ptr);
+}
+
+template<typename C, typename T>
+void bindMemberToNode(SGPropertyNode* parent, const char* childName,
+ C* obj, T C::*ptr, T value)
+{
+ SGPropertyNode* valNode = parent->getNode(childName);
+ RefMember<C, T> refMember = makeRefMember(obj, ptr);
+ if (!valNode) {
+ valNode = parent->getNode(childName, true);
+ valNode->tie(refMember, false);
+ setValue(valNode, value);
+ } else {
+ valNode->tie(refMember, true);
+ }
+}
+
+void buildViewport(flightgear::CameraInfo* info, SGPropertyNode* viewportNode,
+ const osg::GraphicsContext::Traits *traits)
+{
+ using namespace flightgear;
+ bindMemberToNode(viewportNode, "x", info, &CameraInfo::x, 0.0);
+ bindMemberToNode(viewportNode, "y", info, &CameraInfo::y, 0.0);
+ bindMemberToNode(viewportNode, "width", info, &CameraInfo::width,
+ static_cast<double>(traits->width));
+ bindMemberToNode(viewportNode, "height", info, &CameraInfo::height,
+ static_cast<double>(traits->height));
+}
+}
+
+namespace flightgear
+{
+
+// Mostly copied from osg's osgViewer/View.cpp
+
+static osg::Geometry* createPanoramicSphericalDisplayDistortionMesh(
+ const Vec3& origin, const Vec3& widthVector, const Vec3& heightVector,
+ double sphere_radius, double collar_radius,
+ Image* intensityMap = 0, const Matrix& projectorMatrix = Matrix())
+{
+ osg::Vec3d center(0.0,0.0,0.0);
+ osg::Vec3d eye(0.0,0.0,0.0);
+
+ double distance = sqrt(sphere_radius*sphere_radius - collar_radius*collar_radius);
+ bool flip = false;
+ bool texcoord_flip = false;
+
+#if 0
+ osg::Vec3d projector = eye - osg::Vec3d(0.0,0.0, distance);
+
+ OSG_INFO<<"createPanoramicSphericalDisplayDistortionMesh : Projector position = "<<projector<<std::endl;
+ OSG_INFO<<"createPanoramicSphericalDisplayDistortionMesh : distance = "<<distance<<std::endl;
+#endif
+ // create the quad to visualize.
+ osg::Geometry* geometry = new osg::Geometry();
+
+ geometry->setSupportsDisplayList(false);
+
+ osg::Vec3 xAxis(widthVector);
+ float width = widthVector.length();
+ xAxis /= width;
+
+ osg::Vec3 yAxis(heightVector);
+ float height = heightVector.length();
+ yAxis /= height;
+
+ int noSteps = 160;
+
+ osg::Vec3Array* vertices = new osg::Vec3Array;
+ osg::Vec2Array* texcoords0 = new osg::Vec2Array;
+ osg::Vec2Array* texcoords1 = intensityMap==0 ? new osg::Vec2Array : 0;
+ osg::Vec4Array* colors = new osg::Vec4Array;
+
+#if 0
+ osg::Vec3 bottom = origin;
+ osg::Vec3 dx = xAxis*(width/((float)(noSteps-2)));
+ osg::Vec3 dy = yAxis*(height/((float)(noSteps-1)));
+#endif
+ osg::Vec3 top = origin + yAxis*height;
+
+ osg::Vec3 screenCenter = origin + widthVector*0.5f + heightVector*0.5f;
+ float screenRadius = heightVector.length() * 0.5f;
+
+ geometry->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
+
+ for(int i=0;i<noSteps;++i)
+ {
+ //osg::Vec3 cursor = bottom+dy*(float)i;
+ for(int j=0;j<noSteps;++j)
+ {
+ osg::Vec2 texcoord(double(i)/double(noSteps-1), double(j)/double(noSteps-1));
+ double theta = texcoord.x() * 2.0 * osg::PI;
+ double phi = (1.0-texcoord.y()) * osg::PI;
+
+ if (texcoord_flip) texcoord.y() = 1.0f - texcoord.y();
+
+ osg::Vec3 pos(sin(phi)*sin(theta), sin(phi)*cos(theta), cos(phi));
+ pos = pos*projectorMatrix;
+
+ double alpha = atan2(pos.x(), pos.y());
+ if (alpha<0.0) alpha += 2.0*osg::PI;
+
+ double beta = atan2(sqrt(pos.x()*pos.x() + pos.y()*pos.y()), pos.z());
+ if (beta<0.0) beta += 2.0*osg::PI;
+
+ double gamma = atan2(sqrt(double(pos.x()*pos.x() + pos.y()*pos.y())), double(pos.z()+distance));
+ if (gamma<0.0) gamma += 2.0*osg::PI;
+
+
+ osg::Vec3 v = screenCenter + osg::Vec3(sin(alpha)*gamma*2.0/osg::PI, -cos(alpha)*gamma*2.0/osg::PI, 0.0f)*screenRadius;
+
+ if (flip)
+ vertices->push_back(osg::Vec3(v.x(), top.y()-(v.y()-origin.y()),v.z()));
+ else
+ vertices->push_back(v);
+
+ texcoords0->push_back( texcoord );
+
+ osg::Vec2 texcoord1(alpha/(2.0*osg::PI), 1.0f - beta/osg::PI);
+ if (intensityMap)
+ {
+ colors->push_back(intensityMap->getColor(texcoord1));
+ }
+ else
+ {
+ colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
+ if (texcoords1) texcoords1->push_back( texcoord1 );
+ }
+
+
+ }
+ }
+
+
+ // pass the created vertex array to the points geometry object.
+ geometry->setVertexArray(vertices);
+
+ geometry->setColorArray(colors);
+ geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
+
+ geometry->setTexCoordArray(0,texcoords0);
+ if (texcoords1) geometry->setTexCoordArray(1,texcoords1);
+
+ osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES);
+ geometry->addPrimitiveSet(elements);
+
+ for(int i=0;i<noSteps-1;++i)
+ {
+ for(int j=0;j<noSteps-1;++j)
+ {
+ int i1 = j+(i+1)*noSteps;
+ int i2 = j+(i)*noSteps;
+ int i3 = j+1+(i)*noSteps;
+ int i4 = j+1+(i+1)*noSteps;
+
+ osg::Vec3& v1 = (*vertices)[i1];
+ osg::Vec3& v2 = (*vertices)[i2];
+ osg::Vec3& v3 = (*vertices)[i3];
+ osg::Vec3& v4 = (*vertices)[i4];
+
+ if ((v1-screenCenter).length()>screenRadius) continue;
+ if ((v2-screenCenter).length()>screenRadius) continue;
+ if ((v3-screenCenter).length()>screenRadius) continue;
+ if ((v4-screenCenter).length()>screenRadius) continue;
+
+ elements->push_back(i1);
+ elements->push_back(i2);
+ elements->push_back(i3);
+
+ elements->push_back(i1);
+ elements->push_back(i3);
+ elements->push_back(i4);
+ }
+ }
+
+ return geometry;
+}
+
+void CameraGroup::buildDistortionCamera(const SGPropertyNode* psNode,
+ Camera* camera)
+{
+ const SGPropertyNode* texNode = psNode->getNode("texture");
+ if (!texNode) {
+ // error
+ return;
+ }
+ string texName = texNode->getStringValue();
+ TextureMap::iterator itr = _textureTargets.find(texName);
+ if (itr == _textureTargets.end()) {
+ // error
+ return;
+ }
+ Viewport* viewport = camera->getViewport();
+ float width = viewport->width();
+ float height = viewport->height();
+ TextureRectangle* texRect = itr->second.get();
+ double radius = psNode->getDoubleValue("radius", 1.0);
+ double collar = psNode->getDoubleValue("collar", 0.45);
+ Geode* geode = new Geode();
+ geode->addDrawable(createPanoramicSphericalDisplayDistortionMesh(
+ Vec3(0.0f,0.0f,0.0f), Vec3(width,0.0f,0.0f),
+ Vec3(0.0f,height,0.0f), radius, collar));
+
+ // new we need to add the texture to the mesh, we do so by creating a
+ // StateSet to contain the Texture StateAttribute.
+ StateSet* stateset = geode->getOrCreateStateSet();
+ stateset->setTextureAttributeAndModes(0, texRect, StateAttribute::ON);
+ stateset->setMode(GL_LIGHTING, StateAttribute::OFF);
+
+ TexMat* texmat = new TexMat;
+ texmat->setScaleByTextureRectangleSize(true);
+ stateset->setTextureAttributeAndModes(0, texmat, osg::StateAttribute::ON);
+#if 0
+ if (!applyIntensityMapAsColours && intensityMap)
+ {
+ stateset->setTextureAttributeAndModes(1, new osg::Texture2D(intensityMap), osg::StateAttribute::ON);
+ }
+#endif
+ // add subgraph to render
+ camera->addChild(geode);
+ camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ camera->setClearColor(osg::Vec4(0.0, 0.0, 0.0, 1.0));
+ camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+ camera->setCullingMode(osg::CullSettings::NO_CULLING);
+ camera->setName("DistortionCorrectionCamera");
+}
+
+CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
+{
+ WindowBuilder *wBuild = WindowBuilder::getWindowBuilder();
+ const SGPropertyNode* windowNode = cameraNode->getNode("window");
+ GraphicsWindow* window = 0;
+ int cameraFlags = DO_INTERSECTION_TEST;
+ if (windowNode) {
+ // New style window declaration / definition
+ window = wBuild->buildWindow(windowNode);
+ } else {
+ // Old style: suck window params out of camera block
+ window = wBuild->buildWindow(cameraNode);
+ }
+ if (!window) {
+ return 0;
+ }
+ Camera* camera = new Camera;
+ camera->setAllowEventFocus(false);
+ camera->setGraphicsContext(window->gc.get());
+ camera->setViewport(new Viewport);
+ camera->setCullingMode(CullSettings::SMALL_FEATURE_CULLING
+ | CullSettings::VIEW_FRUSTUM_CULLING);
+ camera->setInheritanceMask(CullSettings::ALL_VARIABLES
+ & ~(CullSettings::CULL_MASK
+ | CullSettings::CULLING_MODE
+#if defined(HAVE_CULLSETTINGS_CLEAR_MASK)
+ | CullSettings::CLEAR_MASK
+#endif
+ ));
+
+ osg::Matrix vOff;
+ const SGPropertyNode* viewNode = cameraNode->getNode("view");
+ if (viewNode) {
+ double heading = viewNode->getDoubleValue("heading-deg", 0.0);
+ double pitch = viewNode->getDoubleValue("pitch-deg", 0.0);
+ double roll = viewNode->getDoubleValue("roll-deg", 0.0);
+ double x = viewNode->getDoubleValue("x", 0.0);
+ double y = viewNode->getDoubleValue("y", 0.0);
+ double z = viewNode->getDoubleValue("z", 0.0);
+ // Build a view matrix, which is the inverse of a model
+ // orientation matrix.
+ vOff = (Matrix::translate(-x, -y, -z)
+ * Matrix::rotate(-DegreesToRadians(heading),
+ Vec3d(0.0, 1.0, 0.0),
+ -DegreesToRadians(pitch),
+ Vec3d(1.0, 0.0, 0.0),
+ -DegreesToRadians(roll),
+ Vec3d(0.0, 0.0, 1.0)));
+ if (viewNode->getBoolValue("absolute", false))
+ cameraFlags |= VIEW_ABSOLUTE;
+ } else {
+ // Old heading parameter, works in the opposite direction
+ double heading = cameraNode->getDoubleValue("heading-deg", 0.0);
+ vOff.makeRotate(DegreesToRadians(heading), osg::Vec3(0, 1, 0));
+ }
+ // Configuring the physical dimensions of a monitor
+ SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true);
+ double physicalWidth = viewportNode->getDoubleValue("width", 1024);
+ double physicalHeight = viewportNode->getDoubleValue("height", 768);
+ double bezelHeightTop = 0;
+ double bezelHeightBottom = 0;
+ double bezelWidthLeft = 0;
+ double bezelWidthRight = 0;
+ const SGPropertyNode* physicalDimensionsNode = 0;
+ if ((physicalDimensionsNode = cameraNode->getNode("physical-dimensions")) != 0) {
+ physicalWidth = physicalDimensionsNode->getDoubleValue("width", physicalWidth);
+ physicalHeight = physicalDimensionsNode->getDoubleValue("height", physicalHeight);
+ const SGPropertyNode* bezelNode = 0;
+ if ((bezelNode = physicalDimensionsNode->getNode("bezel")) != 0) {
+ bezelHeightTop = bezelNode->getDoubleValue("top", bezelHeightTop);
+ bezelHeightBottom = bezelNode->getDoubleValue("bottom", bezelHeightBottom);
+ bezelWidthLeft = bezelNode->getDoubleValue("left", bezelWidthLeft);
+ bezelWidthRight = bezelNode->getDoubleValue("right", bezelWidthRight);
+ }
+ }
+ osg::Matrix pOff;
+ unsigned parentCameraIndex = ~0u;
+ osg::Vec2d parentReference[2];
+ osg::Vec2d thisReference[2];
+ SGPropertyNode* projectionNode = 0;
+ if ((projectionNode = cameraNode->getNode("perspective")) != 0) {
+ double fovy = projectionNode->getDoubleValue("fovy-deg", 55.0);
+ double aspectRatio = projectionNode->getDoubleValue("aspect-ratio",
+ 1.0);
+ double zNear = projectionNode->getDoubleValue("near", 0.0);
+ double zFar = projectionNode->getDoubleValue("far", zNear + 20000);
+ double offsetX = projectionNode->getDoubleValue("offset-x", 0.0);
+ double offsetY = projectionNode->getDoubleValue("offset-y", 0.0);
+ double tan_fovy = tan(DegreesToRadians(fovy*0.5));
+ double right = tan_fovy * aspectRatio * zNear + offsetX;
+ double left = -tan_fovy * aspectRatio * zNear + offsetX;
+ double top = tan_fovy * zNear + offsetY;
+ double bottom = -tan_fovy * zNear + offsetY;
+ pOff.makeFrustum(left, right, bottom, top, zNear, zFar);
+ cameraFlags |= PROJECTION_ABSOLUTE;
+ if (projectionNode->getBoolValue("fixed-near-far", true))
+ cameraFlags |= FIXED_NEAR_FAR;
+ } else if ((projectionNode = cameraNode->getNode("frustum")) != 0
+ || (projectionNode = cameraNode->getNode("ortho")) != 0) {
+ double top = projectionNode->getDoubleValue("top", 0.0);
+ double bottom = projectionNode->getDoubleValue("bottom", 0.0);
+ double left = projectionNode->getDoubleValue("left", 0.0);
+ double right = projectionNode->getDoubleValue("right", 0.0);
+ double zNear = projectionNode->getDoubleValue("near", 0.0);
+ double zFar = projectionNode->getDoubleValue("far", zNear + 20000);
+ if (cameraNode->getNode("frustum")) {
+ pOff.makeFrustum(left, right, bottom, top, zNear, zFar);
+ cameraFlags |= PROJECTION_ABSOLUTE;
+ } else {
+ pOff.makeOrtho(left, right, bottom, top, zNear, zFar);
+ cameraFlags |= (PROJECTION_ABSOLUTE | ORTHO);
+ }
+ if (projectionNode->getBoolValue("fixed-near-far", true))
+ cameraFlags |= FIXED_NEAR_FAR;
+ } else if ((projectionNode = cameraNode->getNode("master-perspective")) != 0) {
+ double zNear = projectionNode->getDoubleValue("eye-distance", 0.4*physicalWidth);
+ double xoff = projectionNode->getDoubleValue("x-offset", 0);
+ double yoff = projectionNode->getDoubleValue("y-offset", 0);
+ double left = -0.5*physicalWidth - xoff;
+ double right = 0.5*physicalWidth - xoff;
+ double bottom = -0.5*physicalHeight - yoff;
+ double top = 0.5*physicalHeight - yoff;
+ pOff.makeFrustum(left, right, bottom, top, zNear, zNear*1000);
+ cameraFlags |= PROJECTION_ABSOLUTE | ENABLE_MASTER_ZOOM;
+ } else if ((projectionNode = cameraNode->getNode("right-of-perspective"))
+ || (projectionNode = cameraNode->getNode("left-of-perspective"))
+ || (projectionNode = cameraNode->getNode("above-perspective"))
+ || (projectionNode = cameraNode->getNode("below-perspective"))
+ || (projectionNode = cameraNode->getNode("reference-points-perspective"))) {
+ std::string name = projectionNode->getStringValue("parent-camera");
+ for (unsigned i = 0; i < _cameras.size(); ++i) {
+ if (_cameras[i]->name != name)
+ continue;
+ parentCameraIndex = i;
+ }
+ if (_cameras.size() <= parentCameraIndex) {
+ SG_LOG(SG_VIEW, SG_ALERT, "CameraGroup::buildCamera: "
+ "failed to find parent camera for relative camera!");
+ return 0;
+ }
+ const CameraInfo* parentInfo = _cameras[parentCameraIndex].get();
+ if (projectionNode->getNameString() == "right-of-perspective") {
+ double tmp = (parentInfo->physicalWidth + 2*parentInfo->bezelWidthRight)/parentInfo->physicalWidth;
+ parentReference[0] = osg::Vec2d(tmp, -1);
+ parentReference[1] = osg::Vec2d(tmp, 1);
+ tmp = (physicalWidth + 2*bezelWidthLeft)/physicalWidth;
+ thisReference[0] = osg::Vec2d(-tmp, -1);
+ thisReference[1] = osg::Vec2d(-tmp, 1);
+ } else if (projectionNode->getNameString() == "left-of-perspective") {
+ double tmp = (parentInfo->physicalWidth + 2*parentInfo->bezelWidthLeft)/parentInfo->physicalWidth;
+ parentReference[0] = osg::Vec2d(-tmp, -1);
+ parentReference[1] = osg::Vec2d(-tmp, 1);
+ tmp = (physicalWidth + 2*bezelWidthRight)/physicalWidth;
+ thisReference[0] = osg::Vec2d(tmp, -1);
+ thisReference[1] = osg::Vec2d(tmp, 1);
+ } else if (projectionNode->getNameString() == "above-perspective") {
+ double tmp = (parentInfo->physicalHeight + 2*parentInfo->bezelHeightTop)/parentInfo->physicalHeight;
+ parentReference[0] = osg::Vec2d(-1, tmp);
+ parentReference[1] = osg::Vec2d(1, tmp);
+ tmp = (physicalHeight + 2*bezelHeightBottom)/physicalHeight;
+ thisReference[0] = osg::Vec2d(-1, -tmp);
+ thisReference[1] = osg::Vec2d(1, -tmp);
+ } else if (projectionNode->getNameString() == "below-perspective") {
+ double tmp = (parentInfo->physicalHeight + 2*parentInfo->bezelHeightBottom)/parentInfo->physicalHeight;
+ parentReference[0] = osg::Vec2d(-1, -tmp);
+ parentReference[1] = osg::Vec2d(1, -tmp);
+ tmp = (physicalHeight + 2*bezelHeightTop)/physicalHeight;
+ thisReference[0] = osg::Vec2d(-1, tmp);
+ thisReference[1] = osg::Vec2d(1, tmp);
+ } else if (projectionNode->getNameString() == "reference-points-perspective") {
+ SGPropertyNode* parentNode = projectionNode->getNode("parent", true);
+ SGPropertyNode* thisNode = projectionNode->getNode("this", true);
+ SGPropertyNode* pointNode;
+
+ pointNode = parentNode->getNode("point", 0, true);
+ parentReference[0][0] = pointNode->getDoubleValue("x", 0)*2/parentInfo->physicalWidth;
+ parentReference[0][1] = pointNode->getDoubleValue("y", 0)*2/parentInfo->physicalHeight;
+ pointNode = parentNode->getNode("point", 1, true);
+ parentReference[1][0] = pointNode->getDoubleValue("x", 0)*2/parentInfo->physicalWidth;
+ parentReference[1][1] = pointNode->getDoubleValue("y", 0)*2/parentInfo->physicalHeight;
+
+ pointNode = thisNode->getNode("point", 0, true);
+ thisReference[0][0] = pointNode->getDoubleValue("x", 0)*2/physicalWidth;
+ thisReference[0][1] = pointNode->getDoubleValue("y", 0)*2/physicalHeight;
+ pointNode = thisNode->getNode("point", 1, true);
+ thisReference[1][0] = pointNode->getDoubleValue("x", 0)*2/physicalWidth;
+ thisReference[1][1] = pointNode->getDoubleValue("y", 0)*2/physicalHeight;
+ }
+
+ pOff = osg::Matrix::perspective(45, physicalWidth/physicalHeight, 1, 20000);
+ cameraFlags |= PROJECTION_ABSOLUTE | ENABLE_MASTER_ZOOM;
+ } else {
+ // old style shear parameters
+ double shearx = cameraNode->getDoubleValue("shear-x", 0);
+ double sheary = cameraNode->getDoubleValue("shear-y", 0);
+ pOff.makeTranslate(-shearx, -sheary, 0);
+ }
+ const SGPropertyNode* textureNode = cameraNode->getNode("texture");
+ if (textureNode) {
+ string texName = textureNode->getStringValue("name");
+ int tex_width = textureNode->getIntValue("width");
+ int tex_height = textureNode->getIntValue("height");
+ TextureRectangle* texture = new TextureRectangle;
+
+ texture->setTextureSize(tex_width, tex_height);
+ texture->setInternalFormat(GL_RGB);
+ texture->setFilter(Texture::MIN_FILTER, Texture::LINEAR);
+ texture->setFilter(Texture::MAG_FILTER, Texture::LINEAR);
+ texture->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE);
+ texture->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE);
+ camera->setDrawBuffer(GL_FRONT);
+ camera->setReadBuffer(GL_FRONT);
+ camera->setRenderTargetImplementation(Camera::FRAME_BUFFER_OBJECT);
+ camera->attach(Camera::COLOR_BUFFER, texture);
+ _textureTargets[texName] = texture;
+ } else {
+ camera->setDrawBuffer(GL_BACK);
+ camera->setReadBuffer(GL_BACK);
+ }
+ const SGPropertyNode* psNode = cameraNode->getNode("panoramic-spherical");
+ bool useMasterSceneGraph = !psNode;
+ CameraInfo* info = globals->get_renderer()->buildRenderingPipeline(this, cameraFlags, camera, vOff, pOff,
+ window->gc.get(), useMasterSceneGraph);
+ info->name = cameraNode->getStringValue("name");
+ info->physicalWidth = physicalWidth;
+ info->physicalHeight = physicalHeight;
+ info->bezelHeightTop = bezelHeightTop;
+ info->bezelHeightBottom = bezelHeightBottom;
+ info->bezelWidthLeft = bezelWidthLeft;
+ info->bezelWidthRight = bezelWidthRight;
+ info->relativeCameraParent = parentCameraIndex;
+ info->parentReference[0] = parentReference[0];
+ info->parentReference[1] = parentReference[1];
+ info->thisReference[0] = thisReference[0];
+ info->thisReference[1] = thisReference[1];
+ // If a viewport isn't set on the camera, then it's hard to dig it
+ // out of the SceneView objects in the viewer, and the coordinates
+ // of mouse events are somewhat bizzare.
+ buildViewport(info, viewportNode, window->gc->getTraits());
+ info->updateCameras();
+ // Distortion camera needs the viewport which is created by addCamera().
+ if (psNode) {
+ info->flags = info->flags | VIEW_ABSOLUTE;
+ buildDistortionCamera(psNode, camera);
+ }
+ return info;
+}
+
+CameraInfo* CameraGroup::buildGUICamera(SGPropertyNode* cameraNode,
+ GraphicsWindow* window)
+{
+ WindowBuilder *wBuild = WindowBuilder::getWindowBuilder();
+ const SGPropertyNode* windowNode = (cameraNode
+ ? cameraNode->getNode("window")
+ : 0);
+ if (!window && windowNode) {
+ // New style window declaration / definition
+ window = wBuild->buildWindow(windowNode);
+ }
+
+ if (!window) { // buildWindow can fail
+ SG_LOG(SG_VIEW, SG_WARN, "CameraGroup::buildGUICamera: failed to build a window");
+ return NULL;
+ }
+
+ Camera* camera = new Camera;
+ camera->setName( "GUICamera" );
+ camera->setAllowEventFocus(false);
+ camera->setGraphicsContext(window->gc.get());
+ camera->setViewport(new Viewport);
+ camera->setClearMask(0);
+ camera->setInheritanceMask(CullSettings::ALL_VARIABLES
+ & ~(CullSettings::COMPUTE_NEAR_FAR_MODE
+ | CullSettings::CULLING_MODE
+#if defined(HAVE_CULLSETTINGS_CLEAR_MASK)
+ | CullSettings::CLEAR_MASK
+#endif
+ ));
+ camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+ camera->setCullingMode(osg::CullSettings::NO_CULLING);
+ camera->setProjectionResizePolicy(Camera::FIXED);
+ camera->setReferenceFrame(Transform::ABSOLUTE_RF);
+ const int cameraFlags = GUI | DO_INTERSECTION_TEST;
+
+ CameraInfo* result = new CameraInfo(cameraFlags);
+ // The camera group will always update the camera
+ camera->setReferenceFrame(Transform::ABSOLUTE_RF);
+
+ getViewer()->addSlave(camera, Matrixd::identity(), Matrixd::identity(), false);
+ //installCullVisitor(camera);
+ int slaveIndex = getViewer()->getNumSlaves() - 1;
+ result->addCamera( MAIN_CAMERA, camera, slaveIndex );
+ camera->setRenderOrder(Camera::POST_RENDER, slaveIndex);
+ addCamera(result);
+
+ // XXX Camera needs to be drawn last; eventually the render order
+ // should be assigned by a camera manager.
+ camera->setRenderOrder(osg::Camera::POST_RENDER, 10000);
+ SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true);
+ buildViewport(result, viewportNode, window->gc->getTraits());
+
+ // Disable statistics for the GUI camera.
+ camera->setStats(0);
+ result->updateCameras();
+ return result;
+}
+
+CameraGroup* CameraGroup::buildCameraGroup(osgViewer::Viewer* viewer,
+ SGPropertyNode* gnode)
+{
+ sgUserDataInit( globals->get_props() );
+
+ CameraGroup* cgroup = new CameraGroup(viewer);
+ for (int i = 0; i < gnode->nChildren(); ++i) {
+ SGPropertyNode* pNode = gnode->getChild(i);
+ const char* name = pNode->getName();
+ if (!strcmp(name, "camera")) {
+ cgroup->buildCamera(pNode);
+ } else if (!strcmp(name, "window")) {
+ WindowBuilder::getWindowBuilder()->buildWindow(pNode);
+ } else if (!strcmp(name, "gui")) {
+ cgroup->buildGUICamera(pNode);
+ }
+ }
+ bindMemberToNode(gnode, "znear", cgroup, &CameraGroup::_zNear, .1f);
+ bindMemberToNode(gnode, "zfar", cgroup, &CameraGroup::_zFar, 120000.0f);
+ bindMemberToNode(gnode, "near-field", cgroup, &CameraGroup::_nearField,
+ 100.0f);
+ return cgroup;
+}
+
+void CameraGroup::setCameraCullMasks(Node::NodeMask nm)
+{
+ for (CameraIterator i = camerasBegin(), e = camerasEnd(); i != e; ++i) {
+ CameraInfo* info = i->get();
+ if (info->flags & GUI)
+ continue;
+ osg::ref_ptr<osg::Camera> farCamera = info->getCamera(FAR_CAMERA);
+ osg::Camera* camera = info->getCamera( MAIN_CAMERA );
+ if (camera) {
+ if (farCamera.valid() && farCamera->getNodeMask() != 0) {
+ camera->setCullMask(nm & ~simgear::BACKGROUND_BIT);
+ camera->setCullMaskLeft(nm & ~simgear::BACKGROUND_BIT);
+ camera->setCullMaskRight(nm & ~simgear::BACKGROUND_BIT);
+ farCamera->setCullMask(nm);
+ farCamera->setCullMaskLeft(nm);
+ farCamera->setCullMaskRight(nm);
+ } else {
+ camera->setCullMask(nm);
+ camera->setCullMaskLeft(nm);
+ camera->setCullMaskRight(nm);
+ }
+ } else {
+ camera = info->getCamera( GEOMETRY_CAMERA );
+ if (camera == 0) continue;
+ camera->setCullMask( nm & ~simgear::MODELLIGHT_BIT );
+ }
+ }
+}
+
+void CameraGroup::resized()
+{
+ for (CameraIterator i = camerasBegin(), e = camerasEnd(); i != e; ++i) {
+ CameraInfo *info = i->get();
+ Camera* camera = info->getCamera( MAIN_CAMERA );
+ if ( camera == 0 )
+ camera = info->getCamera( DISPLAY_CAMERA );
+ const Viewport* viewport = camera->getViewport();
+ info->x = viewport->x();
+ info->y = viewport->y();
+ info->width = viewport->width();
+ info->height = viewport->height();
+
+ info->resized( info->width, info->height );
+ }
+}
+
+const CameraInfo* CameraGroup::getGUICamera() const
+{
+ ConstCameraIterator result
+ = std::find_if(camerasBegin(), camerasEnd(),
+ FlagTester<CameraInfo>(GUI));
+ if (result == camerasEnd()) {
+ return NULL;
+ }
+
+ return *result;
+}
+
+Camera* getGUICamera(CameraGroup* cgroup)
+{
+ const CameraInfo* info = cgroup->getGUICamera();
+ if (!info) {
+ return NULL;
+ }
+
+ return info->getCamera(MAIN_CAMERA);
+}
+
+static bool computeCameraIntersection(const CameraInfo* cinfo,
+ const osgGA::GUIEventAdapter* ea,
+ osgUtil::LineSegmentIntersector::Intersections& intersections)
+{
+ using osgUtil::Intersector;
+ using osgUtil::LineSegmentIntersector;
+ double x, y;
+ eventToWindowCoords(ea, x, y);
+
+ if (!(cinfo->flags & CameraGroup::DO_INTERSECTION_TEST))
+ return false;
+
+ const Camera* camera = cinfo->getCamera(MAIN_CAMERA);
+ if ( !camera )
+ camera = cinfo->getCamera( GEOMETRY_CAMERA );
+ if (camera->getGraphicsContext() != ea->getGraphicsContext())
+ return false;
+
+ const Viewport* viewport = camera->getViewport();
+ double epsilon = 0.5;
+ if (!(x >= viewport->x() - epsilon
+ && x < viewport->x() + viewport->width() -1.0 + epsilon
+ && y >= viewport->y() - epsilon
+ && y < viewport->y() + viewport->height() -1.0 + epsilon))
+ return false;
+
+ Vec4d start(x, y, 0.0, 1.0);
+ Vec4d end(x, y, 1.0, 1.0);
+ Matrix windowMat = viewport->computeWindowMatrix();
+ Matrix startPtMat = Matrix::inverse(camera->getProjectionMatrix()
+ * windowMat);
+ Matrix endPtMat;
+ const Camera* farCamera = cinfo->getCamera( FAR_CAMERA );
+ if (!farCamera || farCamera->getNodeMask() == 0)
+ endPtMat = startPtMat;
+ else
+ endPtMat = Matrix::inverse(farCamera->getProjectionMatrix()
+ * windowMat);
+ start = start * startPtMat;
+ start /= start.w();
+ end = end * endPtMat;
+ end /= end.w();
+ ref_ptr<LineSegmentIntersector> picker
+ = new LineSegmentIntersector(Intersector::VIEW,
+ Vec3d(start.x(), start.y(), start.z()),
+ Vec3d(end.x(), end.y(), end.z()));
+ osgUtil::IntersectionVisitor iv(picker.get());
+ iv.setTraversalMask( ~simgear::MODELLIGHT_BIT );
+ const_cast<Camera*>(camera)->accept(iv);
+ if (picker->containsIntersections()) {
+ intersections = picker->getIntersections();
+ return true;
+ }
+
+ return false;
+}
+
+bool computeIntersections(const CameraGroup* cgroup,
+ const osgGA::GUIEventAdapter* ea,
+ osgUtil::LineSegmentIntersector::Intersections& intersections)
+{
+ // test the GUI first
+ const CameraInfo* guiCamera = cgroup->getGUICamera();
+ if (guiCamera && computeCameraIntersection(guiCamera, ea, intersections))
+ return true;
+
+ // Find camera that contains event
+ for (CameraGroup::ConstCameraIterator iter = cgroup->camerasBegin(),
+ e = cgroup->camerasEnd();
+ iter != e;
+ ++iter) {
+ const CameraInfo* cinfo = iter->get();
+ if (cinfo == guiCamera)
+ continue;
+
+ if (computeCameraIntersection(cinfo, ea, intersections))
+ return true;
+ }
+
+ intersections.clear();
+ return false;
+}
+
+void warpGUIPointer(CameraGroup* cgroup, int x, int y)
+{
+ using osgViewer::GraphicsWindow;
+ Camera* guiCamera = getGUICamera(cgroup);
+ if (!guiCamera)
+ return;
+ Viewport* vport = guiCamera->getViewport();
+ GraphicsWindow* gw
+ = dynamic_cast<GraphicsWindow*>(guiCamera->getGraphicsContext());
+ if (!gw)
+ return;
+ globals->get_renderer()->getEventHandler()->setMouseWarped();
+ // Translate the warp request into the viewport of the GUI camera,
+ // send the request to the window, then transform the coordinates
+ // for the Viewer's event queue.
+ double wx = x + vport->x();
+ double wyUp = vport->height() + vport->y() - y;
+ double wy;
+ const GraphicsContext::Traits* traits = gw->getTraits();
+ if (gw->getEventQueue()->getCurrentEventState()->getMouseYOrientation()
+ == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS) {
+ wy = traits->height - wyUp;
+ } else {
+ wy = wyUp;
+ }
+ gw->getEventQueue()->mouseWarped(wx, wy);
+ gw->requestWarpPointer(wx, wy);
+ osgGA::GUIEventAdapter* eventState
+ = cgroup->getViewer()->getEventQueue()->getCurrentEventState();
+ double viewerX
+ = (eventState->getXmin()
+ + ((wx / double(traits->width))
+ * (eventState->getXmax() - eventState->getXmin())));
+ double viewerY
+ = (eventState->getYmin()
+ + ((wyUp / double(traits->height))
+ * (eventState->getYmax() - eventState->getYmin())));
+ cgroup->getViewer()->getEventQueue()->mouseWarped(viewerX, viewerY);
+}
+}
--- /dev/null
+// Copyright (C) 2008 Tim Moore
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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 GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef CAMERAGROUP_HXX
+#define CAMERAGROUP_HXX 1
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <osg/Matrix>
+#include <osg/ref_ptr>
+#include <osg/Referenced>
+#include <osg/Node>
+#include <osg/TextureRectangle>
+#include <osg/Texture2D>
+#include <osg/TexGen>
+#include <osgUtil/RenderBin>
+
+// For osgUtil::LineSegmentIntersector::Intersections, which is a typedef.
+#include <osgUtil/LineSegmentIntersector>
+namespace osg
+{
+class Camera;
+}
+
+namespace osgViewer
+{
+class Viewer;
+}
+
+class SGPropertyNode;
+
+namespace flightgear
+{
+
+class GraphicsWindow;
+
+struct RenderBufferInfo {
+ enum Kind {
+ DEPTH_BUFFER,
+ NORMAL_BUFFER,
+ DIFFUSE_BUFFER,
+ SPEC_EMIS_BUFFER,
+ LIGHTING_BUFFER,
+ SHADOW_BUFFER
+ };
+
+ RenderBufferInfo(osg::Texture2D* t = 0, float s = 1.0 ) : texture(t), scaleFactor(s) {}
+ osg::ref_ptr<osg::Texture2D> texture;
+ float scaleFactor;
+};
+typedef std::map<RenderBufferInfo::Kind,RenderBufferInfo> RenderBufferMap;
+typedef std::map<osg::Camera::BufferComponent,size_t> AttachmentMap;
+
+struct RenderStageInfo {
+ RenderStageInfo(osg::Camera* camera_ = 0, int si = -1, bool fs = false)
+ : camera(camera_), slaveIndex(si), scaleFactor(1.0f), fullscreen(fs)
+ , resizable(true)
+ {
+ }
+
+ osg::ref_ptr<osg::Camera> camera;
+ AttachmentMap buffers;
+ int slaveIndex;
+ float scaleFactor;
+ bool fullscreen;
+ bool resizable;
+};
+
+enum CameraKind {
+ MAIN_CAMERA,
+ FAR_CAMERA,
+ GEOMETRY_CAMERA,
+ SHADOW_CAMERA,
+ BLOOM_CAMERA_1,
+ BLOOM_CAMERA_2,
+ AO_CAMERA_1,
+ AO_CAMERA_2,
+ AO_CAMERA_3,
+ LIGHTING_CAMERA,
+ DISPLAY_CAMERA
+};
+typedef std::map<CameraKind,RenderStageInfo> CameraMap;
+
+/** A wrapper around osg::Camera that contains some extra information.
+ */
+struct CameraInfo : public osg::Referenced
+{
+ CameraInfo(unsigned flags_)
+ : flags(flags_),
+ x(0.0), y(0.0), width(0.0), height(0.0),
+ physicalWidth(0), physicalHeight(0), bezelHeightTop(0),
+ bezelHeightBottom(0), bezelWidthLeft(0), bezelWidthRight(0),
+ relativeCameraParent(~0u),
+ bufferSize( new osg::Uniform("fg_BufferSize", osg::Vec2f() ) ),
+ projInverse( new osg::Uniform( "fg_ProjectionMatrixInverse", osg::Matrixf() ) ),
+ viewInverse( new osg::Uniform( "fg_ViewMatrixInverse",osg::Matrixf() ) ),
+ view( new osg::Uniform( "fg_ViewMatrix",osg::Matrixf() ) ),
+ du( new osg::Uniform( "fg_du",osg::Vec4() ) ),
+ dv( new osg::Uniform( "fg_dv",osg::Vec4() ) )
+ {
+ }
+
+ /** Update and resize cameras
+ */
+ void updateCameras();
+ void resized(double w, double h);
+ /** The name as given in the config file.
+ */
+ std::string name;
+ /** Properties of the camera. @see CameraGroup::Flags.
+ */
+ unsigned flags;
+
+ /** Viewport parameters.
+ */
+ double x;
+ double y;
+ double width;
+ double height;
+ /** Physical size parameters.
+ */
+ double physicalWidth;
+ double physicalHeight;
+ double bezelHeightTop;
+ double bezelHeightBottom;
+ double bezelWidthLeft;
+ double bezelWidthRight;
+ /** The parent camera for relative camera configurations.
+ */
+ unsigned relativeCameraParent;
+
+ /** the camera objects
+ */
+ CameraMap cameras;
+ void addCamera( CameraKind k, osg::Camera* c, int si = -1, bool fs = false ) { cameras[k].camera = c; cameras[k].slaveIndex = si; cameras[k].fullscreen = fs; }
+ void addCamera( CameraKind k, osg::Camera* c, bool fs ) { cameras[k].camera = c; cameras[k].fullscreen = fs; }
+ void addCamera( CameraKind k, osg::Camera* c, float s ) { cameras[k].camera = c; cameras[k].scaleFactor = s; }
+ osg::Camera* getCamera(CameraKind k) const;
+ int getMainSlaveIndex() const;
+ RenderStageInfo& getRenderStageInfo( CameraKind k ) { return cameras[k]; }
+
+ /** the buffer objects
+ */
+ RenderBufferMap buffers;
+ void addBuffer(RenderBufferInfo::Kind k, osg::Texture2D* tex, float scale = 1.0 ) { buffers[k] = RenderBufferInfo(tex,scale); }
+ osg::Texture2D* getBuffer(RenderBufferInfo::Kind k) const;
+
+ osg::ref_ptr<osg::TexGen> shadowTexGen[4];
+
+ osg::ref_ptr<osg::Uniform> bufferSize;
+ //osg::ref_ptr<osg::Uniform> bloomOffset[2];
+ osg::ref_ptr<osg::Uniform> projInverse;
+ osg::ref_ptr<osg::Uniform> viewInverse;
+ osg::ref_ptr<osg::Uniform> view;
+ osg::ref_ptr<osg::Uniform> du;
+ osg::ref_ptr<osg::Uniform> dv;
+
+ void setMatrices( osg::Camera* c );
+
+ osgUtil::RenderBin::RenderBinList savedTransparentBins;
+ /** The reference points in the parents projection space.
+ */
+ osg::Vec2d parentReference[2];
+ /** The reference points in the current projection space.
+ */
+ osg::Vec2d thisReference[2];
+};
+
+/** Update the OSG cameras from the camera info.
+ */
+void updateCameras(const CameraInfo* info);
+
+class CameraGroup : public osg::Referenced
+{
+public:
+ /** properties of a camera.
+ */
+ enum Flags
+ {
+ VIEW_ABSOLUTE = 0x1, /**< The camera view is absolute, not
+ relative to the master camera. */
+ PROJECTION_ABSOLUTE = 0x2, /**< The projection is absolute. */
+ ORTHO = 0x4, /**< The projection is orthographic */
+ GUI = 0x8, /**< Camera draws the GUI. */
+ DO_INTERSECTION_TEST = 0x10,/**< scene intersection tests this
+ camera. */
+ FIXED_NEAR_FAR = 0x20, /**< take the near far values in the
+ projection for real. */
+ ENABLE_MASTER_ZOOM = 0x40 /**< Can apply the zoom algorithm. */
+ };
+ /** Create a camera group associated with an osgViewer::Viewer.
+ * @param viewer the viewer
+ */
+ CameraGroup(osgViewer::Viewer* viewer);
+ /** Get the camera group's Viewer.
+ * @return the viewer
+ */
+ osgViewer::Viewer* getViewer() { return _viewer.get(); }
+ /** Create an osg::Camera from a property node and add it to the
+ * camera group.
+ * @param cameraNode the property node.
+ * @return a CameraInfo object for the camera.
+ */
+ CameraInfo* buildCamera(SGPropertyNode* cameraNode);
+ /** Create a camera from properties that will draw the GUI and add
+ * it to the camera group.
+ * @param cameraNode the property node. This can be 0, in which
+ * case a default GUI camera is created.
+ * @param window the GraphicsWindow to use for the GUI camera. If
+ * this is 0, the window is determined from the property node.
+ * @return a CameraInfo object for the GUI camera.
+ */
+ CameraInfo* buildGUICamera(SGPropertyNode* cameraNode,
+ GraphicsWindow* window = 0);
+ /** Update the view for the camera group.
+ * @param position the world position of the view
+ * @param orientation the world orientation of the view.
+ */
+ void update(const osg::Vec3d& position, const osg::Quat& orientation);
+ /** Set the parameters of the viewer's master camera. This won't
+ * affect cameras that have CameraFlags::PROJECTION_ABSOLUTE set.
+ * XXX Should znear and zfar be settable?
+ * @param vfov the vertical field of view angle
+ * @param aspectRatio the master camera's aspect ratio. This
+ * doesn't actually change the viewport, but should reflect the
+ * current viewport.
+ */
+ void setCameraParameters(float vfov, float aspectRatio);
+ /** Set the default CameraGroup, which is the only one that
+ * matters at this time.
+ * @param group the group to set.
+ */
+ static void setDefault(CameraGroup* group) { _defaultGroup = group; }
+ /** Get the default CameraGroup.
+ * @return the default camera group.
+ */
+ static CameraGroup* getDefault() { return _defaultGroup.get(); }
+ typedef std::vector<osg::ref_ptr<CameraInfo> > CameraList;
+ typedef CameraList::iterator CameraIterator;
+ typedef CameraList::const_iterator ConstCameraIterator;
+ /** Get iterator for camera vector. The iterator's value is a ref_ptr.
+ */
+ CameraIterator camerasBegin() { return _cameras.begin(); }
+ /** Get iteator pointing to the end of the camera list.
+ */
+ CameraIterator camerasEnd() { return _cameras.end(); }
+ ConstCameraIterator camerasBegin() const { return _cameras.begin(); }
+ ConstCameraIterator camerasEnd() const { return _cameras.end(); }
+ void addCamera(CameraInfo* info) { _cameras.push_back(info); }
+ /** Build a complete CameraGroup from a property node.
+ * @param viewer the viewer associated with this camera group.
+ * @param the camera group property node.
+ */
+ static CameraGroup* buildCameraGroup(osgViewer::Viewer* viewer,
+ SGPropertyNode* node);
+ /** Set the cull mask on all non-GUI cameras
+ */
+ void setCameraCullMasks(osg::Node::NodeMask nm);
+ /** Update camera properties after a resize event.
+ */
+ void resized();
+
+ void buildDistortionCamera(const SGPropertyNode* psNode,
+ osg::Camera* camera);
+
+ /**
+ * get aspect ratio of master camera's viewport
+ */
+ double getMasterAspectRatio() const;
+
+ /**
+ * find the GUI camera if one is defined
+ */
+ const CameraInfo* getGUICamera() const;
+protected:
+ CameraList _cameras;
+ osg::ref_ptr<osgViewer::Viewer> _viewer;
+ static osg::ref_ptr<CameraGroup> _defaultGroup;
+ // Near, far for the master camera if used.
+ float _zNear;
+ float _zFar;
+ float _nearField;
+ typedef std::map<std::string, osg::ref_ptr<osg::TextureRectangle> > TextureMap;
+ TextureMap _textureTargets;
+};
+
+}
+
+namespace osgGA
+{
+class GUIEventAdapter;
+}
+
+namespace flightgear
+{
+/** Get the osg::Camera that draws the GUI, if any, from a camera
+ * group.
+ * @param cgroup the camera group
+ * @return the GUI camera or 0
+ */
+osg::Camera* getGUICamera(CameraGroup* cgroup);
+/** Choose a camera using an event and do intersection testing on its
+ * view of the scene. Only cameras with the DO_INTERSECTION_TEST flag
+ * set are considered.
+ * @param cgroup the CameraGroup
+ * @param ea the event containing a window and mouse coordinates
+ * @param intersections container for the result of intersection
+ * testing.
+ * @return true if any intersections are found
+ */
+bool computeIntersections(const CameraGroup* cgroup,
+ const osgGA::GUIEventAdapter* ea,
+ osgUtil::LineSegmentIntersector::Intersections&
+ intersections);
+/** Warp the pointer to coordinates in the GUI camera of a camera group.
+ * @param cgroup the camera group
+ * @param x x window coordinate of pointer
+ * @param y y window coordinate of pointer, in "y down" coordinates.
+ */
+void warpGUIPointer(CameraGroup* cgroup, int x, int y);
+}
+#endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <osg/Camera>
+#include <osg/GraphicsContext>
+#include <osg/Math>
+#include <osg/Viewport>
+#include <osgViewer/Viewer>
+
+#include <plib/pu.h>
+#include <Main/fg_props.hxx>
+#include "CameraGroup.hxx"
+#include "FGEventHandler.hxx"
+#include "WindowSystemAdapter.hxx"
+#include "renderer.hxx"
+
+#if !defined(X_DISPLAY_MISSING)
+#define X_DOUBLE_SCROLL_BUG 1
+#endif
+
+#ifdef SG_MAC
+// hack - during interactive resize on Mac, OSG queues and then flushes
+// a large number of resize events, without doing any drawing.
+extern void puCleanUpJunk ( void ) ;
+#endif
+
+namespace flightgear
+{
+const int displayStatsKey = 1;
+const int printStatsKey = 2;
+
+
+// The manipulator is responsible for updating a Viewer's camera. Its
+// event handling method is also a convenient place to run the FG idle
+// and draw handlers.
+
+FGEventHandler::FGEventHandler() :
+ idleHandler(0),
+ keyHandler(0),
+ mouseClickHandler(0),
+ mouseMotionHandler(0),
+ statsHandler(new FGStatsHandler),
+ statsEvent(new osgGA::GUIEventAdapter),
+ statsType(osgViewer::StatsHandler::NO_STATS),
+ currentModifiers(0),
+ resizable(true),
+ mouseWarped(false),
+ scrollButtonPressed(false),
+ changeStatsCameraRenderOrder(false)
+{
+ using namespace osgGA;
+ statsHandler->setKeyEventTogglesOnScreenStats(displayStatsKey);
+ statsHandler->setKeyEventPrintsOutStats(printStatsKey);
+ statsEvent->setEventType(GUIEventAdapter::KEYDOWN);
+
+ // OSG reports NumPad keycodes independent of the NumLock modifier.
+ // Both KP-4 and KP-Left are reported as KEY_KP_Left (0xff96), so we
+ // have to generate the locked keys ourselves.
+ numlockKeyMap[GUIEventAdapter::KEY_KP_Insert] = '0';
+ numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1';
+ numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2';
+ numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = '3';
+ numlockKeyMap[GUIEventAdapter::KEY_KP_Left] = '4';
+ numlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
+ numlockKeyMap[GUIEventAdapter::KEY_KP_Right] = '6';
+ numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7';
+ numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8';
+ numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9';
+ numlockKeyMap[GUIEventAdapter::KEY_KP_Delete] = '.';
+
+ // mapping when NumLock is off
+ noNumlockKeyMap[GUIEventAdapter::KEY_KP_Insert] = PU_KEY_INSERT;
+ noNumlockKeyMap[GUIEventAdapter::KEY_KP_End] = PU_KEY_END;
+ noNumlockKeyMap[GUIEventAdapter::KEY_KP_Down] = PU_KEY_DOWN;
+ noNumlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = PU_KEY_PAGE_DOWN;
+ noNumlockKeyMap[GUIEventAdapter::KEY_KP_Left] = PU_KEY_LEFT;
+ noNumlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
+ noNumlockKeyMap[GUIEventAdapter::KEY_KP_Right] = PU_KEY_RIGHT;
+ noNumlockKeyMap[GUIEventAdapter::KEY_KP_Home] = PU_KEY_HOME;
+ noNumlockKeyMap[GUIEventAdapter::KEY_KP_Up] = PU_KEY_UP;
+ noNumlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = PU_KEY_PAGE_UP;
+ noNumlockKeyMap[GUIEventAdapter::KEY_KP_Delete] = 127;
+
+ for (int i = 0; i < 128; i++)
+ release_keys[i] = i;
+}
+
+namespace
+{
+// Translate OSG modifier mask to FG modifier mask.
+int osgToFGModifiers(int modifiers)
+{
+ int result = 0;
+ if (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT)
+ result |= KEYMOD_SHIFT;
+
+ if (modifiers & osgGA::GUIEventAdapter::MODKEY_CTRL)
+ result |= KEYMOD_CTRL;
+
+ if (modifiers & osgGA::GUIEventAdapter::MODKEY_ALT)
+ result |= KEYMOD_ALT;
+
+ if (modifiers & osgGA::GUIEventAdapter::MODKEY_META)
+ result |= KEYMOD_META;
+
+ if (modifiers & osgGA::GUIEventAdapter::MODKEY_SUPER)
+ result |= KEYMOD_SUPER;
+
+ if (modifiers & osgGA::GUIEventAdapter::MODKEY_HYPER)
+ result |= KEYMOD_HYPER;
+ return result;
+}
+}
+
+#if 0
+void FGEventHandler::init(const osgGA::GUIEventAdapter& ea,
+ osgGA::GUIActionAdapter& us)
+{
+ currentModifiers = osgToFGModifiers(ea.getModKeyMask());
+ (void)handle(ea, us);
+}
+#endif
+
+// Calculate event coordinates in the viewport of the GUI camera, if
+// possible. Otherwise return false and (-1, -1).
+namespace
+{
+bool
+eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
+ int& x, int& y)
+{
+ x = -1;
+ y = -1;
+
+ const osg::GraphicsContext* eventGC = ea.getGraphicsContext();
+ const osg::GraphicsContext::Traits* traits = eventGC->getTraits();
+ osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
+ if (!guiCamera)
+ return false;
+ osg::Viewport* vport = guiCamera->getViewport();
+ if (!vport)
+ return false;
+
+ // Scale x, y to the dimensions of the window
+ double wx = (((ea.getX() - ea.getXmin()) / (ea.getXmax() - ea.getXmin()))
+ * (float)traits->width);
+ double wy = (((ea.getY() - ea.getYmin()) / (ea.getYmax() - ea.getYmin()))
+ * (float)traits->height);
+ if (vport->x() <= wx && wx <= vport->x() + vport->width()
+ && vport->y() <= wy && wy <= vport->y() + vport->height()) {
+ // Finally, into viewport coordinates. Change y to "increasing
+ // downwards".
+ x = wx - vport->x();
+ y = vport->height() - (wy - vport->y());
+ return true;
+ } else {
+ return false;
+ }
+}
+}
+
+bool FGEventHandler::handle(const osgGA::GUIEventAdapter& ea,
+ osgGA::GUIActionAdapter& us)
+{
+ int x = 0;
+ int y = 0;
+
+ switch (ea.getEventType()) {
+ case osgGA::GUIEventAdapter::FRAME:
+ mouseWarped = false;
+ handleStats(us);
+ return true;
+ case osgGA::GUIEventAdapter::KEYDOWN:
+ case osgGA::GUIEventAdapter::KEYUP:
+ {
+ int key, modmask;
+ handleKey(ea, key, modmask);
+ eventToViewport(ea, us, x, y);
+ if (keyHandler)
+ (*keyHandler)(key, modmask, x, y);
+ return true;
+ }
+ case osgGA::GUIEventAdapter::PUSH:
+ case osgGA::GUIEventAdapter::RELEASE:
+ {
+ bool mainWindow = eventToViewport(ea, us, x, y);
+ int button = 0;
+ switch (ea.getButton()) {
+ case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
+ button = 0;
+ break;
+ case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
+ button = 1;
+ break;
+ case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
+ button = 2;
+ break;
+ }
+ if (mouseClickHandler)
+ (*mouseClickHandler)(button,
+ (ea.getEventType()
+ == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea);
+ return true;
+ }
+ case osgGA::GUIEventAdapter::SCROLL:
+ {
+ bool mainWindow = eventToViewport(ea, us, x, y);
+#ifdef X_DOUBLE_SCROLL_BUG
+ scrollButtonPressed = !scrollButtonPressed;
+ if (!scrollButtonPressed) // Drop the button release event
+ return true;
+#endif
+ int button;
+ if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_2D) {
+ if (ea.getScrollingDeltaY() > 0)
+ button = 3;
+ else if (ea.getScrollingDeltaY() < 0)
+ button = 4;
+ else
+ button = -1;
+ } else if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP)
+ button = 3;
+ else
+ button = 4;
+ if (mouseClickHandler && button != -1) {
+ (*mouseClickHandler)(button, 0, x, y, mainWindow, &ea);
+ (*mouseClickHandler)(button, 1, x, y, mainWindow, &ea);
+ }
+ return true;
+ }
+ case osgGA::GUIEventAdapter::MOVE:
+ case osgGA::GUIEventAdapter::DRAG:
+ // If we warped the mouse, then disregard all pointer motion
+ // events for this frame. We really want to flush the event
+ // queue of mouse events, but don't have the ability to do
+ // that with osgViewer.
+ if (mouseWarped)
+ return true;
+ if (eventToViewport(ea, us, x, y) && mouseMotionHandler)
+ (*mouseMotionHandler)(x, y);
+ return true;
+ case osgGA::GUIEventAdapter::RESIZE:
+ SG_LOG(SG_VIEW, SG_DEBUG, "FGEventHandler::handle: RESIZE event " << ea.getWindowHeight() << " x " << ea.getWindowWidth() << ", resizable: " << resizable);
+ CameraGroup::getDefault()->resized();
+ if (resizable)
+ globals->get_renderer()->resize(ea.getWindowWidth(), ea.getWindowHeight());
+ statsHandler->handle(ea, us);
+ #ifdef SG_MAC
+ // work around OSG Cocoa-Viewer issue with resize event handling,
+ // where resize events are queued up, then dispatched in a batch, with
+ // no interveningd drawing calls.
+ puCleanUpJunk();
+ #endif
+ return true;
+ case osgGA::GUIEventAdapter::CLOSE_WINDOW:
+ case osgGA::GUIEventAdapter::QUIT_APPLICATION:
+ fgOSExit(0);
+ return true;
+ default:
+ return false;
+ }
+}
+
+void FGEventHandler::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
+ int& modifiers)
+{
+ using namespace osgGA;
+ key = ea.getKey();
+ // XXX Probably other translations are needed too.
+ switch (key) {
+ case GUIEventAdapter::KEY_Escape: key = 0x1b; break;
+ case GUIEventAdapter::KEY_Return: key = '\n'; break;
+ case GUIEventAdapter::KEY_BackSpace: key = '\b'; break;
+ case GUIEventAdapter::KEY_Delete: key = 0x7f; break;
+ case GUIEventAdapter::KEY_Tab: key = '\t'; break;
+ case GUIEventAdapter::KEY_Left: key = PU_KEY_LEFT; break;
+ case GUIEventAdapter::KEY_Up: key = PU_KEY_UP; break;
+ case GUIEventAdapter::KEY_Right: key = PU_KEY_RIGHT; break;
+ case GUIEventAdapter::KEY_Down: key = PU_KEY_DOWN; break;
+ case GUIEventAdapter::KEY_Page_Up: key = PU_KEY_PAGE_UP; break;
+ case GUIEventAdapter::KEY_Page_Down: key = PU_KEY_PAGE_DOWN; break;
+ case GUIEventAdapter::KEY_Home: key = PU_KEY_HOME; break;
+ case GUIEventAdapter::KEY_End: key = PU_KEY_END; break;
+ case GUIEventAdapter::KEY_Insert: key = PU_KEY_INSERT; break;
+ case GUIEventAdapter::KEY_F1: key = PU_KEY_F1; break;
+ case GUIEventAdapter::KEY_F2: key = PU_KEY_F2; break;
+ case GUIEventAdapter::KEY_F3: key = PU_KEY_F3; break;
+ case GUIEventAdapter::KEY_F4: key = PU_KEY_F4; break;
+ case GUIEventAdapter::KEY_F5: key = PU_KEY_F5; break;
+ case GUIEventAdapter::KEY_F6: key = PU_KEY_F6; break;
+ case GUIEventAdapter::KEY_F7: key = PU_KEY_F7; break;
+ case GUIEventAdapter::KEY_F8: key = PU_KEY_F8; break;
+ case GUIEventAdapter::KEY_F9: key = PU_KEY_F9; break;
+ case GUIEventAdapter::KEY_F10: key = PU_KEY_F10; break;
+ case GUIEventAdapter::KEY_F11: key = PU_KEY_F11; break;
+ case GUIEventAdapter::KEY_F12: key = PU_KEY_F12; break;
+ case GUIEventAdapter::KEY_KP_Enter: key = '\r'; break;
+ case GUIEventAdapter::KEY_KP_Add: key = '+'; break;
+ case GUIEventAdapter::KEY_KP_Divide: key = '/'; break;
+ case GUIEventAdapter::KEY_KP_Multiply: key = '*'; break;
+ case GUIEventAdapter::KEY_KP_Subtract: key = '-'; break;
+ }
+ osgGA::GUIEventAdapter::EventType eventType = ea.getEventType();
+
+#ifdef __APPLE__
+ // Num Lock is always true on Mac
+ std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
+ if (numPadIter != numlockKeyMap.end()) {
+ key = numPadIter->second;
+ }
+#else
+ if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK)
+ {
+ // NumLock on: map to numeric keys
+ std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
+ if (numPadIter != numlockKeyMap.end()) {
+ key = numPadIter->second;
+ }
+ }
+ else
+ {
+ // NumLock off: map to PU arrow keys
+ std::map<int, int>::iterator numPadIter = noNumlockKeyMap.find(key);
+ if (numPadIter != noNumlockKeyMap.end()) {
+ key = numPadIter->second;
+ }
+ }
+#endif
+
+ modifiers = osgToFGModifiers(ea.getModKeyMask());
+ currentModifiers = modifiers;
+ if (eventType == osgGA::GUIEventAdapter::KEYUP)
+ modifiers |= KEYMOD_RELEASED;
+
+ // Release the letter key, for which the key press was reported. This
+ // is to deal with Ctrl-press -> a-press -> Ctrl-release -> a-release
+ // correctly.
+ if (key >= 0 && key < 128) {
+ if (modifiers & KEYMOD_RELEASED) {
+ key = release_keys[key];
+ } else {
+ release_keys[key] = key;
+ if (key >= 1 && key <= 26) {
+ release_keys[key + '@'] = key;
+ release_keys[key + '`'] = key;
+ } else if (key >= 'A' && key <= 'Z') {
+ release_keys[key - '@'] = key;
+ release_keys[tolower(key)] = key;
+ } else if (key >= 'a' && key <= 'z') {
+ release_keys[key - '`'] = key;
+ release_keys[toupper(key)] = key;
+ }
+ }
+ }
+}
+
+void FGEventHandler::handleStats(osgGA::GUIActionAdapter& us)
+{
+ static SGPropertyNode_ptr display = fgGetNode("/sim/rendering/on-screen-statistics", true);
+ static SGPropertyNode_ptr print = fgGetNode("/sim/rendering/print-statistics", true);
+
+ int type = display->getIntValue() % osgViewer::StatsHandler::LAST;
+ if (type != statsType) {
+ statsEvent->setKey(displayStatsKey);
+ do {
+ statsType = (statsType + 1) % osgViewer::StatsHandler::LAST;
+ statsHandler->handle(*statsEvent, us);
+ if (changeStatsCameraRenderOrder) {
+ statsHandler->getCamera()->setRenderOrder(osg::Camera::POST_RENDER, 99999);
+ changeStatsCameraRenderOrder = false;
+ }
+ } while (statsType != type);
+
+ display->setIntValue(statsType);
+ }
+
+ if (print->getBoolValue()) {
+ statsEvent->setKey(printStatsKey);
+ statsHandler->handle(*statsEvent, us);
+ print->setBoolValue(false);
+ }
+}
+
+void eventToWindowCoords(const osgGA::GUIEventAdapter* ea,
+ double& x, double& y)
+{
+ using namespace osg;
+ const GraphicsContext* gc = ea->getGraphicsContext();
+ const GraphicsContext::Traits* traits = gc->getTraits() ;
+ // Scale x, y to the dimensions of the window
+ x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin()))
+ * (double)traits->width);
+ y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin()))
+ * (double)traits->height);
+ if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS)
+ y = (double)traits->height - y;
+}
+
+void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea,
+ double& x, double& y)
+{
+ using namespace osg;
+ const GraphicsContext* gc = ea->getGraphicsContext();
+ const GraphicsContext::Traits* traits = gc->getTraits() ;
+ // Scale x, y to the dimensions of the window
+ x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin()))
+ * (double)traits->width);
+ y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin()))
+ * (double)traits->height);
+ if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS)
+ y = (double)traits->height - y;
+}
+}
--- /dev/null
+#ifndef FGEVENTHANDLER_H
+#define FGEVENTHANDLER_H 1
+
+#include <map>
+#include <osg/Quat>
+#include <osgGA/GUIEventHandler>
+#include <osgViewer/ViewerEventHandlers>
+#include <simgear/structure/OSGVersion.hxx>
+
+#include <Main/fg_os.hxx>
+
+namespace flightgear
+{
+ class FGStatsHandler : public osgViewer::StatsHandler
+ {
+ public:
+ FGStatsHandler()
+ {
+#if (SG_OSG_VERSION >= 30000)
+ // Adjust font type/size for >=OSG3.
+ // OSG defaults aren't working/available for FG.
+ _font = "Fonts/helvetica_medium.txf";
+ _characterSize = 12.0f;
+#endif
+ }
+ };
+
+class FGEventHandler : public osgGA::GUIEventHandler {
+public:
+ FGEventHandler();
+
+ virtual ~FGEventHandler() {}
+
+ virtual const char* className() const {return "FGEventHandler"; }
+#if 0
+ virtual void init(const osgGA::GUIEventAdapter& ea,
+ osgGA::GUIActionAdapter& us);
+#endif
+ virtual bool handle(const osgGA::GUIEventAdapter& ea,
+ osgGA::GUIActionAdapter& us);
+
+ void setIdleHandler(fgIdleHandler idleHandler)
+ {
+ this->idleHandler = idleHandler;
+ }
+
+ fgIdleHandler getIdleHandler() const
+ {
+ return idleHandler;
+ }
+
+ void setKeyHandler(fgKeyHandler keyHandler)
+ {
+ this->keyHandler = keyHandler;
+ }
+
+ fgKeyHandler getKeyHandler() const
+ {
+ return keyHandler;
+ }
+
+ void setMouseClickHandler(fgMouseClickHandler mouseClickHandler)
+ {
+ this->mouseClickHandler = mouseClickHandler;
+ }
+
+ fgMouseClickHandler getMouseClickHandler()
+ {
+ return mouseClickHandler;
+ }
+
+ void setMouseMotionHandler(fgMouseMotionHandler mouseMotionHandler)
+ {
+ this->mouseMotionHandler = mouseMotionHandler;
+ }
+
+ fgMouseMotionHandler getMouseMotionHandler()
+ {
+ return mouseMotionHandler;
+ }
+
+ void setChangeStatsCameraRenderOrder(bool c)
+ {
+ changeStatsCameraRenderOrder = c;
+ }
+
+ int getCurrentModifiers() const
+ {
+ return currentModifiers;
+ }
+
+ void setMouseWarped()
+ {
+ mouseWarped = true;
+ }
+
+ /** Whether or not resizing is supported. It might not be when
+ * using multiple displays.
+ */
+ bool getResizable() { return resizable; }
+ void setResizable(bool _resizable) { resizable = _resizable; }
+
+protected:
+ osg::ref_ptr<osg::Node> _node;
+ fgIdleHandler idleHandler;
+ fgKeyHandler keyHandler;
+ fgMouseClickHandler mouseClickHandler;
+ fgMouseMotionHandler mouseMotionHandler;
+ osg::ref_ptr<FGStatsHandler> statsHandler;
+ osg::ref_ptr<osgGA::GUIEventAdapter> statsEvent;
+ int statsType;
+ int currentModifiers;
+ std::map<int, int> numlockKeyMap;
+ std::map<int, int> noNumlockKeyMap;
+ void handleKey(const osgGA::GUIEventAdapter& ea, int& key, int& modifiers);
+ bool resizable;
+ bool mouseWarped;
+ // workaround for osgViewer double scroll events
+ bool scrollButtonPressed;
+ int release_keys[128];
+ void handleStats(osgGA::GUIActionAdapter& us);
+ bool changeStatsCameraRenderOrder;
+};
+
+void eventToWindowCoords(const osgGA::GUIEventAdapter* ea, double& x, double& y);
+void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea,
+ double& x, double& y);
+}
+#endif
--- /dev/null
+// Copyright (C) 2008 Tim Moore
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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 GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "WindowBuilder.hxx"
+
+#include "WindowSystemAdapter.hxx"
+#include <Main/fg_props.hxx>
+
+#include <sstream>
+
+using namespace std;
+using namespace osg;
+
+namespace flightgear
+{
+string makeName(const string& prefix, int num)
+{
+ stringstream stream;
+ stream << prefix << num;
+ return stream.str();
+}
+
+ref_ptr<WindowBuilder> WindowBuilder::windowBuilder;
+
+const string WindowBuilder::defaultWindowName("FlightGear");
+
+void WindowBuilder::initWindowBuilder(bool stencil)
+{
+ windowBuilder = new WindowBuilder(stencil);
+}
+
+WindowBuilder::WindowBuilder(bool stencil) : defaultCounter(0)
+{
+ defaultTraits = makeDefaultTraits(stencil);
+}
+
+GraphicsContext::Traits*
+WindowBuilder::makeDefaultTraits(bool stencil)
+{
+ GraphicsContext::WindowingSystemInterface* wsi
+ = osg::GraphicsContext::getWindowingSystemInterface();
+ GraphicsContext::Traits* traits = new osg::GraphicsContext::Traits;
+
+ traits->readDISPLAY();
+ if (traits->displayNum < 0)
+ traits->displayNum = 0;
+ if (traits->screenNum < 0)
+ traits->screenNum = 0;
+
+ int bpp = fgGetInt("/sim/rendering/bits-per-pixel");
+ bool alpha = fgGetBool("/sim/rendering/clouds3d-enable");
+ int cbits = (bpp <= 16) ? 5 : 8;
+ int zbits = (bpp <= 16) ? 16 : 24;
+ traits->red = traits->green = traits->blue = cbits;
+ traits->depth = zbits;
+ if (alpha)
+ traits->alpha = 8;
+
+ if (stencil)
+ traits->stencil = 8;
+
+ unsigned screenwidth = 0;
+ unsigned screenheight = 0;
+ wsi->getScreenResolution(*traits, screenwidth, screenheight);
+
+ traits->doubleBuffer = true;
+ traits->mipMapGeneration = true;
+ traits->windowName = "FlightGear";
+ // XXX should check per window too.
+ traits->sampleBuffers = fgGetInt("/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
+ traits->samples = fgGetInt("/sim/rendering/multi-samples", traits->samples);
+ traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync);
+ traits->windowDecoration = !fgGetBool("/sim/startup/fullscreen");
+
+ if (!traits->windowDecoration) {
+ // fullscreen
+ traits->supportsResize = false;
+ traits->width = screenwidth;
+ traits->height = screenheight;
+ SG_LOG(SG_VIEW,SG_DEBUG,"Using full screen size for window: " << screenwidth << " x " << screenheight);
+ } else {
+ // window
+ int w = fgGetInt("/sim/startup/xsize");
+ int h = fgGetInt("/sim/startup/ysize");
+ traits->supportsResize = true;
+ traits->width = w;
+ traits->height = h;
+ if ((w>0)&&(h>0))
+ {
+ traits->x = ((unsigned)w>screenwidth) ? 0 : (screenwidth-w)/3;
+ traits->y = ((unsigned)h>screenheight) ? 0 : (screenheight-h)/3;
+ }
+ SG_LOG(SG_VIEW,SG_DEBUG,"Using initial window size: " << w << " x " << h);
+ }
+ return traits;
+}
+}
+
+namespace
+{
+// Helper functions that set a value based on a property if it exists,
+// returning 1 if the value was set.
+
+inline int setFromProperty(string& place, const SGPropertyNode* node,
+ const char* name)
+{
+ const SGPropertyNode* valNode = node->getNode(name);
+ if (valNode) {
+ place = valNode->getStringValue();
+ return 1;
+ }
+ return 0;
+}
+
+inline int setFromProperty(int& place, const SGPropertyNode* node,
+ const char* name)
+{
+ const SGPropertyNode* valNode = node->getNode(name);
+ if (valNode) {
+ place = valNode->getIntValue();
+ return 1;
+ }
+ return 0;
+}
+
+inline int setFromProperty(bool& place, const SGPropertyNode* node,
+ const char* name)
+{
+ const SGPropertyNode* valNode = node->getNode(name);
+ if (valNode) {
+ place = valNode->getBoolValue();
+ return 1;
+ }
+ return 0;
+}
+}
+
+namespace flightgear
+{
+GraphicsWindow* WindowBuilder::buildWindow(const SGPropertyNode* winNode)
+{
+ GraphicsContext::WindowingSystemInterface* wsi
+ = osg::GraphicsContext::getWindowingSystemInterface();
+ WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
+ string windowName;
+ if (winNode->hasChild("window-name"))
+ windowName = winNode->getStringValue("window-name");
+ else if (winNode->hasChild("name"))
+ windowName = winNode->getStringValue("name");
+ GraphicsWindow* result = 0;
+ if (!windowName.empty()) {
+ result = wsa->findWindow(windowName);
+ if (result)
+ return result;
+ }
+ GraphicsContext::Traits* traits
+ = new GraphicsContext::Traits(*defaultTraits);
+ int traitsSet = setFromProperty(traits->hostName, winNode, "host-name");
+ traitsSet |= setFromProperty(traits->displayNum, winNode, "display");
+ traitsSet |= setFromProperty(traits->screenNum, winNode, "screen");
+
+ const SGPropertyNode* fullscreenNode = winNode->getNode("fullscreen");
+
+ if (fullscreenNode && fullscreenNode->getBoolValue()) {
+ // fullscreen mode
+ unsigned width = 0;
+ unsigned height = 0;
+ wsi->getScreenResolution(*traits, width, height);
+ traits->windowDecoration = false;
+ traits->width = width;
+ traits->height = height;
+ traits->supportsResize = false;
+ traits->x = 0;
+ traits->y = 0;
+ traitsSet = 1;
+ } else {
+ int resizable = 0;
+ if (fullscreenNode && !fullscreenNode->getBoolValue())
+ {
+ traits->windowDecoration = true;
+ resizable = 1;
+ }
+ resizable |= setFromProperty(traits->windowDecoration, winNode,
+ "decoration");
+ resizable |= setFromProperty(traits->width, winNode, "width");
+ resizable |= setFromProperty(traits->height, winNode, "height");
+ if (resizable) {
+ traits->supportsResize = true;
+ traitsSet = 1;
+ }
+ // Otherwise use default values.
+ }
+ traitsSet |= setFromProperty(traits->x, winNode, "x");
+ traitsSet |= setFromProperty(traits->y, winNode, "y");
+ if (!windowName.empty() && windowName != traits->windowName) {
+ traits->windowName = windowName;
+ traitsSet = 1;
+ } else if (traitsSet) {
+ traits->windowName = makeName("FlightGear", defaultCounter++);
+ }
+ bool drawGUI = false;
+ traitsSet |= setFromProperty(drawGUI, winNode, "gui");
+ if (traitsSet) {
+ GraphicsContext* gc = GraphicsContext::createGraphicsContext(traits);
+ if (gc) {
+ GraphicsWindow* window = WindowSystemAdapter::getWSA()
+ ->registerWindow(gc, traits->windowName);
+ if (drawGUI)
+ window->flags |= GraphicsWindow::GUI;
+ return window;
+ } else {
+ return 0;
+ }
+ } else {
+ // XXX What if the window has no traits, but does have a name?
+ // We should create a "default window" registered with that name.
+ return getDefaultWindow();
+ }
+}
+
+GraphicsWindow* WindowBuilder::getDefaultWindow()
+{
+ GraphicsWindow* defaultWindow
+ = WindowSystemAdapter::getWSA()->findWindow(defaultWindowName);
+ if (defaultWindow)
+ return defaultWindow;
+ GraphicsContext::Traits* traits
+ = new GraphicsContext::Traits(*defaultTraits);
+ traits->windowName = "FlightGear";
+
+ GraphicsContext* gc = GraphicsContext::createGraphicsContext(traits);
+ if (gc) {
+ defaultWindow = WindowSystemAdapter::getWSA()
+ ->registerWindow(gc, defaultWindowName);
+ return defaultWindow;
+ } else {
+ SG_LOG(SG_VIEW, SG_ALERT, "getDefaultWindow: failed to create GraphicsContext");
+ return 0;
+ }
+}
+}
--- /dev/null
+// Copyright (C) 2008 Tim Moore
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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 GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef FLIGHTGEAR_WINDOWBUILDER_HXX
+#define FLIGHTGEAR_WINDOWBUILDER_HXX 1
+
+#include <osg/ref_ptr>
+#include <osg/Referenced>
+#include <osg/GraphicsContext>
+
+#include <string>
+
+class SGPropertyNode;
+
+namespace flightgear
+{
+class GraphicsWindow;
+/** Singleton Builder class for creating a GraphicsWindow from property
+ * nodes. This involves initializing an osg::GraphicsContext::Traits
+ * structure from the property node values and creating an
+ * osgViewer::GraphicsWindow.
+ */
+class WindowBuilder : public osg::Referenced
+{
+public:
+ /** Initialize the singleton window builder.
+ * @param stencil whether windows should allocate stencil planes
+ */
+ static void initWindowBuilder(bool stencil);
+ /** Get the singleton window builder
+ */
+ static WindowBuilder* getWindowBuilder() { return windowBuilder.get(); }
+ /** Create a window from its property node description.
+ * @param winNode The window's root property node
+ * @return a graphics window.
+ */
+ GraphicsWindow* buildWindow(const SGPropertyNode* winNode);
+ /** Get a window whose properties come from FlightGear's
+ * command line arguments and their defaults. The window is opened
+ * if it has not been already.
+ * @return the default graphics window
+ */
+ GraphicsWindow* getDefaultWindow();
+ /** Get the name used to look up the default window.
+ */
+ const std::string& getDefaultWindowName() { return defaultWindowName; }
+protected:
+ WindowBuilder(bool stencil);
+ static osg::GraphicsContext::Traits* makeDefaultTraits(bool stencil);
+ osg::ref_ptr<osg::GraphicsContext::Traits> defaultTraits;
+ int defaultCounter;
+ static osg::ref_ptr<WindowBuilder> windowBuilder;
+ static const std::string defaultWindowName;
+};
+
+/** Silly function for making the default window and camera
+ * names. This concatenates a string with in integer.
+ */
+std::string makeName(const std::string& prefix, int num);
+
+}
+#endif
--- /dev/null
+// Copyright (C) 2008 Tim Moore
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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 GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <plib/pu.h>
+
+#include<algorithm>
+#include <functional>
+
+#include "CameraGroup.hxx"
+#include "WindowSystemAdapter.hxx"
+
+#include <osg/Camera>
+#include <osg/GraphicsContext>
+#include <osg/Viewport>
+
+using namespace osg;
+using namespace std;
+
+namespace flightgear
+{
+ref_ptr<WindowSystemAdapter> WindowSystemAdapter::_wsa;
+
+void GraphicsContextOperation::operator()(GraphicsContext* gc)
+{
+ run(gc);
+ ++done;
+}
+
+WindowSystemAdapter::WindowSystemAdapter() :
+ _nextWindowID(0), _isPuInitialized(false)
+{
+}
+
+GraphicsWindow*
+WindowSystemAdapter::registerWindow(GraphicsContext* gc,
+ const string& windowName)
+{
+ GraphicsWindow* window = new GraphicsWindow(gc, windowName,
+ _nextWindowID++);
+ windows.push_back(window);
+ return window;
+}
+
+// The pu getWindow callback is supposed to return a window ID that
+// would allow drawing a GUI on different windows. All that stuff is
+// broken in multi-threaded OSG, and we only have one GUI "window"
+// anyway, so just return a constant.
+int WindowSystemAdapter::puGetWindow()
+{
+ return 1;
+}
+
+void WindowSystemAdapter::puGetWindowSize(int* width, int* height)
+{
+ *width = 0;
+ *height = 0;
+ Camera* camera = getGUICamera(CameraGroup::getDefault());
+ if (!camera)
+ return;
+ Viewport* vport = camera->getViewport();
+ *width = (int)vport->width();
+ *height = (int)vport->height();
+}
+
+void WindowSystemAdapter::puInitialize()
+{
+ puSetWindowFuncs(puGetWindow, 0, puGetWindowSize, 0);
+ puRealInit();
+}
+
+GraphicsWindow* WindowSystemAdapter::findWindow(const string& name)
+{
+ for (WindowVector::iterator iter = windows.begin(), e = windows.end();
+ iter != e;
+ ++iter) {
+ if ((*iter)->name == name)
+ return iter->get();
+ }
+ return 0;
+}
+}
--- /dev/null
+// Copyright (C) 2008 Tim Moore
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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 GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef FLIGHTGEAR_WINDOWSYSTEMADAPTER_HXX
+#define FLIGHTGEAR_WINDOWSYSTEMADAPTER_HXX 1
+
+#include <functional>
+#include <string>
+
+#include <osg/Referenced>
+#include <osg/Camera>
+#include <osg/GraphicsThread>
+#include <osg/ref_ptr>
+
+#include <simgear/structure/SGAtomic.hxx>
+
+namespace osg
+{
+class GraphicsContext;
+}
+
+// Flexible window support
+namespace flightgear
+{
+/** A window with a graphics context and an integer ID
+ */
+class GraphicsWindow : public osg::Referenced
+{
+public:
+ GraphicsWindow(osg::GraphicsContext* gc_, const std::string& name_,
+ int id_, unsigned flags_ = 0) :
+ gc(gc_), name(name_), id(id_), flags(flags_)
+ {
+ }
+ /** The OSG graphics context for this window.
+ */
+ osg::ref_ptr<osg::GraphicsContext> gc;
+ /** The window's internal name.
+ */
+ std::string name;
+ /** A unique ID for the window.
+ */
+ int id;
+ enum Flags {
+ GUI = 1 /**< The GUI (and 2D cockpit) will be drawn on this window. */
+ };
+ /** Flags for the window.
+ */
+ unsigned flags;
+};
+
+typedef std::vector<osg::ref_ptr<GraphicsWindow> > WindowVector;
+
+/**
+ * An operation that is run once with a particular GraphicsContext
+ * current. It will probably be deferred and may run in a different
+ * thread.
+ */
+class GraphicsContextOperation : public osg::GraphicsOperation
+{
+public:
+ GraphicsContextOperation(const std::string& name) :
+ osg::GraphicsOperation(name, false)
+ {
+ }
+ /** Don't override this!
+ */
+ virtual void operator()(osg::GraphicsContext* gc);
+ /** The body of the operation.
+ */
+ virtual void run(osg::GraphicsContext* gc) = 0;
+ /** Test if the operation has completed.
+ * @return true if the run() method has finished.
+ */
+ bool isFinished() const { return done != 0; }
+private:
+ SGAtomic done;
+};
+
+/** Adapter from windows system / graphics context management API to
+ * functions used by flightgear. This papers over the difference
+ * between osgViewer::Viewer, which handles multiple windows, graphics
+ * threads, etc., and the embedded viewer used with GLUT and SDL.
+ */
+class WindowSystemAdapter : public osg::Referenced
+{
+public:
+ WindowSystemAdapter();
+ virtual ~WindowSystemAdapter() {}
+ /** Vector of all the registered windows.
+ */
+ WindowVector windows;
+ /** Register a window, assigning it an ID.
+ * @param gc graphics context
+ * @param windowName internal name (not displayed)
+ * @return a graphics window
+ */
+ GraphicsWindow* registerWindow(osg::GraphicsContext* gc,
+ const std::string& windowName);
+ /** Initialize the plib pui interface library. This might happen
+ *in another thread and may be deferred.
+ */
+ virtual void puInitialize();
+ /** Find a window by name.
+ * @param name the window name
+ * @return the window or 0
+ */
+ GraphicsWindow* findWindow(const std::string& name);
+ /** Get the global WindowSystemAdapter
+ * @return the adapter
+ */
+ static WindowSystemAdapter* getWSA() { return _wsa.get(); }
+ /** Set the global adapter
+ * @param wsa the adapter
+ */
+ static void setWSA(WindowSystemAdapter* wsa) { _wsa = wsa; }
+protected:
+ int _nextWindowID;
+ osg::ref_ptr<GraphicsContextOperation> _puInitOp;
+ bool _isPuInitialized;
+ static osg::ref_ptr<WindowSystemAdapter> _wsa;
+ // Default callbacks for plib
+ static int puGetWindow();
+ static void puGetWindowSize(int* width, int* height);
+
+};
+
+/**
+ * Class for testing if flags are set in an object with a flags member.
+ */
+template<typename T>
+class FlagTester : public std::unary_function<osg::ref_ptr<T>, bool>
+{
+public:
+ /** Initialize with flags to test for.
+ * @param flags logical or of flags to test.
+ */
+ FlagTester(unsigned flags_) : flags(flags_) {}
+ /** test operator
+ * @param obj An object with a flags member
+ * @return true if flags member of obj contains any of the flags
+ * (bitwise and with flags is nonzero).
+ */
+ bool operator() (const osg::ref_ptr<T>& obj)
+ {
+ return (obj->flags & flags) != 0;
+ }
+ unsigned flags;
+};
+
+}
+#endif
--- /dev/null
+// fg_os_osgviewer.cxx -- common functions for fg_os interface
+// implemented as an osgViewer
+//
+// Copyright (C) 2007 Tim Moore timoore@redhat.com
+// Copyright (C) 2007 Mathias Froehlich
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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 GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <stdlib.h>
+
+#include <boost/foreach.hpp>
+
+#include <simgear/compiler.h>
+#include <simgear/structure/exception.hxx>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/props/props_io.hxx>
+
+#include <osg/Camera>
+#include <osg/GraphicsContext>
+#include <osg/Group>
+#include <osg/Matrixd>
+#include <osg/Viewport>
+#include <osg/Version>
+#include <osg/View>
+#include <osgViewer/ViewerEventHandlers>
+#include <osgViewer/Viewer>
+#include <osgViewer/GraphicsWindow>
+
+#include <Scenery/scenery.hxx>
+#include <Main/fg_os.hxx>
+#include <Main/fg_props.hxx>
+#include <Main/util.hxx>
+#include <Main/globals.hxx>
+#include "renderer.hxx"
+#include "CameraGroup.hxx"
+#include "FGEventHandler.hxx"
+#include "WindowBuilder.hxx"
+#include "WindowSystemAdapter.hxx"
+
+// Static linking of OSG needs special macros
+#ifdef OSG_LIBRARY_STATIC
+#include <osgDB/Registry>
+USE_GRAPHICSWINDOW();
+// Image formats
+USE_OSGPLUGIN(bmp);
+USE_OSGPLUGIN(dds);
+USE_OSGPLUGIN(hdr);
+USE_OSGPLUGIN(pic);
+USE_OSGPLUGIN(pnm);
+USE_OSGPLUGIN(rgb);
+USE_OSGPLUGIN(tga);
+#ifdef OSG_JPEG_ENABLED
+ USE_OSGPLUGIN(jpeg);
+#endif
+#ifdef OSG_PNG_ENABLED
+ USE_OSGPLUGIN(png);
+#endif
+#ifdef OSG_TIFF_ENABLED
+ USE_OSGPLUGIN(tiff);
+#endif
+// Model formats
+USE_OSGPLUGIN(3ds);
+USE_OSGPLUGIN(ac);
+USE_OSGPLUGIN(ive);
+USE_OSGPLUGIN(osg);
+USE_OSGPLUGIN(txf);
+#endif
+
+// fg_os implementation using OpenSceneGraph's osgViewer::Viewer class
+// to create the graphics window and run the event/update/render loop.
+
+//
+// fg_os implementation
+//
+
+using namespace std;
+using namespace flightgear;
+using namespace osg;
+
+static osg::ref_ptr<osgViewer::Viewer> viewer;
+static osg::ref_ptr<osg::Camera> mainCamera;
+
+static void setStereoMode( const char * mode )
+{
+ DisplaySettings::StereoMode stereoMode = DisplaySettings::QUAD_BUFFER;
+ bool stereoOn = true;
+
+ if (strcmp(mode,"QUAD_BUFFER")==0)
+ {
+ stereoMode = DisplaySettings::QUAD_BUFFER;
+ }
+ else if (strcmp(mode,"ANAGLYPHIC")==0)
+ {
+ stereoMode = DisplaySettings::ANAGLYPHIC;
+ }
+ else if (strcmp(mode,"HORIZONTAL_SPLIT")==0)
+ {
+ stereoMode = DisplaySettings::HORIZONTAL_SPLIT;
+ }
+ else if (strcmp(mode,"VERTICAL_SPLIT")==0)
+ {
+ stereoMode = DisplaySettings::VERTICAL_SPLIT;
+ }
+ else if (strcmp(mode,"LEFT_EYE")==0)
+ {
+ stereoMode = DisplaySettings::LEFT_EYE;
+ }
+ else if (strcmp(mode,"RIGHT_EYE")==0)
+ {
+ stereoMode = DisplaySettings::RIGHT_EYE;
+ }
+ else if (strcmp(mode,"HORIZONTAL_INTERLACE")==0)
+ {
+ stereoMode = DisplaySettings::HORIZONTAL_INTERLACE;
+ }
+ else if (strcmp(mode,"VERTICAL_INTERLACE")==0)
+ {
+ stereoMode = DisplaySettings::VERTICAL_INTERLACE;
+ }
+ else if (strcmp(mode,"CHECKERBOARD")==0)
+ {
+ stereoMode = DisplaySettings::CHECKERBOARD;
+ } else {
+ stereoOn = false;
+ }
+ DisplaySettings::instance()->setStereo( stereoOn );
+ DisplaySettings::instance()->setStereoMode( stereoMode );
+}
+
+static const char * getStereoMode()
+{
+ DisplaySettings::StereoMode stereoMode = DisplaySettings::instance()->getStereoMode();
+ bool stereoOn = DisplaySettings::instance()->getStereo();
+ if( !stereoOn ) return "OFF";
+ if( stereoMode == DisplaySettings::QUAD_BUFFER ) {
+ return "QUAD_BUFFER";
+ } else if( stereoMode == DisplaySettings::ANAGLYPHIC ) {
+ return "ANAGLYPHIC";
+ } else if( stereoMode == DisplaySettings::HORIZONTAL_SPLIT ) {
+ return "HORIZONTAL_SPLIT";
+ } else if( stereoMode == DisplaySettings::VERTICAL_SPLIT ) {
+ return "VERTICAL_SPLIT";
+ } else if( stereoMode == DisplaySettings::LEFT_EYE ) {
+ return "LEFT_EYE";
+ } else if( stereoMode == DisplaySettings::RIGHT_EYE ) {
+ return "RIGHT_EYE";
+ } else if( stereoMode == DisplaySettings::HORIZONTAL_INTERLACE ) {
+ return "HORIZONTAL_INTERLACE";
+ } else if( stereoMode == DisplaySettings::VERTICAL_INTERLACE ) {
+ return "VERTICAL_INTERLACE";
+ } else if( stereoMode == DisplaySettings::CHECKERBOARD ) {
+ return "CHECKERBOARD";
+ }
+ return "OFF";
+}
+
+void fgOSOpenWindow(bool stencil)
+{
+ viewer = new osgViewer::Viewer;
+ viewer->setDatabasePager(FGScenery::getPagerSingleton());
+ CameraGroup* cameraGroup = 0;
+ std::string mode;
+ mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
+ if (mode == "AutomaticSelection")
+ viewer->setThreadingModel(osgViewer::Viewer::AutomaticSelection);
+ else if (mode == "CullDrawThreadPerContext")
+ viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
+ else if (mode == "DrawThreadPerContext")
+ viewer->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
+ else if (mode == "CullThreadPerCameraDrawThreadPerContext")
+ viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
+ else
+ viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
+ WindowBuilder::initWindowBuilder(stencil);
+ WindowBuilder *windowBuilder = WindowBuilder::getWindowBuilder();
+
+ // Look for windows, camera groups, and the old syntax of
+ // top-level cameras
+ SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
+ SGPropertyNode* cgroupNode = renderingNode->getNode("camera-group", true);
+ bool oldSyntax = !cgroupNode->hasChild("camera");
+ if (oldSyntax) {
+ for (int i = 0; i < renderingNode->nChildren(); ++i) {
+ SGPropertyNode* propNode = renderingNode->getChild(i);
+ const char* propName = propNode->getName();
+ if (!strcmp(propName, "window") || !strcmp(propName, "camera")) {
+ SGPropertyNode* copiedNode
+ = cgroupNode->getNode(propName, propNode->getIndex(), true);
+ copyProperties(propNode, copiedNode);
+ }
+ }
+ vector<SGPropertyNode_ptr> cameras = cgroupNode->getChildren("camera");
+ SGPropertyNode* masterCamera = 0;
+ BOOST_FOREACH(SGPropertyNode_ptr& camera, cameras) {
+ if (camera->getDoubleValue("shear-x", 0.0) == 0.0
+ && camera->getDoubleValue("shear-y", 0.0) == 0.0) {
+ masterCamera = camera.ptr();
+ break;
+ }
+ }
+ if (!masterCamera) {
+ masterCamera = cgroupNode->getChild("camera", cameras.size(), true);
+ setValue(masterCamera->getNode("window/name", true),
+ windowBuilder->getDefaultWindowName());
+ }
+ SGPropertyNode* nameNode = masterCamera->getNode("window/name");
+ if (nameNode)
+ setValue(cgroupNode->getNode("gui/window/name", true),
+ nameNode->getStringValue());
+ }
+ cameraGroup = CameraGroup::buildCameraGroup(viewer.get(), cgroupNode);
+ Camera* guiCamera = getGUICamera(cameraGroup);
+ if (guiCamera) {
+ Viewport* guiViewport = guiCamera->getViewport();
+ fgSetInt("/sim/startup/xsize", guiViewport->width());
+ fgSetInt("/sim/startup/ysize", guiViewport->height());
+ }
+ FGEventHandler* manipulator = globals->get_renderer()->getEventHandler();
+ WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
+ if (wsa->windows.size() != 1) {
+ manipulator->setResizable(false);
+ }
+ viewer->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);
+ viewer->addEventHandler(manipulator);
+ // Let FG handle the escape key with a confirmation
+ viewer->setKeyEventSetsDone(0);
+ // The viewer won't start without some root.
+ viewer->setSceneData(new osg::Group);
+ globals->get_renderer()->setViewer(viewer.get());
+ CameraGroup::setDefault(cameraGroup);
+
+ DisplaySettings * displaySettings = DisplaySettings::instance();
+ fgTie("/sim/rendering/osg-displaysettings/eye-separation", displaySettings, &DisplaySettings::getEyeSeparation, &DisplaySettings::setEyeSeparation );
+ fgTie("/sim/rendering/osg-displaysettings/screen-distance", displaySettings, &DisplaySettings::getScreenDistance, &DisplaySettings::setScreenDistance );
+ fgTie("/sim/rendering/osg-displaysettings/screen-width", displaySettings, &DisplaySettings::getScreenWidth, &DisplaySettings::setScreenWidth );
+ fgTie("/sim/rendering/osg-displaysettings/screen-height", displaySettings, &DisplaySettings::getScreenHeight, &DisplaySettings::setScreenHeight );
+ fgTie("/sim/rendering/osg-displaysettings/stereo-mode", getStereoMode, setStereoMode );
+ fgTie("/sim/rendering/osg-displaysettings/double-buffer", displaySettings, &DisplaySettings::getDoubleBuffer, &DisplaySettings::setDoubleBuffer );
+ fgTie("/sim/rendering/osg-displaysettings/depth-buffer", displaySettings, &DisplaySettings::getDepthBuffer, &DisplaySettings::setDepthBuffer );
+ fgTie("/sim/rendering/osg-displaysettings/rgb", displaySettings, &DisplaySettings::getRGB, &DisplaySettings::setRGB );
+}
+
+
+static int status = 0;
+
+void fgOSExit(int code)
+{
+ viewer->setDone(true);
+ viewer->getDatabasePager()->cancel();
+ status = code;
+}
+
+int fgOSMainLoop()
+{
+ ref_ptr<FGEventHandler> manipulator
+ = globals->get_renderer()->getEventHandler();
+ viewer->setReleaseContextAtEndOfFrameHint(false);
+ if (!viewer->isRealized())
+ viewer->realize();
+ while (!viewer->done()) {
+ fgIdleHandler idleFunc = manipulator->getIdleHandler();
+ if (idleFunc)
+ (*idleFunc)();
+ globals->get_renderer()->update();
+ viewer->frame();
+ }
+
+ return status;
+}
+
+int fgGetKeyModifiers()
+{
+ if (!globals->get_renderer()) { // happens during shutdown
+ return 0;
+ }
+
+ return globals->get_renderer()->getEventHandler()->getCurrentModifiers();
+}
+
+void fgWarpMouse(int x, int y)
+{
+ warpGUIPointer(CameraGroup::getDefault(), x, y);
+}
+
+void fgOSInit(int* argc, char** argv)
+{
+ globals->get_renderer()->init();
+ WindowSystemAdapter::setWSA(new WindowSystemAdapter);
+}
+
+// Noop
+void fgOSFullScreen()
+{
+}
+
+static void setMouseCursor(osgViewer::GraphicsWindow* gw, int cursor)
+{
+ if (!gw) {
+ return;
+ }
+
+ osgViewer::GraphicsWindow::MouseCursor mouseCursor;
+ mouseCursor = osgViewer::GraphicsWindow::InheritCursor;
+ if (cursor == MOUSE_CURSOR_NONE)
+ mouseCursor = osgViewer::GraphicsWindow::NoCursor;
+ else if(cursor == MOUSE_CURSOR_POINTER)
+#ifdef SG_MAC
+ // osgViewer-Cocoa lacks RightArrowCursor, use Left
+ mouseCursor = osgViewer::GraphicsWindow::LeftArrowCursor;
+#else
+ mouseCursor = osgViewer::GraphicsWindow::RightArrowCursor;
+#endif
+ else if(cursor == MOUSE_CURSOR_WAIT)
+ mouseCursor = osgViewer::GraphicsWindow::WaitCursor;
+ else if(cursor == MOUSE_CURSOR_CROSSHAIR)
+ mouseCursor = osgViewer::GraphicsWindow::CrosshairCursor;
+ else if(cursor == MOUSE_CURSOR_LEFTRIGHT)
+ mouseCursor = osgViewer::GraphicsWindow::LeftRightCursor;
+ else if(cursor == MOUSE_CURSOR_TOPSIDE)
+ mouseCursor = osgViewer::GraphicsWindow::TopSideCursor;
+ else if(cursor == MOUSE_CURSOR_BOTTOMSIDE)
+ mouseCursor = osgViewer::GraphicsWindow::BottomSideCursor;
+ else if(cursor == MOUSE_CURSOR_LEFTSIDE)
+ mouseCursor = osgViewer::GraphicsWindow::LeftSideCursor;
+ else if(cursor == MOUSE_CURSOR_RIGHTSIDE)
+ mouseCursor = osgViewer::GraphicsWindow::RightSideCursor;
+ else if(cursor == MOUSE_CURSOR_TOPLEFT)
+ mouseCursor = osgViewer::GraphicsWindow::TopLeftCorner;
+ else if(cursor == MOUSE_CURSOR_TOPRIGHT)
+ mouseCursor = osgViewer::GraphicsWindow::TopRightCorner;
+ else if(cursor == MOUSE_CURSOR_BOTTOMLEFT)
+ mouseCursor = osgViewer::GraphicsWindow::BottomLeftCorner;
+ else if(cursor == MOUSE_CURSOR_BOTTOMRIGHT)
+ mouseCursor = osgViewer::GraphicsWindow::BottomRightCorner;
+
+ gw->setCursor(mouseCursor);
+}
+
+static int _cursor = -1;
+
+void fgSetMouseCursor(int cursor)
+{
+ _cursor = cursor;
+
+ std::vector<osgViewer::GraphicsWindow*> windows;
+ viewer->getWindows(windows);
+ BOOST_FOREACH(osgViewer::GraphicsWindow* gw, windows) {
+ setMouseCursor(gw, cursor);
+ }
+}
+
+int fgGetMouseCursor()
+{
+ return _cursor;
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <iostream>
+#include <cstdlib>
+
+#include <osg/ArgumentParser>
+#include <osg/Fog>
+#include <osgDB/ReadFile>
+#include <osgDB/Registry>
+#include <osgDB/WriteFile>
+#include <osgViewer/Renderer>
+#include <osgViewer/Viewer>
+#include <osgViewer/ViewerEventHandlers>
+#include <osgGA/KeySwitchMatrixManipulator>
+#include <osgGA/TrackballManipulator>
+#include <osgGA/FlightManipulator>
+#include <osgGA/DriveManipulator>
+#include <osgGA/TerrainManipulator>
+#include <osgGA/StateSetManipulator>
+
+#include <simgear/props/props.hxx>
+#include <simgear/props/props_io.hxx>
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/scene/material/EffectCullVisitor.hxx>
+#include <simgear/scene/material/matlib.hxx>
+#include <simgear/scene/util/SGReaderWriterOptions.hxx>
+#include <simgear/scene/tgdb/userdata.hxx>
+#include <simgear/scene/model/ModelRegistry.hxx>
+#include <simgear/scene/model/modellib.hxx>
+
+#include <Scenery/scenery.hxx>
+
+#include <Main/fg_props.hxx>
+#include <Main/globals.hxx>
+#include <Main/options.hxx>
+#include <Main/fg_init.hxx>
+
+class GraphDumpHandler : public osgGA::GUIEventHandler
+{
+public:
+ GraphDumpHandler() : _keyDump('d') {}
+ void setKeyDump(int key) { _keyDump = key; }
+ int getKeyDump() const { return _keyDump; }
+ bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);
+
+ /** Get the keyboard and mouse usage of this manipulator.*/
+ virtual void getUsage(osg::ApplicationUsage& usage) const;
+protected:
+ int _keyDump;
+};
+
+static void dumpOut(osg::Node* node)
+{
+ char filename[24];
+ static int count = 1;
+
+ while (count < 1000) {
+ FILE *fp;
+ snprintf(filename, 24, "fgviewer-%03d.osg", count++);
+ if ( (fp = fopen(filename, "r")) == NULL )
+ break;
+ fclose(fp);
+ }
+
+ if (osgDB::writeNodeFile(*node, filename))
+ std::cerr << "Entire scene graph saved to \"" << filename << "\".\n";
+ else
+ std::cerr << "Failed to save to \"" << filename << "\".\n";
+}
+
+bool GraphDumpHandler::handle(const osgGA::GUIEventAdapter& ea,
+ osgGA::GUIActionAdapter& aa)
+{
+ osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
+ if (!view)
+ return false;
+ if (ea.getHandled())
+ return false;
+ switch(ea.getEventType()) {
+ case osgGA::GUIEventAdapter::KEYUP:
+ if (ea.getKey() == _keyDump) {
+ dumpOut(view->getScene()->getSceneData());
+ return true;
+ }
+ break;
+ default:
+ return false;
+ }
+ return false;
+}
+
+void GraphDumpHandler::getUsage(osg::ApplicationUsage& usage) const
+{
+ std::ostringstream ostr;
+ ostr << char(_keyDump);
+ usage.addKeyboardMouseBinding(ostr.str(),
+ "Dump scene graph to file");
+}
+
+int
+fgviewerMain(int argc, char** argv)
+{
+
+ sgUserDataInit(0);
+
+ // use an ArgumentParser object to manage the program arguments.
+ osg::ArgumentParser arguments(&argc, argv);
+
+ // construct the viewer.
+ osgViewer::Viewer viewer(arguments);
+ osg::Camera* camera = viewer.getCamera();
+ osgViewer::Renderer* renderer
+ = static_cast<osgViewer::Renderer*>(camera->getRenderer());
+ for (int i = 0; i < 2; ++i) {
+ osgUtil::SceneView* sceneView = renderer->getSceneView(i);
+ sceneView->setCullVisitor(new simgear::EffectCullVisitor);
+ }
+ // Shaders expect valid fog
+ osg::StateSet* cameraSS = camera->getOrCreateStateSet();
+ osg::Fog* fog = new osg::Fog;
+ fog->setMode(osg::Fog::EXP2);
+ fog->setColor(osg::Vec4(1.0, 1.0, 1.0, 1.0));
+ fog->setDensity(.0000001);
+ cameraSS->setAttributeAndModes(fog);
+ // ... for some reason, get rid of that FIXME!
+ viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
+
+ // set up the camera manipulators.
+ osgGA::KeySwitchMatrixManipulator* keyswitchManipulator;
+ 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);
+ viewer.setCameraManipulator(keyswitchManipulator);
+
+ // Usefull stats
+ viewer.addEventHandler(new osgViewer::HelpHandler);
+ viewer.addEventHandler(new osgViewer::StatsHandler);
+ viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
+ // Same FIXME ...
+ // viewer.addEventHandler(new osgViewer::ThreadingHandler);
+ viewer.addEventHandler(new osgViewer::LODScaleHandler);
+ viewer.addEventHandler(new osgViewer::ScreenCaptureHandler);
+
+ viewer.addEventHandler(new GraphDumpHandler);
+
+ // Extract files to load from arguments now; this way fgInitConfig
+ // won't choke on them.
+ string_list dataFiles;
+ for (int i = arguments.argc() - 1; i >= 0; --i) {
+ if (arguments.isOption(i)) {
+ break;
+ } else {
+ dataFiles.insert(dataFiles.begin(), arguments[i]);
+ arguments.remove(i);
+ }
+ }
+
+ // A subset of full flightgear initialization.
+ // Allocate global data structures. This needs to happen before
+ // we parse command line options
+
+ globals = new FGGlobals;
+
+ if ( !fgInitConfig(arguments.argc(), arguments.argv()) ) {
+ SG_LOG( SG_GENERAL, SG_ALERT, "Config option parsing failed ..." );
+ exit(-1);
+ }
+
+ osgDB::FilePathList filePathList
+ = osgDB::Registry::instance()->getDataFilePathList();
+ filePathList.push_back(globals->get_fg_root());
+
+ string_list path_list = globals->get_fg_scenery();
+ for (unsigned i = 0; i < path_list.size(); ++i) {
+ filePathList.push_back(path_list[i]);
+ }
+
+ globals->set_matlib( new SGMaterialLib );
+ simgear::SGModelLib::init(globals->get_fg_root(), globals->get_props());
+
+ // Initialize the material property subsystem.
+
+ SGPath mpath( globals->get_fg_root() );
+ mpath.append( fgGetString("/sim/rendering/materials-file") );
+ if ( ! globals->get_matlib()->load(globals->get_fg_root(), mpath.str(),
+ globals->get_props()) ) {
+ SG_LOG( SG_GENERAL, SG_ALERT,
+ "Error loading materials file " << mpath.str() );
+ exit(-1);
+ }
+
+ globals->set_scenery( new FGScenery );
+ globals->get_scenery()->init();
+ globals->get_scenery()->bind();
+
+ // The file path list must be set in the registry.
+ osgDB::Registry::instance()->getDataFilePathList() = filePathList;
+
+ simgear::SGReaderWriterOptions* options = new simgear::SGReaderWriterOptions;
+ options->getDatabasePathList() = filePathList;
+ options->setMaterialLib(globals->get_matlib());
+ options->setPropertyNode(globals->get_props());
+
+ // read the scene from the list of file specified command line args.
+ osg::ref_ptr<osg::Node> loadedModel;
+ loadedModel = osgDB::readNodeFiles(dataFiles, options);
+
+ // if no model has been successfully loaded report failure.
+ if (!loadedModel.valid()) {
+ std::cerr << arguments.getApplicationName()
+ << ": No data loaded" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ // pass the loaded scene graph to the viewer.
+ viewer.setSceneData(loadedModel.get());
+
+ return viewer.run();
+}
--- /dev/null
+#ifndef __FG_FGVIEWER_HXX
+#define __FG_FGVIEWER_HXX 1
+
+int fgviewerMain(int argc, char** argv);
+#endif
--- /dev/null
+// renderer.cxx -- top level sim routines
+//
+// Written by Curtis Olson, started May 1997.
+// This file contains parts of main.cxx prior to october 2004
+//
+// Copyright (C) 1997 - 2002 Curtis L. Olson - http://www.flightgear.org/~curt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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 GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_WINDOWS_H
+# include <windows.h>
+#endif
+
+#include <simgear/compiler.h>
+
+#include <algorithm>
+#include <iostream>
+#include <map>
+#include <vector>
+#include <typeinfo>
+
+#include <osg/ref_ptr>
+#include <osg/AlphaFunc>
+#include <osg/BlendFunc>
+#include <osg/Camera>
+#include <osg/CullFace>
+#include <osg/CullStack>
+#include <osg/Depth>
+#include <osg/Fog>
+#include <osg/Group>
+#include <osg/Hint>
+#include <osg/Light>
+#include <osg/LightModel>
+#include <osg/LightSource>
+#include <osg/Material>
+#include <osg/Math>
+#include <osg/NodeCallback>
+#include <osg/Notify>
+#include <osg/PolygonMode>
+#include <osg/PolygonOffset>
+#include <osg/Program>
+#include <osg/Version>
+#include <osg/TexEnv>
+
+#include <osgUtil/LineSegmentIntersector>
+
+#include <osg/io_utils>
+#include <osgDB/WriteFile>
+#include <osgViewer/Renderer>
+
+#include <simgear/math/SGMath.hxx>
+#include <simgear/scene/material/matlib.hxx>
+#include <simgear/scene/material/EffectCullVisitor.hxx>
+#include <simgear/scene/material/Effect.hxx>
+#include <simgear/scene/material/EffectGeode.hxx>
+#include <simgear/scene/model/animation.hxx>
+#include <simgear/scene/model/placement.hxx>
+#include <simgear/scene/sky/sky.hxx>
+#include <simgear/scene/util/SGUpdateVisitor.hxx>
+#include <simgear/scene/util/RenderConstants.hxx>
+#include <simgear/scene/util/SGSceneUserData.hxx>
+#include <simgear/scene/tgdb/GroundLightManager.hxx>
+#include <simgear/scene/tgdb/pt_lights.hxx>
+#include <simgear/structure/OSGUtils.hxx>
+#include <simgear/props/props.hxx>
+#include <simgear/timing/sg_time.hxx>
+#include <simgear/ephemeris/ephemeris.hxx>
+#include <simgear/math/sg_random.h>
+#ifdef FG_JPEG_SERVER
+#include <simgear/screen/jpgfactory.hxx>
+#endif
+
+#include <Time/light.hxx>
+#include <Time/light.hxx>
+#include <Cockpit/panel.hxx>
+
+#include <Model/panelnode.hxx>
+#include <Model/modelmgr.hxx>
+#include <Model/acmodel.hxx>
+#include <Scenery/scenery.hxx>
+#include <Scenery/redout.hxx>
+#include <GUI/new_gui.hxx>
+#include <Instrumentation/HUD/HUD.hxx>
+#include <Environment/precipitation_mgr.hxx>
+#include <Environment/environment_mgr.hxx>
+
+//#include <Main/main.hxx>
+#include "viewer.hxx"
+#include "viewmgr.hxx"
+#include "splash.hxx"
+#include "renderer.hxx"
+#include "CameraGroup.hxx"
+#include "FGEventHandler.hxx"
+
+using namespace osg;
+using namespace simgear;
+using namespace flightgear;
+
+class FGHintUpdateCallback : public osg::StateAttribute::Callback {
+public:
+ FGHintUpdateCallback(const char* configNode) :
+ mConfigNode(fgGetNode(configNode, true))
+ { }
+ virtual void operator()(osg::StateAttribute* stateAttribute,
+ osg::NodeVisitor*)
+ {
+ assert(dynamic_cast<osg::Hint*>(stateAttribute));
+ osg::Hint* hint = static_cast<osg::Hint*>(stateAttribute);
+
+ const char* value = mConfigNode->getStringValue();
+ if (!value)
+ hint->setMode(GL_DONT_CARE);
+ else if (0 == strcmp(value, "nicest"))
+ hint->setMode(GL_NICEST);
+ else if (0 == strcmp(value, "fastest"))
+ hint->setMode(GL_FASTEST);
+ else
+ hint->setMode(GL_DONT_CARE);
+ }
+private:
+ SGPropertyNode_ptr mConfigNode;
+};
+
+
+class SGPuDrawable : public osg::Drawable {
+public:
+ SGPuDrawable()
+ {
+ // Dynamic stuff, do not store geometry
+ setUseDisplayList(false);
+ setDataVariance(Object::DYNAMIC);
+
+ osg::StateSet* stateSet = getOrCreateStateSet();
+ stateSet->setRenderBinDetails(1001, "RenderBin");
+ // speed optimization?
+ stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
+ // We can do translucent menus, so why not. :-)
+ stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
+ stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
+ stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF);
+
+ stateSet->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE));
+
+ stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
+ stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
+ }
+ virtual void drawImplementation(osg::RenderInfo& renderInfo) const
+ { drawImplementation(*renderInfo.getState()); }
+ void drawImplementation(osg::State& state) const
+ {
+ state.setActiveTextureUnit(0);
+ state.setClientActiveTextureUnit(0);
+
+ state.disableAllVertexArrays();
+
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+ glPushClientAttrib(~0u);
+
+ puDisplay();
+
+ glPopClientAttrib();
+ glPopAttrib();
+ }
+
+ virtual osg::Object* cloneType() const { return new SGPuDrawable; }
+ virtual osg::Object* clone(const osg::CopyOp&) const { return new SGPuDrawable; }
+
+private:
+};
+
+class SGHUDDrawable : public osg::Drawable {
+public:
+ SGHUDDrawable()
+ {
+ // Dynamic stuff, do not store geometry
+ setUseDisplayList(false);
+ setDataVariance(Object::DYNAMIC);
+
+ osg::StateSet* stateSet = getOrCreateStateSet();
+ stateSet->setRenderBinDetails(1000, "RenderBin");
+
+ // speed optimization?
+ stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
+ stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
+ stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
+ stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
+ stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
+
+ stateSet->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE));
+ }
+ virtual void drawImplementation(osg::RenderInfo& renderInfo) const
+ { drawImplementation(*renderInfo.getState()); }
+ void drawImplementation(osg::State& state) const
+ {
+ state.setActiveTextureUnit(0);
+ state.setClientActiveTextureUnit(0);
+ state.disableAllVertexArrays();
+
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+ glPushClientAttrib(~0u);
+
+ HUD *hud = static_cast<HUD*>(globals->get_subsystem("hud"));
+ hud->draw(state);
+
+ glPopClientAttrib();
+ glPopAttrib();
+ }
+
+ virtual osg::Object* cloneType() const { return new SGHUDDrawable; }
+ virtual osg::Object* clone(const osg::CopyOp&) const { return new SGHUDDrawable; }
+
+private:
+};
+
+class FGLightSourceUpdateCallback : public osg::NodeCallback {
+public:
+
+ /**
+ * @param isSun true if the light is the actual sun i.e., for
+ * illuminating the moon.
+ */
+ FGLightSourceUpdateCallback(bool isSun = false) : _isSun(isSun) {}
+ FGLightSourceUpdateCallback(const FGLightSourceUpdateCallback& nc,
+ const CopyOp& op)
+ : NodeCallback(nc, op), _isSun(nc._isSun)
+ {}
+ META_Object(flightgear,FGLightSourceUpdateCallback);
+
+ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
+ {
+ assert(dynamic_cast<osg::LightSource*>(node));
+ osg::LightSource* lightSource = static_cast<osg::LightSource*>(node);
+ osg::Light* light = lightSource->getLight();
+
+ FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
+ if (_isSun) {
+ light->setAmbient(Vec4(0.0f, 0.0f, 0.0f, 0.0f));
+ light->setDiffuse(Vec4(1.0f, 1.0f, 1.0f, 1.0f));
+ light->setSpecular(Vec4(0.0f, 0.0f, 0.0f, 0.0f));
+ } else {
+ light->setAmbient(toOsg(l->scene_ambient()));
+ light->setDiffuse(toOsg(l->scene_diffuse()));
+ light->setSpecular(toOsg(l->scene_specular()));
+ }
+ osg::Vec4f position(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2], 0);
+ light->setPosition(position);
+
+ traverse(node, nv);
+ }
+private:
+ const bool _isSun;
+};
+
+class FGWireFrameModeUpdateCallback : public osg::StateAttribute::Callback {
+public:
+ FGWireFrameModeUpdateCallback() :
+ mWireframe(fgGetNode("/sim/rendering/wireframe", true))
+ { }
+ virtual void operator()(osg::StateAttribute* stateAttribute,
+ osg::NodeVisitor*)
+ {
+ assert(dynamic_cast<osg::PolygonMode*>(stateAttribute));
+ osg::PolygonMode* polygonMode;
+ polygonMode = static_cast<osg::PolygonMode*>(stateAttribute);
+
+ if (mWireframe->getBoolValue())
+ polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
+ osg::PolygonMode::LINE);
+ else
+ polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
+ osg::PolygonMode::FILL);
+ }
+private:
+ SGPropertyNode_ptr mWireframe;
+};
+
+class FGLightModelUpdateCallback : public osg::StateAttribute::Callback {
+public:
+ FGLightModelUpdateCallback() :
+ mHighlights(fgGetNode("/sim/rendering/specular-highlight", true))
+ { }
+ virtual void operator()(osg::StateAttribute* stateAttribute,
+ osg::NodeVisitor*)
+ {
+ assert(dynamic_cast<osg::LightModel*>(stateAttribute));
+ osg::LightModel* lightModel;
+ lightModel = static_cast<osg::LightModel*>(stateAttribute);
+
+#if 0
+ FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
+ lightModel->setAmbientIntensity(toOsg(l->scene_ambient());
+#else
+ lightModel->setAmbientIntensity(osg::Vec4(0, 0, 0, 1));
+#endif
+ lightModel->setTwoSided(true);
+ lightModel->setLocalViewer(false);
+
+ if (mHighlights->getBoolValue()) {
+ lightModel->setColorControl(osg::LightModel::SEPARATE_SPECULAR_COLOR);
+ } else {
+ lightModel->setColorControl(osg::LightModel::SINGLE_COLOR);
+ }
+ }
+private:
+ SGPropertyNode_ptr mHighlights;
+};
+
+class FGFogEnableUpdateCallback : public osg::StateSet::Callback {
+public:
+ FGFogEnableUpdateCallback() :
+ mFogEnabled(fgGetNode("/sim/rendering/fog", true))
+ { }
+ virtual void operator()(osg::StateSet* stateSet, osg::NodeVisitor*)
+ {
+ if (strcmp(mFogEnabled->getStringValue(), "disabled") == 0) {
+ stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
+ } else {
+ stateSet->setMode(GL_FOG, osg::StateAttribute::ON);
+ }
+ }
+private:
+ SGPropertyNode_ptr mFogEnabled;
+};
+
+class FGFogUpdateCallback : public osg::StateAttribute::Callback {
+public:
+ virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
+ {
+ assert(dynamic_cast<SGUpdateVisitor*>(nv));
+ assert(dynamic_cast<osg::Fog*>(sa));
+ SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
+ osg::Fog* fog = static_cast<osg::Fog*>(sa);
+ fog->setMode(osg::Fog::EXP2);
+ fog->setColor(toOsg(updateVisitor->getFogColor()));
+ fog->setDensity(updateVisitor->getFogExp2Density());
+ }
+};
+
+// update callback for the switch node guarding that splash
+class FGScenerySwitchCallback : public osg::NodeCallback {
+public:
+ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
+ {
+ assert(dynamic_cast<osg::Switch*>(node));
+ osg::Switch* sw = static_cast<osg::Switch*>(node);
+
+ bool enabled = scenery_enabled;
+ sw->setValue(0, enabled);
+ if (!enabled)
+ return;
+ traverse(node, nv);
+ }
+
+ static bool scenery_enabled;
+};
+
+bool FGScenerySwitchCallback::scenery_enabled = false;
+
+static osg::ref_ptr<osg::FrameStamp> mFrameStamp = new osg::FrameStamp;
+static osg::ref_ptr<SGUpdateVisitor> mUpdateVisitor= new SGUpdateVisitor;
+
+static osg::ref_ptr<osg::Group> mRealRoot = new osg::Group;
+static osg::ref_ptr<osg::Group> mDeferredRealRoot = new osg::Group;
+
+static osg::ref_ptr<osg::Group> mRoot = new osg::Group;
+
+static osg::ref_ptr<osg::Switch> panelSwitch;
+
+
+// update callback for the switch node controlling the 2D panel
+class FGPanelSwitchCallback : public osg::NodeCallback {
+public:
+ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
+ {
+ assert(dynamic_cast<osg::Switch*>(node));
+ osg::Switch* sw = static_cast<osg::Switch*>(node);
+
+ bool enabled = fgPanelVisible();
+ sw->setValue(0, enabled);
+ if (!enabled)
+ return;
+ traverse(node, nv);
+ }
+};
+
+#ifdef FG_JPEG_SERVER
+static void updateRenderer()
+{
+ globals->get_renderer()->update();
+}
+#endif
+
+FGRenderer::FGRenderer() :
+ _sky(NULL),
+ _ambientFactor( new osg::Uniform( "fg_SunAmbientColor", osg::Vec4f() ) ),
+ _sunDiffuse( new osg::Uniform( "fg_SunDiffuseColor", osg::Vec4f() ) ),
+ _sunSpecular( new osg::Uniform( "fg_SunSpecularColor", osg::Vec4f() ) ),
+ _sunDirection( new osg::Uniform( "fg_SunDirection", osg::Vec3f() ) ),
+ _planes( new osg::Uniform( "fg_Planes", osg::Vec3f() ) ),
+ _fogColor( new osg::Uniform( "fg_FogColor", osg::Vec4f(1.0, 1.0, 1.0, 1.0) ) ),
+ _fogDensity( new osg::Uniform( "fg_FogDensity", 0.0001f ) ),
+ _shadowNumber( new osg::Uniform( "fg_ShadowNumber", (int)4 ) ),
+ _shadowDistances( new osg::Uniform( "fg_ShadowDistances", osg::Vec4f(5.0, 50.0, 500.0, 5000.0 ) ) )
+{
+#ifdef FG_JPEG_SERVER
+ jpgRenderFrame = updateRenderer;
+#endif
+ eventHandler = new FGEventHandler;
+
+ _numCascades = 4;
+ _cascadeFar[0] = 5.f;
+ _cascadeFar[1] = 50.f;
+ _cascadeFar[2] = 500.f;
+ _cascadeFar[3] = 5000.f;
+}
+
+FGRenderer::~FGRenderer()
+{
+#ifdef FG_JPEG_SERVER
+ jpgRenderFrame = NULL;
+#endif
+ delete _sky;
+}
+
+// Initialize various GL/view parameters
+// XXX This should be called "preinit" or something, as it initializes
+// critical parts of the scene graph in addition to the splash screen.
+void
+FGRenderer::splashinit( void ) {
+ osgViewer::Viewer* viewer = getViewer();
+ mRealRoot = dynamic_cast<osg::Group*>(viewer->getSceneData());
+ ref_ptr<Node> splashNode = fgCreateSplashNode();
+ if (_classicalRenderer) {
+ mRealRoot->addChild(splashNode.get());
+ } else {
+ for ( CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
+ ii != CameraGroup::getDefault()->camerasEnd();
+ ++ii )
+ {
+ CameraInfo* info = ii->get();
+ Camera* camera = info->getCamera(DISPLAY_CAMERA);
+ if (camera == 0) continue;
+
+ camera->addChild(splashNode.get());
+ }
+ }
+ mFrameStamp = viewer->getFrameStamp();
+ // Scene doesn't seem to pass the frame stamp to the update
+ // visitor automatically.
+ mUpdateVisitor->setFrameStamp(mFrameStamp.get());
+ viewer->setUpdateVisitor(mUpdateVisitor.get());
+ fgSetDouble("/sim/startup/splash-alpha", 1.0);
+}
+
+class ShadowMapSizeListener : public SGPropertyChangeListener {
+public:
+ virtual void valueChanged(SGPropertyNode* node) {
+ globals->get_renderer()->updateShadowMapSize(node->getIntValue());
+ }
+};
+
+class ShadowEnabledListener : public SGPropertyChangeListener {
+public:
+ virtual void valueChanged(SGPropertyNode* node) {
+ globals->get_renderer()->enableShadows(node->getBoolValue());
+ }
+};
+
+class ShadowNumListener : public SGPropertyChangeListener {
+public:
+ virtual void valueChanged(SGPropertyNode* node) {
+ globals->get_renderer()->updateCascadeNumber(node->getIntValue());
+ }
+};
+
+class ShadowRangeListener : public SGPropertyChangeListener {
+public:
+ virtual void valueChanged(SGPropertyNode* node) {
+ globals->get_renderer()->updateCascadeFar(node->getIndex(), node->getFloatValue());
+ }
+};
+
+void
+FGRenderer::init( void )
+{
+ _classicalRenderer = !fgGetBool("/sim/rendering/rembrandt", false);
+ _shadowMapSize = fgGetInt( "/sim/rendering/shadows/map-size", 4096 );
+ fgAddChangeListener( new ShadowMapSizeListener, "/sim/rendering/shadows/map-size" );
+ fgAddChangeListener( new ShadowEnabledListener, "/sim/rendering/shadows/enabled" );
+ ShadowRangeListener* srl = new ShadowRangeListener;
+ fgAddChangeListener(srl, "/sim/rendering/shadows/cascade-far-m[0]");
+ fgAddChangeListener(srl, "/sim/rendering/shadows/cascade-far-m[1]");
+ fgAddChangeListener(srl, "/sim/rendering/shadows/cascade-far-m[2]");
+ fgAddChangeListener(srl, "/sim/rendering/shadows/cascade-far-m[3]");
+ fgAddChangeListener(new ShadowNumListener, "/sim/rendering/shadows/num-cascades");
+ _numCascades = fgGetInt("/sim/rendering/shadows/num-cascades", 4);
+ _cascadeFar[0] = fgGetFloat("/sim/rendering/shadows/cascade-far-m[0]", 5.0f);
+ _cascadeFar[1] = fgGetFloat("/sim/rendering/shadows/cascade-far-m[1]", 50.0f);
+ _cascadeFar[2] = fgGetFloat("/sim/rendering/shadows/cascade-far-m[2]", 500.0f);
+ _cascadeFar[3] = fgGetFloat("/sim/rendering/shadows/cascade-far-m[3]", 5000.0f);
+ _scenery_loaded = fgGetNode("/sim/sceneryloaded", true);
+ _scenery_override = fgGetNode("/sim/sceneryloaded-override", true);
+ _panel_hotspots = fgGetNode("/sim/panel-hotspots", true);
+ _virtual_cockpit = fgGetNode("/sim/virtual-cockpit", true);
+
+ _sim_delta_sec = fgGetNode("/sim/time/delta-sec", true);
+
+ _xsize = fgGetNode("/sim/startup/xsize", true);
+ _ysize = fgGetNode("/sim/startup/ysize", true);
+ _splash_alpha = fgGetNode("/sim/startup/splash-alpha", true);
+
+ _skyblend = fgGetNode("/sim/rendering/skyblend", true);
+ _point_sprites = fgGetNode("/sim/rendering/point-sprites", true);
+ _enhanced_lighting = fgGetNode("/sim/rendering/enhanced-lighting", true);
+ _distance_attenuation = fgGetNode("/sim/rendering/distance-attenuation", true);
+ _horizon_effect = fgGetNode("/sim/rendering/horizon-effect", true);
+ _textures = fgGetNode("/sim/rendering/textures", true);
+
+ _altitude_ft = fgGetNode("/position/altitude-ft", true);
+
+ _cloud_status = fgGetNode("/environment/clouds/status", true);
+ _visibility_m = fgGetNode("/environment/visibility-m", true);
+
+ bool use_point_sprites = _point_sprites->getBoolValue();
+ bool enhanced_lighting = _enhanced_lighting->getBoolValue();
+ bool distance_attenuation = _distance_attenuation->getBoolValue();
+
+ SGConfigureDirectionalLights( use_point_sprites, enhanced_lighting,
+ distance_attenuation );
+
+ if (const char* tc = fgGetString("/sim/rendering/texture-compression", NULL)) {
+ if (strcmp(tc, "false") == 0 || strcmp(tc, "off") == 0 ||
+ strcmp(tc, "0") == 0 || strcmp(tc, "no") == 0 ||
+ strcmp(tc, "none") == 0) {
+ SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::DoNotUseCompression);
+ } else if (strcmp(tc, "arb") == 0) {
+ SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseARBCompression);
+ } else if (strcmp(tc, "dxt1") == 0) {
+ SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseDXT1Compression);
+ } else if (strcmp(tc, "dxt3") == 0) {
+ SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseDXT3Compression);
+ } else if (strcmp(tc, "dxt5") == 0) {
+ SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseDXT5Compression);
+ } else {
+ SG_LOG(SG_VIEW, SG_WARN, "Unknown texture compression setting!");
+ }
+ }
+
+// create sky, but can't build until setupView, since we depend
+// on other subsystems to be inited, eg Ephemeris
+ _sky = new SGSky;
+
+ SGPath texture_path(globals->get_fg_root());
+ texture_path.append("Textures");
+ texture_path.append("Sky");
+ for (int i = 0; i < FGEnvironmentMgr::MAX_CLOUD_LAYERS; i++) {
+ SGCloudLayer * layer = new SGCloudLayer(texture_path.str());
+ _sky->add_cloud_layer(layer);
+ }
+
+ _sky->texture_path( texture_path.str() );
+
+ if (!_classicalRenderer) {
+ eventHandler->setChangeStatsCameraRenderOrder( true );
+ }
+}
+
+void installCullVisitor(Camera* camera)
+{
+ osgViewer::Renderer* renderer
+ = static_cast<osgViewer::Renderer*>(camera->getRenderer());
+ for (int i = 0; i < 2; ++i) {
+ osgUtil::SceneView* sceneView = renderer->getSceneView(i);
+#if SG_OSG_VERSION_LESS_THAN(3,0,0)
+ sceneView->setCullVisitor(new simgear::EffectCullVisitor);
+#else
+ osg::ref_ptr<osgUtil::CullVisitor::Identifier> identifier;
+ identifier = sceneView->getCullVisitor()->getIdentifier();
+ sceneView->setCullVisitor(new simgear::EffectCullVisitor);
+ sceneView->getCullVisitor()->setIdentifier(identifier.get());
+
+ identifier = sceneView->getCullVisitorLeft()->getIdentifier();
+ sceneView->setCullVisitorLeft(sceneView->getCullVisitor()->clone());
+ sceneView->getCullVisitorLeft()->setIdentifier(identifier.get());
+
+ identifier = sceneView->getCullVisitorRight()->getIdentifier();
+ sceneView->setCullVisitorRight(sceneView->getCullVisitor()->clone());
+ sceneView->getCullVisitorRight()->setIdentifier(identifier.get());
+#endif
+ }
+}
+
+flightgear::CameraInfo*
+FGRenderer::buildRenderingPipeline(flightgear::CameraGroup* cgroup, unsigned flags, Camera* camera,
+ const Matrix& view,
+ const Matrix& projection,
+ osg::GraphicsContext* gc,
+ bool useMasterSceneData)
+{
+ flightgear::CameraInfo* info = 0;
+ if (!_classicalRenderer && (flags & (CameraGroup::GUI | CameraGroup::ORTHO)) == 0)
+ info = buildDeferredPipeline( cgroup, flags, camera, view, projection, gc );
+
+ if (info) {
+ return info;
+ } else {
+ if ((flags & (CameraGroup::GUI | CameraGroup::ORTHO)) == 0)
+ _classicalRenderer = true;
+ return buildClassicalPipeline( cgroup, flags, camera, view, projection, useMasterSceneData );
+ }
+}
+
+flightgear::CameraInfo*
+FGRenderer::buildClassicalPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
+ const osg::Matrix& view,
+ const osg::Matrix& projection,
+ bool useMasterSceneData)
+{
+ CameraInfo* info = new CameraInfo(flags);
+ // The camera group will always update the camera
+ camera->setReferenceFrame(Transform::ABSOLUTE_RF);
+
+ Camera* farCamera = 0;
+ if ((flags & (CameraGroup::GUI | CameraGroup::ORTHO)) == 0) {
+ farCamera = new Camera;
+ farCamera->setAllowEventFocus(camera->getAllowEventFocus());
+ farCamera->setGraphicsContext(camera->getGraphicsContext());
+ farCamera->setCullingMode(camera->getCullingMode());
+ farCamera->setInheritanceMask(camera->getInheritanceMask());
+ farCamera->setReferenceFrame(Transform::ABSOLUTE_RF);
+ // Each camera's viewport is written when the window is
+ // resized; if the the viewport isn't copied here, it gets updated
+ // twice and ends up with the wrong value.
+ farCamera->setViewport(simgear::clone(camera->getViewport()));
+ farCamera->setDrawBuffer(camera->getDrawBuffer());
+ farCamera->setReadBuffer(camera->getReadBuffer());
+ farCamera->setRenderTargetImplementation(
+ camera->getRenderTargetImplementation());
+ const Camera::BufferAttachmentMap& bufferMap
+ = camera->getBufferAttachmentMap();
+ if (bufferMap.count(Camera::COLOR_BUFFER) != 0) {
+ farCamera->attach(
+ Camera::COLOR_BUFFER,
+ bufferMap.find(Camera::COLOR_BUFFER)->second._texture.get());
+ }
+ cgroup->getViewer()->addSlave(farCamera, projection, view, useMasterSceneData);
+ installCullVisitor(farCamera);
+ int farSlaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
+ info->addCamera( FAR_CAMERA, farCamera, farSlaveIndex );
+ farCamera->setRenderOrder(Camera::POST_RENDER, farSlaveIndex);
+ camera->setCullMask(camera->getCullMask() & ~simgear::BACKGROUND_BIT);
+ camera->setClearMask(GL_DEPTH_BUFFER_BIT);
+ }
+ cgroup->getViewer()->addSlave(camera, projection, view, useMasterSceneData);
+ installCullVisitor(camera);
+ int slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
+ info->addCamera( MAIN_CAMERA, camera, slaveIndex );
+ camera->setRenderOrder(Camera::POST_RENDER, slaveIndex);
+ cgroup->addCamera(info);
+ return info;
+}
+
+class FGDeferredRenderingCameraCullCallback : public osg::NodeCallback {
+public:
+ FGDeferredRenderingCameraCullCallback( flightgear::CameraKind k, CameraInfo* i ) : kind( k ), info( i ) {}
+ virtual void operator()( osg::Node *n, osg::NodeVisitor *nv) {
+ simgear::EffectCullVisitor* cv = dynamic_cast<simgear::EffectCullVisitor*>(nv);
+ osg::Camera* camera = static_cast<osg::Camera*>(n);
+
+ cv->clearBufferList();
+ cv->addBuffer(simgear::Effect::DEPTH_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::DEPTH_BUFFER ) );
+ cv->addBuffer(simgear::Effect::NORMAL_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::NORMAL_BUFFER ) );
+ cv->addBuffer(simgear::Effect::DIFFUSE_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::DIFFUSE_BUFFER ) );
+ cv->addBuffer(simgear::Effect::SPEC_EMIS_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER ) );
+ cv->addBuffer(simgear::Effect::LIGHTING_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::LIGHTING_BUFFER ) );
+ cv->addBuffer(simgear::Effect::SHADOW_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::SHADOW_BUFFER ) );
+ // cv->addBuffer(simgear::Effect::AO_BUFFER, info->gBuffer->aoBuffer[2]);
+
+ if ( !info->getRenderStageInfo(kind).fullscreen )
+ info->setMatrices( camera );
+
+ cv->traverse( *camera );
+
+ if ( kind == flightgear::GEOMETRY_CAMERA ) {
+ // Save transparent bins to render later
+ osgUtil::RenderStage* renderStage = cv->getRenderStage();
+ osgUtil::RenderBin::RenderBinList& rbl = renderStage->getRenderBinList();
+ for (osgUtil::RenderBin::RenderBinList::iterator rbi = rbl.begin(); rbi != rbl.end(); ) {
+ if (rbi->second->getSortMode() == osgUtil::RenderBin::SORT_BACK_TO_FRONT) {
+ info->savedTransparentBins.insert( std::make_pair( rbi->first, rbi->second ) );
+ rbl.erase( rbi++ );
+ } else {
+ ++rbi;
+ }
+ }
+ } else if ( kind == flightgear::LIGHTING_CAMERA ) {
+ osg::ref_ptr<osg::Camera> mainShadowCamera = info->getCamera( SHADOW_CAMERA );
+ if (mainShadowCamera.valid()) {
+ osg::Group* grp = mainShadowCamera->getChild(0)->asGroup();
+ for (int i = 0; i < 4; ++i ) {
+ osg::TexGen* shadowTexGen = info->shadowTexGen[i];
+ shadowTexGen->setMode(osg::TexGen::EYE_LINEAR);
+
+ osg::Camera* cascadeCam = static_cast<osg::Camera*>( grp->getChild(i) );
+ // compute the matrix which takes a vertex from view coords into tex coords
+ shadowTexGen->setPlanesFromMatrix( cascadeCam->getProjectionMatrix() *
+ osg::Matrix::translate(1.0,1.0,1.0) *
+ osg::Matrix::scale(0.5f,0.5f,0.5f) );
+
+ osg::RefMatrix * refMatrix = new osg::RefMatrix( cascadeCam->getInverseViewMatrix() * *cv->getModelViewMatrix() );
+
+ cv->getRenderStage()->getPositionalStateContainer()->addPositionedTextureAttribute( i+1, refMatrix, shadowTexGen );
+ }
+ }
+ // Render saved transparent render bins
+ osgUtil::RenderStage* renderStage = cv->getRenderStage();
+ osgUtil::RenderBin::RenderBinList& rbl = renderStage->getRenderBinList();
+ for (osgUtil::RenderBin::RenderBinList::iterator rbi = info->savedTransparentBins.begin(); rbi != info->savedTransparentBins.end(); ++rbi ){
+ rbl.insert( std::make_pair( rbi->first + 10000, rbi->second ) );
+ }
+ info->savedTransparentBins.clear();
+ }
+ }
+
+private:
+ flightgear::CameraKind kind;
+ CameraInfo* info;
+};
+
+osg::Texture2D* buildDeferredBuffer(GLint internalFormat, GLenum sourceFormat, GLenum sourceType, osg::Texture::WrapMode wrapMode, bool shadowComparison = false)
+{
+ osg::Texture2D* tex = new osg::Texture2D;
+ tex->setResizeNonPowerOfTwoHint( false );
+ tex->setInternalFormat( internalFormat );
+ tex->setShadowComparison(shadowComparison);
+ if (shadowComparison) {
+ tex->setShadowTextureMode(osg::Texture2D::LUMINANCE);
+ tex->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
+ }
+ tex->setSourceFormat(sourceFormat);
+ tex->setSourceType(sourceType);
+ tex->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR );
+ tex->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR );
+ tex->setWrap( osg::Texture::WRAP_S, wrapMode );
+ tex->setWrap( osg::Texture::WRAP_T, wrapMode );
+ return tex;
+}
+
+void buildDeferredBuffers( flightgear::CameraInfo* info, int shadowMapSize, bool normal16 )
+{
+ info->addBuffer(flightgear::RenderBufferInfo::DEPTH_BUFFER, buildDeferredBuffer( GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_FLOAT, osg::Texture::CLAMP_TO_BORDER) );
+ if (false)
+ info->addBuffer(flightgear::RenderBufferInfo::NORMAL_BUFFER, buildDeferredBuffer( 0x822C /*GL_RG16*/, 0x8227 /*GL_RG*/, GL_UNSIGNED_SHORT, osg::Texture::CLAMP_TO_BORDER) );
+ else
+ info->addBuffer(flightgear::RenderBufferInfo::NORMAL_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_SHORT, osg::Texture::CLAMP_TO_BORDER) );
+
+ info->addBuffer(flightgear::RenderBufferInfo::DIFFUSE_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, osg::Texture::CLAMP_TO_BORDER) );
+ info->addBuffer(flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, osg::Texture::CLAMP_TO_BORDER) );
+ info->addBuffer(flightgear::RenderBufferInfo::LIGHTING_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, osg::Texture::CLAMP_TO_BORDER) );
+ info->addBuffer(flightgear::RenderBufferInfo::SHADOW_BUFFER, buildDeferredBuffer( GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_FLOAT, osg::Texture::CLAMP_TO_BORDER, true), 0.0f );
+ info->getBuffer(RenderBufferInfo::SHADOW_BUFFER)->setTextureSize(shadowMapSize,shadowMapSize);
+}
+
+void attachBufferToCamera( flightgear::CameraInfo* info, osg::Camera* camera, osg::Camera::BufferComponent c, flightgear::CameraKind ck, flightgear::RenderBufferInfo::Kind bk )
+{
+ camera->attach( c, info->getBuffer(bk) );
+ info->getRenderStageInfo(ck).buffers.insert( std::make_pair( c, bk ) );
+}
+
+osg::Camera* FGRenderer::buildDeferredGeometryCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc )
+{
+ osg::Camera* camera = new osg::Camera;
+ info->addCamera(flightgear::GEOMETRY_CAMERA, camera );
+
+ camera->setCullMask( ~simgear::MODELLIGHT_BIT );
+ camera->setName( "GeometryC" );
+ camera->setGraphicsContext( gc );
+ camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( flightgear::GEOMETRY_CAMERA, info ) );
+ camera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+ camera->setClearColor( osg::Vec4( 0., 0., 0., 0. ) );
+ camera->setClearDepth( 1.0 );
+ camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
+ camera->setViewport( new osg::Viewport );
+ attachBufferToCamera( info, camera, osg::Camera::DEPTH_BUFFER, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::DEPTH_BUFFER );
+ attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER0, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::NORMAL_BUFFER );
+ attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER1, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::DIFFUSE_BUFFER );
+ attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER2, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER );
+ camera->setDrawBuffer(GL_FRONT);
+ camera->setReadBuffer(GL_FRONT);
+
+ camera->addChild( mDeferredRealRoot.get() );
+
+ return camera;
+}
+
+static void setShadowCascadeStateSet( osg::Camera* cam ) {
+ osg::StateSet* ss = cam->getOrCreateStateSet();
+ ss->setAttribute( new osg::PolygonOffset( 1.1f, 5.0f ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
+ ss->setMode( GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
+ ss->setRenderBinDetails( 0, "RenderBin", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS );
+ ss->setAttributeAndModes( new osg::AlphaFunc( osg::AlphaFunc::GREATER, 0.05 ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
+ ss->setAttributeAndModes( new osg::ColorMask( false, false, false, false ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
+ ss->setAttributeAndModes( new osg::CullFace( osg::CullFace::FRONT ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
+ osg::Program* program = new osg::Program;
+ ss->setAttribute( program, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON );
+ ss->setMode( GL_LIGHTING, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
+ ss->setMode( GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
+ //ss->setTextureMode( 0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON );
+ ss->setTextureMode( 0, GL_TEXTURE_3D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
+ ss->setTextureMode( 1, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
+ ss->setTextureMode( 1, GL_TEXTURE_3D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
+ ss->setTextureMode( 2, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
+ ss->setTextureMode( 2, GL_TEXTURE_3D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
+}
+
+static osg::Camera* createShadowCascadeCamera( int no, int cascadeSize ) {
+ osg::Camera* cascadeCam = new osg::Camera;
+ setShadowCascadeStateSet( cascadeCam );
+
+ std::ostringstream oss;
+ oss << "CascadeCamera" << (no + 1);
+ cascadeCam->setName( oss.str() );
+ cascadeCam->setClearMask(0);
+ cascadeCam->setCullMask(~( simgear::MODELLIGHT_BIT /* | simgear::NO_SHADOW_BIT */ ) );
+ cascadeCam->setCullingMode( cascadeCam->getCullingMode() & ~osg::CullSettings::SMALL_FEATURE_CULLING );
+ cascadeCam->setAllowEventFocus(false);
+ cascadeCam->setReferenceFrame(osg::Transform::ABSOLUTE_RF_INHERIT_VIEWPOINT);
+ cascadeCam->setRenderOrder(osg::Camera::NESTED_RENDER);
+ cascadeCam->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+ cascadeCam->setViewport( int( no / 2 ) * cascadeSize, (no & 1) * cascadeSize, cascadeSize, cascadeSize );
+ return cascadeCam;
+}
+
+osg::Camera* FGRenderer::buildDeferredShadowCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc )
+{
+ osg::Camera* mainShadowCamera = new osg::Camera;
+ info->addCamera(flightgear::SHADOW_CAMERA, mainShadowCamera, 0.0f );
+
+ mainShadowCamera->setName( "ShadowC" );
+ mainShadowCamera->setClearMask( GL_DEPTH_BUFFER_BIT );
+ mainShadowCamera->setClearDepth( 1.0 );
+ mainShadowCamera->setAllowEventFocus(false);
+ mainShadowCamera->setGraphicsContext(gc);
+ mainShadowCamera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
+ attachBufferToCamera( info, mainShadowCamera, osg::Camera::DEPTH_BUFFER, flightgear::SHADOW_CAMERA, flightgear::RenderBufferInfo::SHADOW_BUFFER );
+ mainShadowCamera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
+ mainShadowCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
+ mainShadowCamera->setProjectionMatrix(osg::Matrix::identity());
+ mainShadowCamera->setCullingMode( osg::CullSettings::NO_CULLING );
+ mainShadowCamera->setViewport( 0, 0, _shadowMapSize, _shadowMapSize );
+ mainShadowCamera->setDrawBuffer(GL_FRONT);
+ mainShadowCamera->setReadBuffer(GL_FRONT);
+
+ osg::Switch* shadowSwitch = new osg::Switch;
+ mainShadowCamera->addChild( shadowSwitch );
+
+ for (int i = 0; i < 4; ++i ) {
+ osg::Camera* cascadeCam = createShadowCascadeCamera( i, _shadowMapSize/2 );
+ cascadeCam->addChild( mDeferredRealRoot.get() );
+ shadowSwitch->addChild( cascadeCam );
+ info->shadowTexGen[i] = new osg::TexGen;
+ }
+ if (fgGetBool("/sim/rendering/shadows/enabled", true))
+ shadowSwitch->setAllChildrenOn();
+ else
+ shadowSwitch->setAllChildrenOff();
+
+ return mainShadowCamera;
+}
+
+void FGRenderer::updateShadowCascade(const CameraInfo* info, osg::Camera* camera, osg::Group* grp, int idx, double left, double right, double bottom, double top, double zNear, double f1, double f2)
+{
+ osg::Camera* cascade = static_cast<osg::Camera*>( grp->getChild(idx) );
+ osg::Matrixd &viewMatrix = cascade->getViewMatrix();
+ osg::Matrixd &projectionMatrix = cascade->getProjectionMatrix();
+
+ osg::BoundingSphere bs;
+ bs.expandBy(osg::Vec3(left,bottom,-zNear) * f1);
+ bs.expandBy(osg::Vec3(right,top,-zNear) * f2);
+ bs.expandBy(osg::Vec3(left,bottom,-zNear) * f2);
+ bs.expandBy(osg::Vec3(right,top,-zNear) * f1);
+
+ osg::Vec4 aim = osg::Vec4(bs.center(), 1.0) * camera->getInverseViewMatrix();
+
+ projectionMatrix.makeOrtho( -bs.radius(), bs.radius(), -bs.radius(), bs.radius(), 1., 15000.0 );
+ osg::Vec3 position( aim.x(), aim.y(), aim.z() );
+ viewMatrix.makeLookAt( position + (getSunDirection() * 10000.0), position, position );
+}
+
+osg::Vec3 FGRenderer::getSunDirection() const
+{
+ osg::Vec3 val;
+ _sunDirection->get( val );
+ return val;
+}
+
+void FGRenderer::updateShadowCamera(const flightgear::CameraInfo* info, const osg::Vec3d& position)
+{
+ ref_ptr<Camera> mainShadowCamera = info->getCamera( SHADOW_CAMERA );
+ if (mainShadowCamera.valid()) {
+ ref_ptr<Switch> shadowSwitch = mainShadowCamera->getChild( 0 )->asSwitch();
+ osg::Vec3d up = position,
+ dir = getSunDirection();
+ up.normalize();
+ dir.normalize();
+ // cos(100 deg) == -0.17
+ if (up * dir < -0.17 || !fgGetBool("/sim/rendering/shadows/enabled", true)) {
+ shadowSwitch->setAllChildrenOff();
+ } else {
+ double left,right,bottom,top,zNear,zFar;
+ ref_ptr<Camera> camera = info->getCamera(GEOMETRY_CAMERA);
+ camera->getProjectionMatrix().getFrustum(left,right,bottom,top,zNear,zFar);
+
+ shadowSwitch->setAllChildrenOn();
+ if (_numCascades == 1) {
+ osg::Camera* cascadeCam = static_cast<osg::Camera*>( shadowSwitch->getChild(0) );
+ cascadeCam->setViewport( 0, 0, _shadowMapSize, _shadowMapSize );
+ } else {
+ for (int no = 0; no < 4; ++no) {
+ osg::Camera* cascadeCam = static_cast<osg::Camera*>( shadowSwitch->getChild(no) );
+ cascadeCam->setViewport( int( no / 2 ) * (_shadowMapSize/2), (no & 1) * (_shadowMapSize/2), (_shadowMapSize/2), (_shadowMapSize/2) );
+ }
+ }
+ updateShadowCascade(info, camera, shadowSwitch, 0, left, right, bottom, top, zNear, 1.0, _cascadeFar[0]/zNear);
+ if (_numCascades > 1) {
+ shadowSwitch->setValue(1, true);
+ updateShadowCascade(info, camera, shadowSwitch, 1, left, right, bottom, top, zNear, _cascadeFar[0]/zNear, _cascadeFar[1]/zNear);
+ } else {
+ shadowSwitch->setValue(1, false);
+ }
+ if (_numCascades > 2) {
+ shadowSwitch->setValue(2, true);
+ updateShadowCascade(info, camera, shadowSwitch, 2, left, right, bottom, top, zNear, _cascadeFar[1]/zNear, _cascadeFar[2]/zNear);
+ } else {
+ shadowSwitch->setValue(2, false);
+ }
+ if (_numCascades > 3) {
+ shadowSwitch->setValue(3, true);
+ updateShadowCascade(info, camera, shadowSwitch, 3, left, right, bottom, top, zNear, _cascadeFar[2]/zNear, _cascadeFar[3]/zNear);
+ } else {
+ shadowSwitch->setValue(3, false);
+ }
+ {
+ osg::Matrixd &viewMatrix = mainShadowCamera->getViewMatrix();
+
+ osg::Vec4 aim = osg::Vec4( 0.0, 0.0, 0.0, 1.0 ) * camera->getInverseViewMatrix();
+
+ osg::Vec3 position( aim.x(), aim.y(), aim.z() );
+ viewMatrix.makeLookAt( position, position + (getSunDirection() * 10000.0), position );
+ }
+ }
+ }
+}
+
+void FGRenderer::updateShadowMapSize(int mapSize)
+{
+ if ( ((~( mapSize-1 )) & mapSize) != mapSize ) {
+ SG_LOG( SG_VIEW, SG_ALERT, "Map size is not a power of two" );
+ return;
+ }
+ for ( CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
+ ii != CameraGroup::getDefault()->camerasEnd();
+ ++ii )
+ {
+ CameraInfo* info = ii->get();
+ Camera* camera = info->getCamera(SHADOW_CAMERA);
+ if (camera == 0) continue;
+
+ Texture2D* tex = info->getBuffer(RenderBufferInfo::SHADOW_BUFFER);
+ if (tex == 0) continue;
+
+ tex->setTextureSize( mapSize, mapSize );
+ tex->dirtyTextureObject();
+
+ Viewport* vp = camera->getViewport();
+ vp->width() = mapSize;
+ vp->height() = mapSize;
+
+ osgViewer::Renderer* renderer
+ = static_cast<osgViewer::Renderer*>(camera->getRenderer());
+ for (int i = 0; i < 2; ++i) {
+ osgUtil::SceneView* sceneView = renderer->getSceneView(i);
+ sceneView->getRenderStage()->setFrameBufferObject(0);
+ sceneView->getRenderStage()->setCameraRequiresSetUp(true);
+ if (sceneView->getRenderStageLeft()) {
+ sceneView->getRenderStageLeft()->setFrameBufferObject(0);
+ sceneView->getRenderStageLeft()->setCameraRequiresSetUp(true);
+ }
+ if (sceneView->getRenderStageRight()) {
+ sceneView->getRenderStageRight()->setFrameBufferObject(0);
+ sceneView->getRenderStageRight()->setCameraRequiresSetUp(true);
+ }
+ }
+
+ int cascadeSize = mapSize / 2;
+ Group* grp = camera->getChild(0)->asGroup();
+ for (int i = 0; i < 4; ++i ) {
+ Camera* cascadeCam = static_cast<Camera*>( grp->getChild(i) );
+ cascadeCam->setViewport( int( i / 2 ) * cascadeSize, (i & 1) * cascadeSize, cascadeSize, cascadeSize );
+ }
+
+ _shadowMapSize = mapSize;
+ }
+}
+
+void FGRenderer::enableShadows(bool enabled)
+{
+ for ( CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
+ ii != CameraGroup::getDefault()->camerasEnd();
+ ++ii )
+ {
+ CameraInfo* info = ii->get();
+ Camera* camera = info->getCamera(SHADOW_CAMERA);
+ if (camera == 0) continue;
+
+ osg::Switch* shadowSwitch = camera->getChild(0)->asSwitch();
+ if (enabled)
+ shadowSwitch->setAllChildrenOn();
+ else
+ shadowSwitch->setAllChildrenOff();
+ }
+}
+
+void FGRenderer::updateCascadeFar(int index, float far_m)
+{
+ if (index < 0 || index > 3)
+ return;
+ _cascadeFar[index] = far_m;
+ _shadowDistances->set( osg::Vec4f(_cascadeFar[0], _cascadeFar[1], _cascadeFar[2], _cascadeFar[3]) );
+}
+
+void FGRenderer::updateCascadeNumber(size_t num)
+{
+ if (num < 1 || num > 4)
+ return;
+ _numCascades = num;
+ _shadowNumber->set( (int)_numCascades );
+}
+
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+
+const char *ambient_vert_src = ""
+ "#line " TOSTRING(__LINE__) " 1\n"
+ "void main() {\n"
+ " gl_Position = gl_Vertex;\n"
+ " gl_TexCoord[0] = gl_MultiTexCoord0;\n"
+ "}\n";
+
+const char *ambient_frag_src = ""
+ "#line " TOSTRING(__LINE__) " 1\n"
+ "uniform sampler2D color_tex;\n"
+// "uniform sampler2D ao_tex;\n"
+ "uniform sampler2D normal_tex;\n"
+ "uniform sampler2D spec_emis_tex;\n"
+ "uniform vec4 fg_SunAmbientColor;\n"
+ "void main() {\n"
+ " vec2 coords = gl_TexCoord[0].xy;\n"
+ " float initialized = texture2D( spec_emis_tex, coords ).a;\n"
+ " if ( initialized < 0.1 )\n"
+ " discard;\n"
+ " vec3 tcolor = texture2D( color_tex, coords ).rgb;\n"
+// " float ao = texture2D( ao_tex, coords ).r;\n"
+// " gl_FragColor = vec4(tcolor*fg_SunAmbientColor.rgb*ao, 1.0);\n"
+ " gl_FragColor = vec4(tcolor*fg_SunAmbientColor.rgb, 1.0);\n"
+ "}\n";
+
+const char *sunlight_vert_src = ""
+ "#line " TOSTRING(__LINE__) " 1\n"
+// "uniform mat4 fg_ViewMatrixInverse;\n"
+ "uniform mat4 fg_ProjectionMatrixInverse;\n"
+ "varying vec3 ray;\n"
+ "void main() {\n"
+ " gl_Position = gl_Vertex;\n"
+ " gl_TexCoord[0] = gl_MultiTexCoord0;\n"
+// " ray = (fg_ViewMatrixInverse * vec4((fg_ProjectionMatrixInverse * gl_Vertex).xyz, 0.0)).xyz;\n"
+ " ray = (fg_ProjectionMatrixInverse * gl_Vertex).xyz;\n"
+ "}\n";
+
+const char *sunlight_frag_src = ""
+#if 0
+ "#version 130\n"
+#endif
+ "#line " TOSTRING(__LINE__) " 1\n"
+ "uniform mat4 fg_ViewMatrix;\n"
+ "uniform sampler2D depth_tex;\n"
+ "uniform sampler2D normal_tex;\n"
+ "uniform sampler2D color_tex;\n"
+ "uniform sampler2D spec_emis_tex;\n"
+ "uniform sampler2DShadow shadow_tex;\n"
+ "uniform vec4 fg_SunDiffuseColor;\n"
+ "uniform vec4 fg_SunSpecularColor;\n"
+ "uniform vec3 fg_SunDirection;\n"
+ "uniform vec3 fg_Planes;\n"
+ "varying vec3 ray;\n"
+ "vec4 DynamicShadow( in vec4 ecPosition, out vec4 tint )\n"
+ "{\n"
+ " vec4 coords;\n"
+ " vec2 shift = vec2( 0.0 );\n"
+ " int index = 4;\n"
+ " if (ecPosition.z > -5.0) {\n"
+ " index = 1;\n"
+ " tint = vec4(0.0,1.0,0.0,1.0);\n"
+ " } else if (ecPosition.z > -50.0) {\n"
+ " index = 2;\n"
+ " shift = vec2( 0.0, 0.5 );\n"
+ " tint = vec4(0.0,0.0,1.0,1.0);\n"
+ " } else if (ecPosition.z > -512.0) {\n"
+ " index = 3;\n"
+ " shift = vec2( 0.5, 0.0 );\n"
+ " tint = vec4(1.0,1.0,0.0,1.0);\n"
+ " } else if (ecPosition.z > -10000.0) {\n"
+ " shift = vec2( 0.5, 0.5 );\n"
+ " tint = vec4(1.0,0.0,0.0,1.0);\n"
+ " } else {\n"
+ " return vec4(1.1,1.1,0.0,1.0);\n" // outside, clamp to border
+ " }\n"
+ " coords.s = dot( ecPosition, gl_EyePlaneS[index] );\n"
+ " coords.t = dot( ecPosition, gl_EyePlaneT[index] );\n"
+ " coords.p = dot( ecPosition, gl_EyePlaneR[index] );\n"
+ " coords.q = dot( ecPosition, gl_EyePlaneQ[index] );\n"
+ " coords.st *= .5;\n"
+ " coords.st += shift;\n"
+ " return coords;\n"
+ "}\n"
+ "void main() {\n"
+ " vec2 coords = gl_TexCoord[0].xy;\n"
+ " vec4 spec_emis = texture2D( spec_emis_tex, coords );\n"
+ " if ( spec_emis.a < 0.1 )\n"
+ " discard;\n"
+ " vec3 normal;\n"
+ " normal.xy = texture2D( normal_tex, coords ).rg * 2.0 - vec2(1.0,1.0);\n"
+ " normal.z = sqrt( 1.0 - dot( normal.xy, normal.xy ) );\n"
+ " float len = length(normal);\n"
+ " normal /= len;\n"
+ " vec3 viewDir = normalize(ray);\n"
+ " float depth = texture2D( depth_tex, coords ).r;\n"
+ " vec3 pos;\n"
+ " pos.z = - fg_Planes.y / (fg_Planes.x + depth * fg_Planes.z);\n"
+ " pos.xy = viewDir.xy / viewDir.z * pos.z;\n"
+
+ " vec4 tint;\n"
+#if 0
+ " float shadow = 1.0;\n"
+#elif 1
+ " float shadow = shadow2DProj( shadow_tex, DynamicShadow( vec4( pos, 1.0 ), tint ) ).r;\n"
+#else
+ " float kernel[9] = float[]( 36/256.0, 24/256.0, 6/256.0,\n"
+ " 24/256.0, 16/256.0, 4/256.0,\n"
+ " 6/256.0, 4/256.0, 1/256.0 );\n"
+ " float shadow = 0;\n"
+ " for( int x = -2; x <= 2; ++x )\n"
+ " for( int y = -2; y <= 2; ++y )\n"
+ " shadow += kernel[abs(x)*3 + abs(y)] * shadow2DProj( shadow_tex, DynamicShadow( vec4(pos + vec3(0.05 * x, 0.05 * y, 0), 1.0), tint ) ).r;\n"
+#endif
+ " vec3 lightDir = (fg_ViewMatrix * vec4( fg_SunDirection, 0.0 )).xyz;\n"
+ " lightDir = normalize( lightDir );\n"
+ " vec3 color = texture2D( color_tex, coords ).rgb;\n"
+ " vec3 Idiff = clamp( dot( lightDir, normal ), 0.0, 1.0 ) * color * fg_SunDiffuseColor.rgb;\n"
+ " vec3 halfDir = lightDir - viewDir;\n"
+ " len = length( halfDir );\n"
+ " vec3 Ispec = vec3(0.0);\n"
+ " vec3 Iemis = spec_emis.z * color;\n"
+ " if (len > 0.0001) {\n"
+ " halfDir /= len;\n"
+ " Ispec = pow( clamp( dot( halfDir, normal ), 0.0, 1.0 ), spec_emis.y * 255.0 ) * spec_emis.x * fg_SunSpecularColor.rgb;\n"
+ " }\n"
+ " gl_FragColor = vec4(mix(vec3(0.0), Idiff + Ispec, shadow) + Iemis, 1.0);\n"
+// " gl_FragColor = mix(tint, vec4(mix(vec3(0.0), Idiff + Ispec, shadow) + Iemis, 1.0), 0.92);\n"
+ "}\n";
+
+const char *fog_vert_src = ""
+ "#line " TOSTRING(__LINE__) " 1\n"
+ "uniform mat4 fg_ProjectionMatrixInverse;\n"
+ "varying vec3 ray;\n"
+ "void main() {\n"
+ " gl_Position = gl_Vertex;\n"
+ " gl_TexCoord[0] = gl_MultiTexCoord0;\n"
+ " ray = (fg_ProjectionMatrixInverse * gl_Vertex).xyz;\n"
+ "}\n";
+
+const char *fog_frag_src = ""
+ "#line " TOSTRING(__LINE__) " 1\n"
+ "uniform sampler2D depth_tex;\n"
+ "uniform sampler2D normal_tex;\n"
+ "uniform sampler2D color_tex;\n"
+ "uniform sampler2D spec_emis_tex;\n"
+ "uniform vec4 fg_FogColor;\n"
+ "uniform float fg_FogDensity;\n"
+ "uniform vec3 fg_Planes;\n"
+ "varying vec3 ray;\n"
+ "void main() {\n"
+ " vec2 coords = gl_TexCoord[0].xy;\n"
+ " float initialized = texture2D( spec_emis_tex, coords ).a;\n"
+ " if ( initialized < 0.1 )\n"
+ " discard;\n"
+ " vec3 normal;\n"
+ " normal.xy = texture2D( normal_tex, coords ).rg * 2.0 - vec2(1.0,1.0);\n"
+ " normal.z = sqrt( 1.0 - dot( normal.xy, normal.xy ) );\n"
+ " float len = length(normal);\n"
+ " normal /= len;\n"
+ " vec3 viewDir = normalize(ray);\n"
+ " float depth = texture2D( depth_tex, coords ).r;\n"
+ " vec3 pos;\n"
+ " pos.z = - fg_Planes.y / (fg_Planes.x + depth * fg_Planes.z);\n"
+ " pos.xy = viewDir.xy / viewDir.z * pos.z;\n"
+
+ " float fogFactor = 0.0;\n"
+ " const float LOG2 = 1.442695;\n"
+ " fogFactor = exp2(-fg_FogDensity * fg_FogDensity * pos.z * pos.z * LOG2);\n"
+ " fogFactor = clamp(fogFactor, 0.0, 1.0);\n"
+
+ " gl_FragColor = vec4(fg_FogColor.rgb, 1.0 - fogFactor);\n"
+ "}\n";
+
+osg::Camera* FGRenderer::buildDeferredLightingCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc )
+{
+ osg::Camera* camera = new osg::Camera;
+ info->addCamera(flightgear::LIGHTING_CAMERA, camera );
+
+ camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( flightgear::LIGHTING_CAMERA, info ) );
+ camera->setAllowEventFocus(false);
+ camera->setGraphicsContext(gc);
+ camera->setViewport(new Viewport);
+ camera->setName("LightingC");
+ camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
+ camera->setRenderOrder(osg::Camera::POST_RENDER, 50);
+ camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
+ camera->setViewport( new osg::Viewport );
+ attachBufferToCamera( info, camera, osg::Camera::DEPTH_BUFFER, flightgear::LIGHTING_CAMERA, flightgear::RenderBufferInfo::DEPTH_BUFFER );
+ attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER, flightgear::LIGHTING_CAMERA, flightgear::RenderBufferInfo::LIGHTING_BUFFER );
+ camera->setDrawBuffer(GL_FRONT);
+ camera->setReadBuffer(GL_FRONT);
+ camera->setClearColor( osg::Vec4( 0., 0., 0., 1. ) );
+ camera->setClearMask( GL_COLOR_BUFFER_BIT );
+ osg::StateSet* ss = camera->getOrCreateStateSet();
+ ss->setAttribute( new osg::Depth(osg::Depth::LESS, 0.0, 1.0, false) );
+
+ osg::Group* lightingGroup = new osg::Group;
+
+ osg::Camera* quadCam1 = new osg::Camera;
+ quadCam1->setName( "QuadCamera1" );
+ quadCam1->setClearMask(0);
+ quadCam1->setAllowEventFocus(false);
+ quadCam1->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
+ quadCam1->setRenderOrder(osg::Camera::NESTED_RENDER);
+ quadCam1->setViewMatrix(osg::Matrix::identity());
+ quadCam1->setProjectionMatrixAsOrtho2D(-1,1,-1,1);
+ quadCam1->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+ ss = quadCam1->getOrCreateStateSet();
+ ss->addUniform( _ambientFactor );
+ ss->addUniform( info->projInverse );
+ ss->addUniform( info->viewInverse );
+ ss->addUniform( info->view );
+ ss->addUniform( _sunDiffuse );
+ ss->addUniform( _sunSpecular );
+ ss->addUniform( _sunDirection );
+ ss->addUniform( _planes );
+ ss->addUniform( _shadowNumber );
+ ss->addUniform( _shadowDistances );
+
+ osg::Geometry* g = osg::createTexturedQuadGeometry( osg::Vec3(-1.,-1.,0.), osg::Vec3(2.,0.,0.), osg::Vec3(0.,2.,0.) );
+ g->setUseDisplayList(false);
+ simgear::EffectGeode* eg = new simgear::EffectGeode;
+ simgear::Effect* effect = simgear::makeEffect("Effects/ambient", true);
+ if (effect) {
+ eg->setEffect( effect );
+ } else {
+ SG_LOG( SG_VIEW, SG_ALERT, "=> Using default, builtin, Effects/ambient" );
+ ss = eg->getOrCreateStateSet();
+ ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
+ ss->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
+ ss->setTextureAttributeAndModes( 0, info->getBuffer( flightgear::RenderBufferInfo::DEPTH_BUFFER ) );
+ ss->setTextureAttributeAndModes( 1, info->getBuffer( flightgear::RenderBufferInfo::NORMAL_BUFFER ) );
+ ss->setTextureAttributeAndModes( 2, info->getBuffer( flightgear::RenderBufferInfo::DIFFUSE_BUFFER ) );
+ ss->setTextureAttributeAndModes( 3, info->getBuffer( flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER ) );
+ //ss->setTextureAttributeAndModes( 4, info->gBuffer->aoBuffer[2] );
+ ss->addUniform( new osg::Uniform( "depth_tex", 0 ) );
+ ss->addUniform( new osg::Uniform( "normal_tex", 1 ) );
+ ss->addUniform( new osg::Uniform( "color_tex", 2 ) );
+ ss->addUniform( new osg::Uniform( "spec_emis_tex", 3 ) );
+ //ss->addUniform( new osg::Uniform( "ao_tex", 4 ) );
+ ss->setRenderBinDetails( 0, "RenderBin" );
+ osg::Program* program = new osg::Program;
+ program->addShader( new osg::Shader( osg::Shader::VERTEX, ambient_vert_src ) );
+ program->addShader( new osg::Shader( osg::Shader::FRAGMENT, ambient_frag_src ) );
+ ss->setAttributeAndModes( program );
+ }
+
+ g->setName( "AmbientQuad" );
+ eg->setName("AmbientQuad");
+ eg->setCullingActive(false);
+ eg->addDrawable(g);
+ quadCam1->addChild( eg );
+
+ g = osg::createTexturedQuadGeometry( osg::Vec3(-1.,-1.,0.), osg::Vec3(2.,0.,0.), osg::Vec3(0.,2.,0.) );
+ g->setUseDisplayList(false);
+ g->setName( "SunlightQuad" );
+ eg = new simgear::EffectGeode;
+ effect = simgear::makeEffect("Effects/sunlight", true);
+ if (effect) {
+ eg->setEffect( effect );
+ } else {
+ SG_LOG( SG_VIEW, SG_ALERT, "=> Using default, builtin, Effects/sunlight" );
+ ss = eg->getOrCreateStateSet();
+ ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
+ ss->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
+ ss->setAttributeAndModes( new osg::BlendFunc( osg::BlendFunc::ONE, osg::BlendFunc::ONE ) );
+ ss->setTextureAttribute( 0, info->getBuffer( flightgear::RenderBufferInfo::DEPTH_BUFFER ) );
+ ss->setTextureAttribute( 1, info->getBuffer( flightgear::RenderBufferInfo::NORMAL_BUFFER ) );
+ ss->setTextureAttribute( 2, info->getBuffer( flightgear::RenderBufferInfo::DIFFUSE_BUFFER ) );
+ ss->setTextureAttribute( 3, info->getBuffer( flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER ) );
+ ss->setTextureAttribute( 4, info->getBuffer( flightgear::RenderBufferInfo::SHADOW_BUFFER ) );
+ ss->addUniform( new osg::Uniform( "depth_tex", 0 ) );
+ ss->addUniform( new osg::Uniform( "normal_tex", 1 ) );
+ ss->addUniform( new osg::Uniform( "color_tex", 2 ) );
+ ss->addUniform( new osg::Uniform( "spec_emis_tex", 3 ) );
+ ss->addUniform( new osg::Uniform( "shadow_tex", 4 ) );
+ ss->setRenderBinDetails( 1, "RenderBin" );
+ osg::Program* program = new osg::Program;
+ program->addShader( new osg::Shader( osg::Shader::VERTEX, sunlight_vert_src ) );
+ program->addShader( new osg::Shader( osg::Shader::FRAGMENT, sunlight_frag_src ) );
+ ss->setAttributeAndModes( program );
+ }
+ eg->setName("SunlightQuad");
+ eg->setCullingActive(false);
+ eg->addDrawable(g);
+ quadCam1->addChild( eg );
+
+ osg::Camera* lightCam = new osg::Camera;
+ ss = lightCam->getOrCreateStateSet();
+ ss->addUniform( _planes );
+ ss->addUniform( info->bufferSize );
+ lightCam->setName( "LightCamera" );
+ lightCam->setClearMask(0);
+ lightCam->setAllowEventFocus(false);
+ lightCam->setReferenceFrame(osg::Transform::RELATIVE_RF);
+ lightCam->setRenderOrder(osg::Camera::NESTED_RENDER,1);
+ lightCam->setViewMatrix(osg::Matrix::identity());
+ lightCam->setProjectionMatrix(osg::Matrix::identity());
+ lightCam->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+ lightCam->setCullMask( simgear::MODELLIGHT_BIT );
+ lightCam->setInheritanceMask( osg::CullSettings::ALL_VARIABLES & ~osg::CullSettings::CULL_MASK );
+ lightCam->addChild( mDeferredRealRoot.get() );
+
+
+ osg::Camera* quadCam2 = new osg::Camera;
+ quadCam2->setName( "QuadCamera1" );
+ quadCam2->setClearMask(0);
+ quadCam2->setAllowEventFocus(false);
+ quadCam2->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
+ quadCam2->setRenderOrder(osg::Camera::NESTED_RENDER,2);
+ quadCam2->setViewMatrix(osg::Matrix::identity());
+ quadCam2->setProjectionMatrixAsOrtho2D(-1,1,-1,1);
+ quadCam2->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+ ss = quadCam2->getOrCreateStateSet();
+ ss->addUniform( _ambientFactor );
+ ss->addUniform( info->projInverse );
+ ss->addUniform( info->viewInverse );
+ ss->addUniform( info->view );
+ ss->addUniform( _sunDiffuse );
+ ss->addUniform( _sunSpecular );
+ ss->addUniform( _sunDirection );
+ ss->addUniform( _fogColor );
+ ss->addUniform( _fogDensity );
+ ss->addUniform( _planes );
+
+ g = osg::createTexturedQuadGeometry( osg::Vec3(-1.,-1.,0.), osg::Vec3(2.,0.,0.), osg::Vec3(0.,2.,0.) );
+ g->setUseDisplayList(false);
+ g->setName( "FogQuad" );
+ eg = new simgear::EffectGeode;
+ effect = simgear::makeEffect("Effects/fog", true);
+ if (effect) {
+ eg->setEffect( effect );
+ } else {
+ SG_LOG( SG_VIEW, SG_ALERT, "=> Using default, builtin, Effects/fog" );
+ ss = eg->getOrCreateStateSet();
+ ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
+ ss->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
+ ss->setAttributeAndModes( new osg::BlendFunc( osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA ) );
+ ss->setTextureAttributeAndModes( 0, info->getBuffer( flightgear::RenderBufferInfo::DEPTH_BUFFER ) );
+ ss->setTextureAttributeAndModes( 1, info->getBuffer( flightgear::RenderBufferInfo::NORMAL_BUFFER ) );
+ ss->setTextureAttributeAndModes( 2, info->getBuffer( flightgear::RenderBufferInfo::DIFFUSE_BUFFER ) );
+ ss->setTextureAttributeAndModes( 3, info->getBuffer( flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER ) );
+ ss->addUniform( new osg::Uniform( "depth_tex", 0 ) );
+ ss->addUniform( new osg::Uniform( "normal_tex", 1 ) );
+ ss->addUniform( new osg::Uniform( "color_tex", 2 ) );
+ ss->addUniform( new osg::Uniform( "spec_emis_tex", 3 ) );
+ ss->setRenderBinDetails( 10000, "RenderBin" );
+ osg::Program* program = new osg::Program;
+ program->addShader( new osg::Shader( osg::Shader::VERTEX, fog_vert_src ) );
+ program->addShader( new osg::Shader( osg::Shader::FRAGMENT, fog_frag_src ) );
+ ss->setAttributeAndModes( program );
+ }
+ eg->setName("FogQuad");
+ eg->setCullingActive(false);
+ eg->addDrawable(g);
+ quadCam2->addChild( eg );
+
+ lightingGroup->addChild( _sky->getPreRoot() );
+ lightingGroup->addChild( _sky->getCloudRoot() );
+ lightingGroup->addChild( quadCam1 );
+ lightingGroup->addChild( lightCam );
+ lightingGroup->addChild( quadCam2 );
+
+ camera->addChild( lightingGroup );
+
+ return camera;
+}
+
+flightgear::CameraInfo*
+FGRenderer::buildDeferredPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
+ const osg::Matrix& view,
+ const osg::Matrix& projection,
+ osg::GraphicsContext* gc)
+{
+ CameraInfo* info = new CameraInfo(flags);
+ buildDeferredBuffers( info, _shadowMapSize, !fgGetBool("/sim/rendering/no-16bit-buffer", false ) );
+
+ osg::Camera* geometryCamera = buildDeferredGeometryCamera( info, gc );
+ cgroup->getViewer()->addSlave(geometryCamera, false);
+ installCullVisitor(geometryCamera);
+ int slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
+ info->getRenderStageInfo(GEOMETRY_CAMERA).slaveIndex = slaveIndex;
+
+ Camera* shadowCamera = buildDeferredShadowCamera( info, gc );
+ cgroup->getViewer()->addSlave(shadowCamera, false);
+ installCullVisitor(shadowCamera);
+ slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
+ info->getRenderStageInfo(SHADOW_CAMERA).slaveIndex = slaveIndex;
+
+ osg::Camera* lightingCamera = buildDeferredLightingCamera( info, gc );
+ cgroup->getViewer()->addSlave(lightingCamera, false);
+ installCullVisitor(lightingCamera);
+ slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
+ info->getRenderStageInfo(LIGHTING_CAMERA).slaveIndex = slaveIndex;
+
+ camera->setName( "DisplayC" );
+ camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( flightgear::DISPLAY_CAMERA, info ) );
+ camera->setReferenceFrame(Transform::ABSOLUTE_RF);
+ camera->setAllowEventFocus(false);
+ osg::Geometry* g = osg::createTexturedQuadGeometry( osg::Vec3(-1.,-1.,0.), osg::Vec3(2.,0.,0.), osg::Vec3(0.,2.,0.) );
+ g->setUseDisplayList(false); //DEBUG
+ simgear::EffectGeode* eg = new simgear::EffectGeode;
+ simgear::Effect* effect = simgear::makeEffect("Effects/display", true);
+ if (!effect) {
+ SG_LOG(SG_VIEW, SG_ALERT, "Effects/display not found");
+ return 0;
+ }
+ eg->setEffect(effect);
+ eg->setCullingActive(false);
+ eg->addDrawable(g);
+ camera->setViewMatrix(osg::Matrix::identity());
+ camera->setProjectionMatrixAsOrtho2D(-1,1,-1,1);
+ camera->addChild(eg);
+
+ cgroup->getViewer()->addSlave(camera, false);
+ installCullVisitor(camera);
+ slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
+ info->addCamera( DISPLAY_CAMERA, camera, slaveIndex, true );
+ camera->setRenderOrder(Camera::POST_RENDER, 99+slaveIndex); //FIXME
+ cgroup->addCamera(info);
+ return info;
+}
+
+
+void
+FGRenderer::setupView( void )
+{
+ osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
+ osg::initNotifyLevel();
+
+ // The number of polygon-offset "units" to place between layers. In
+ // principle, one is supposed to be enough. In practice, I find that
+ // my hardware/driver requires many more.
+ osg::PolygonOffset::setUnitsMultiplier(1);
+ osg::PolygonOffset::setFactorMultiplier(1);
+
+ // Go full screen if requested ...
+ if ( fgGetBool("/sim/startup/fullscreen") )
+ fgOSFullScreen();
+
+// build the sky
+ // The sun and moon diameters are scaled down numbers of the
+ // actual diameters. This was needed to fit both the sun and the
+ // moon within the distance to the far clip plane.
+ // Moon diameter: 3,476 kilometers
+ // Sun diameter: 1,390,000 kilometers
+ _sky->build( 80000.0, 80000.0,
+ 463.3, 361.8,
+ *globals->get_ephem(),
+ fgGetNode("/environment", true));
+
+ viewer->getCamera()
+ ->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+
+ osg::StateSet* stateSet = mRoot->getOrCreateStateSet();
+
+ stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
+
+ stateSet->setAttribute(new osg::Depth(osg::Depth::LESS));
+ stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
+
+ stateSet->setAttribute(new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01));
+ stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
+ stateSet->setAttribute(new osg::BlendFunc);
+ stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
+
+ stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
+
+ // this will be set below
+ stateSet->setMode(GL_NORMALIZE, osg::StateAttribute::OFF);
+
+ osg::Material* material = new osg::Material;
+ stateSet->setAttribute(material);
+
+ stateSet->setTextureAttribute(0, new osg::TexEnv);
+ stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF);
+
+ osg::Hint* hint = new osg::Hint(GL_FOG_HINT, GL_DONT_CARE);
+ hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/fog"));
+ stateSet->setAttribute(hint);
+ hint = new osg::Hint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE);
+ hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/polygon-smooth"));
+ stateSet->setAttribute(hint);
+ hint = new osg::Hint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
+ hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/line-smooth"));
+ stateSet->setAttribute(hint);
+ hint = new osg::Hint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
+ hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/point-smooth"));
+ stateSet->setAttribute(hint);
+ hint = new osg::Hint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE);
+ hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/perspective-correction"));
+ stateSet->setAttribute(hint);
+
+ osg::Group* sceneGroup = new osg::Group;
+ sceneGroup->addChild(globals->get_scenery()->get_scene_graph());
+ sceneGroup->setNodeMask(~simgear::BACKGROUND_BIT);
+
+ //sceneGroup->addChild(thesky->getCloudRoot());
+
+ stateSet = sceneGroup->getOrCreateStateSet();
+ stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
+
+ // need to update the light on every frame
+ // OSG LightSource objects are rather confusing. OSG only supports
+ // the 10 lights specified by OpenGL itself; if more than one
+ // LightSource in the scene graph have the same light number, it's
+ // indeterminate which values will be used to render geometry that
+ // has that light number enabled. Also, adding children to a
+ // LightSource is just a shortcut for setting up a state set that
+ // has the corresponding OpenGL light enabled: a LightSource will
+ // affect geometry anywhere in the scene graph that has its light
+ // number enabled in a state set.
+ LightSource* lightSource = new LightSource;
+ lightSource->getLight()->setDataVariance(Object::DYNAMIC);
+ // relative because of CameraView being just a clever transform node
+ lightSource->setReferenceFrame(osg::LightSource::RELATIVE_RF);
+ lightSource->setLocalStateSetModes(osg::StateAttribute::ON);
+ lightSource->setUpdateCallback(new FGLightSourceUpdateCallback);
+ mRealRoot->addChild(lightSource);
+ // we need a white diffuse light for the phase of the moon
+ osg::LightSource* sunLight = new osg::LightSource;
+ sunLight->getLight()->setDataVariance(Object::DYNAMIC);
+ sunLight->getLight()->setLightNum(1);
+ sunLight->setUpdateCallback(new FGLightSourceUpdateCallback(true));
+ sunLight->setReferenceFrame(osg::LightSource::RELATIVE_RF);
+ sunLight->setLocalStateSetModes(osg::StateAttribute::ON);
+
+ // Hang a StateSet above the sky subgraph in order to turn off
+ // light 0
+ Group* skyGroup = new Group;
+ StateSet* skySS = skyGroup->getOrCreateStateSet();
+ skySS->setMode(GL_LIGHT0, StateAttribute::OFF);
+ skyGroup->addChild(_sky->getPreRoot());
+ sunLight->addChild(skyGroup);
+ mRoot->addChild(sceneGroup);
+ if ( _classicalRenderer )
+ mRoot->addChild(sunLight);
+
+ // Clouds are added to the scene graph later
+ stateSet = globals->get_scenery()->get_scene_graph()->getOrCreateStateSet();
+ stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
+ stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
+ stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
+
+ // enable disable specular highlights.
+ // is the place where we might plug in an other fragment shader ...
+ osg::LightModel* lightModel = new osg::LightModel;
+ lightModel->setUpdateCallback(new FGLightModelUpdateCallback);
+ stateSet->setAttribute(lightModel);
+
+ // switch to enable wireframe
+ osg::PolygonMode* polygonMode = new osg::PolygonMode;
+ polygonMode->setUpdateCallback(new FGWireFrameModeUpdateCallback);
+ stateSet->setAttributeAndModes(polygonMode);
+
+ // scene fog handling
+ osg::Fog* fog = new osg::Fog;
+ fog->setUpdateCallback(new FGFogUpdateCallback);
+ stateSet->setAttributeAndModes(fog);
+ stateSet->setUpdateCallback(new FGFogEnableUpdateCallback);
+
+ // plug in the GUI
+ osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
+ if (guiCamera) {
+
+ osg::Geode* geode = new osg::Geode;
+ geode->addDrawable(new SGPuDrawable);
+ geode->addDrawable(new SGHUDDrawable);
+ guiCamera->addChild(geode);
+
+ panelSwitch = new osg::Switch;
+ osg::StateSet* stateSet = panelSwitch->getOrCreateStateSet();
+ stateSet->setRenderBinDetails(1000, "RenderBin");
+
+ // speed optimization?
+ stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
+ stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
+ stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
+ stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
+ stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
+
+
+ panelSwitch->setUpdateCallback(new FGPanelSwitchCallback);
+ panelChanged();
+
+ guiCamera->addChild(panelSwitch.get());
+ }
+
+ osg::Switch* sw = new osg::Switch;
+ sw->setUpdateCallback(new FGScenerySwitchCallback);
+ sw->addChild(mRoot.get());
+ mRealRoot->addChild(sw);
+ // The clouds are attached directly to the scene graph root
+ // because, in theory, they don't want the same default state set
+ // as the rest of the scene. This may not be true in practice.
+ if ( _classicalRenderer ) {
+ mRealRoot->addChild(_sky->getCloudRoot());
+ mRealRoot->addChild(FGCreateRedoutNode());
+ }
+ // Attach empty program to the scene root so that shader programs
+ // don't leak into state sets (effects) that shouldn't have one.
+ stateSet = mRealRoot->getOrCreateStateSet();
+ stateSet->setAttributeAndModes(new osg::Program, osg::StateAttribute::ON);
+
+ mDeferredRealRoot->addChild( mRealRoot.get() );
+}
+
+void FGRenderer::panelChanged()
+{
+ if (!panelSwitch) {
+ return;
+ }
+
+ osg::Node* n = FGPanelNode::createNode(globals->get_current_panel());
+ if (panelSwitch->getNumChildren()) {
+ panelSwitch->setChild(0, n);
+ } else {
+ panelSwitch->addChild(n);
+ }
+}
+
+// Update all Visuals (redraws anything graphics related)
+void
+FGRenderer::update( ) {
+ if (!(_scenery_loaded->getBoolValue() ||
+ _scenery_override->getBoolValue()))
+ {
+ _splash_alpha->setDoubleValue(1.0);
+ return;
+ }
+ osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
+
+ if (_splash_alpha->getDoubleValue()>0.0)
+ {
+ // Fade out the splash screen
+ const double fade_time = 0.5;
+ const double fade_steps_per_sec = 10;
+ double delay_time = SGMiscd::min(fade_time/fade_steps_per_sec,
+ (SGTimeStamp::now() - _splash_time).toSecs());
+ _splash_time = SGTimeStamp::now();
+ double sAlpha = _splash_alpha->getDoubleValue();
+ sAlpha -= SGMiscd::max(0.0,delay_time/fade_time);
+ FGScenerySwitchCallback::scenery_enabled = (sAlpha<1.0);
+ _splash_alpha->setDoubleValue((sAlpha < 0) ? 0.0 : sAlpha);
+ }
+
+ FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
+ if (!_classicalRenderer ) {
+ _ambientFactor->set( toOsg(l->scene_ambient()) );
+ _sunDiffuse->set( toOsg(l->scene_diffuse()) );
+ _sunSpecular->set( toOsg(l->scene_specular()) );
+ _sunDirection->set( osg::Vec3f(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]) );
+ }
+
+ // update fog params
+ double actual_visibility;
+ if (_cloud_status->getBoolValue()) {
+ actual_visibility = _sky->get_visibility();
+ } else {
+ actual_visibility = _visibility_m->getDoubleValue();
+ }
+
+ // idle_state is now 1000 meaning we've finished all our
+ // initializations and are running the main loop, so this will
+ // now work without seg faulting the system.
+
+ FGViewer *current__view = globals->get_current_view();
+ // Force update of center dependent values ...
+ current__view->set_dirty();
+
+ osg::Camera *camera = viewer->getCamera();
+
+ bool skyblend = _skyblend->getBoolValue();
+ if ( skyblend ) {
+
+ if ( _textures->getBoolValue() ) {
+ SGVec4f clearColor(l->adj_fog_color());
+ camera->setClearColor(toOsg(clearColor));
+ }
+ } else {
+ SGVec4f clearColor(l->sky_color());
+ camera->setClearColor(toOsg(clearColor));
+ }
+
+ // update fog params if visibility has changed
+ double visibility_meters = _visibility_m->getDoubleValue();
+ _sky->set_visibility(visibility_meters);
+
+ double altitude_m = _altitude_ft->getDoubleValue() * SG_FEET_TO_METER;
+ _sky->modify_vis( altitude_m, 0.0 /* time factor, now unused */);
+
+ // update the sky dome
+ if ( skyblend ) {
+
+ // The sun and moon distances are scaled down versions
+ // of the actual distance to get both the moon and the sun
+ // within the range of the far clip plane.
+ // Moon distance: 384,467 kilometers
+ // Sun distance: 150,000,000 kilometers
+
+ double sun_horiz_eff, moon_horiz_eff;
+ if (_horizon_effect->getBoolValue()) {
+ sun_horiz_eff
+ = 0.67 + pow(osg::clampAbove(0.5 + cos(l->get_sun_angle()),
+ 0.0),
+ 0.33) / 3.0;
+ moon_horiz_eff
+ = 0.67 + pow(osg::clampAbove(0.5 + cos(l->get_moon_angle()),
+ 0.0),
+ 0.33)/3.0;
+ } else {
+ sun_horiz_eff = moon_horiz_eff = 1.0;
+ }
+
+ SGSkyState sstate;
+ sstate.pos = current__view->getViewPosition();
+ sstate.pos_geod = current__view->getPosition();
+ sstate.ori = current__view->getViewOrientation();
+ sstate.spin = l->get_sun_rotation();
+ sstate.gst = globals->get_time_params()->getGst();
+ sstate.sun_dist = 50000.0 * sun_horiz_eff;
+ sstate.moon_dist = 40000.0 * moon_horiz_eff;
+ sstate.sun_angle = l->get_sun_angle();
+
+ SGSkyColor scolor;
+ scolor.sky_color = SGVec3f(l->sky_color().data());
+ scolor.adj_sky_color = SGVec3f(l->adj_sky_color().data());
+ scolor.fog_color = SGVec3f(l->adj_fog_color().data());
+ scolor.cloud_color = SGVec3f(l->cloud_color().data());
+ scolor.sun_angle = l->get_sun_angle();
+ scolor.moon_angle = l->get_moon_angle();
+
+ double delta_time_sec = _sim_delta_sec->getDoubleValue();
+ _sky->reposition( sstate, *globals->get_ephem(), delta_time_sec );
+ _sky->repaint( scolor, *globals->get_ephem() );
+
+ //OSGFIXME
+// shadows->setupShadows(
+// current__view->getLongitude_deg(),
+// current__view->getLatitude_deg(),
+// globals->get_time_params()->getGst(),
+// globals->get_ephem()->getSunRightAscension(),
+// globals->get_ephem()->getSunDeclination(),
+// l->get_sun_angle());
+
+ }
+
+// sgEnviro.setLight(l->adj_fog_color());
+// sgEnviro.startOfFrame(current__view->get_view_pos(),
+// current__view->get_world_up(),
+// current__view->getLongitude_deg(),
+// current__view->getLatitude_deg(),
+// current__view->getAltitudeASL_ft() * SG_FEET_TO_METER,
+// delta_time_sec);
+
+ // OSGFIXME
+// sgEnviro.drawLightning();
+
+// double current_view_origin_airspeed_horiz_kt =
+// fgGetDouble("/velocities/airspeed-kt", 0.0)
+// * cos( fgGetDouble("/orientation/pitch-deg", 0.0)
+// * SGD_DEGREES_TO_RADIANS);
+
+ // OSGFIXME
+// if( is_internal )
+// shadows->endOfFrame();
+
+ // need to call the update visitor once
+ mFrameStamp->setCalendarTime(*globals->get_time_params()->getGmt());
+ mUpdateVisitor->setViewData(current__view->getViewPosition(),
+ current__view->getViewOrientation());
+ SGVec3f direction(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]);
+ mUpdateVisitor->setLight(direction, l->scene_ambient(),
+ l->scene_diffuse(), l->scene_specular(),
+ l->adj_fog_color(),
+ l->get_sun_angle()*SGD_RADIANS_TO_DEGREES);
+ mUpdateVisitor->setVisibility(actual_visibility);
+ simgear::GroundLightManager::instance()->update(mUpdateVisitor.get());
+ osg::Node::NodeMask cullMask = ~simgear::LIGHTS_BITS & ~simgear::PICK_BIT;
+ cullMask |= simgear::GroundLightManager::instance()
+ ->getLightNodeMask(mUpdateVisitor.get());
+ if (_panel_hotspots->getBoolValue())
+ cullMask |= simgear::PICK_BIT;
+ CameraGroup::getDefault()->setCameraCullMasks(cullMask);
+ if ( !_classicalRenderer ) {
+ _fogColor->set( toOsg( l->adj_fog_color() ) );
+ _fogDensity->set( float( mUpdateVisitor->getFogExp2Density() ) );
+ }
+}
+
+void
+FGRenderer::resize( int width, int height )
+{
+ int curWidth = _xsize->getIntValue(),
+ curHeight = _ysize->getIntValue();
+ SG_LOG(SG_VIEW, SG_DEBUG, "FGRenderer::resize: new size " << width << " x " << height);
+ if ((curHeight != height) || (curWidth != width)) {
+ // must guard setting these, or PLIB-PUI fails with too many live interfaces
+ _xsize->setIntValue(width);
+ _ysize->setIntValue(height);
+ }
+}
+
+bool
+FGRenderer::pick(std::vector<SGSceneryPick>& pickList,
+ const osgGA::GUIEventAdapter* ea)
+{
+ // wipe out the return ...
+ pickList.clear();
+ typedef osgUtil::LineSegmentIntersector::Intersections Intersections;
+ Intersections intersections;
+
+ if (!computeIntersections(CameraGroup::getDefault(), ea, intersections))
+ return false;
+ for (Intersections::iterator hit = intersections.begin(),
+ e = intersections.end();
+ hit != e;
+ ++hit) {
+ const osg::NodePath& np = hit->nodePath;
+ osg::NodePath::const_reverse_iterator npi;
+ for (npi = np.rbegin(); npi != np.rend(); ++npi) {
+ SGSceneUserData* ud = SGSceneUserData::getSceneUserData(*npi);
+ if (!ud)
+ continue;
+ for (unsigned i = 0; i < ud->getNumPickCallbacks(); ++i) {
+ SGPickCallback* pickCallback = ud->getPickCallback(i);
+ if (!pickCallback)
+ continue;
+ SGSceneryPick sceneryPick;
+ sceneryPick.info.local = toSG(hit->getLocalIntersectPoint());
+ sceneryPick.info.wgs84 = toSG(hit->getWorldIntersectPoint());
+ sceneryPick.callback = pickCallback;
+ pickList.push_back(sceneryPick);
+ }
+ }
+ }
+ return !pickList.empty();
+}
+
+void
+FGRenderer::setViewer(osgViewer::Viewer* viewer_)
+{
+ viewer = viewer_;
+}
+
+void
+FGRenderer::setEventHandler(FGEventHandler* eventHandler_)
+{
+ eventHandler = eventHandler_;
+}
+
+void
+FGRenderer::addCamera(osg::Camera* camera, bool useSceneData)
+{
+ mRealRoot->addChild(camera);
+}
+
+void
+FGRenderer::removeCamera(osg::Camera* camera)
+{
+ mRealRoot->removeChild(camera);
+}
+
+void
+FGRenderer::setPlanes( double zNear, double zFar )
+{
+ _planes->set( osg::Vec3f( - zFar, - zFar * zNear, zFar - zNear ) );
+}
+
+bool
+fgDumpSceneGraphToFile(const char* filename)
+{
+ return osgDB::writeNodeFile(*mRealRoot.get(), filename);
+}
+
+bool
+fgDumpTerrainBranchToFile(const char* filename)
+{
+ return osgDB::writeNodeFile( *globals->get_scenery()->get_terrain_branch(),
+ filename );
+}
+
+// For debugging
+bool
+fgDumpNodeToFile(osg::Node* node, const char* filename)
+{
+ return osgDB::writeNodeFile(*node, filename);
+}
+
+namespace flightgear
+{
+using namespace osg;
+
+class VisibleSceneInfoVistor : public NodeVisitor, CullStack
+{
+public:
+ VisibleSceneInfoVistor()
+ : NodeVisitor(CULL_VISITOR, TRAVERSE_ACTIVE_CHILDREN)
+ {
+ setCullingMode(CullSettings::SMALL_FEATURE_CULLING
+ | CullSettings::VIEW_FRUSTUM_CULLING);
+ setComputeNearFarMode(CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+ }
+
+ VisibleSceneInfoVistor(const VisibleSceneInfoVistor& rhs)
+ {
+ }
+
+ META_NodeVisitor("flightgear","VisibleSceneInfoVistor")
+
+ typedef std::map<const std::string,int> InfoMap;
+
+ void getNodeInfo(Node* node)
+ {
+ const char* typeName = typeid(*node).name();
+ classInfo[typeName]++;
+ const std::string& nodeName = node->getName();
+ if (!nodeName.empty())
+ nodeInfo[nodeName]++;
+ }
+
+ void dumpInfo()
+ {
+ using namespace std;
+ typedef vector<InfoMap::iterator> FreqVector;
+ cout << "class info:\n";
+ FreqVector classes;
+ for (InfoMap::iterator itr = classInfo.begin(), end = classInfo.end();
+ itr != end;
+ ++itr)
+ classes.push_back(itr);
+ sort(classes.begin(), classes.end(), freqComp);
+ for (FreqVector::iterator itr = classes.begin(), end = classes.end();
+ itr != end;
+ ++itr) {
+ cout << (*itr)->first << " " << (*itr)->second << "\n";
+ }
+ cout << "\nnode info:\n";
+ FreqVector nodes;
+ for (InfoMap::iterator itr = nodeInfo.begin(), end = nodeInfo.end();
+ itr != end;
+ ++itr)
+ nodes.push_back(itr);
+
+ sort (nodes.begin(), nodes.end(), freqComp);
+ for (FreqVector::iterator itr = nodes.begin(), end = nodes.end();
+ itr != end;
+ ++itr) {
+ cout << (*itr)->first << " " << (*itr)->second << "\n";
+ }
+ cout << endl;
+ }
+
+ void doTraversal(Camera* camera, Node* root, Viewport* viewport)
+ {
+ ref_ptr<RefMatrix> projection
+ = createOrReuseMatrix(camera->getProjectionMatrix());
+ ref_ptr<RefMatrix> mv = createOrReuseMatrix(camera->getViewMatrix());
+ if (!viewport)
+ viewport = camera->getViewport();
+ if (viewport)
+ pushViewport(viewport);
+ pushProjectionMatrix(projection.get());
+ pushModelViewMatrix(mv.get(), Transform::ABSOLUTE_RF);
+ root->accept(*this);
+ popModelViewMatrix();
+ popProjectionMatrix();
+ if (viewport)
+ popViewport();
+ dumpInfo();
+ }
+
+ void apply(Node& node)
+ {
+ if (isCulled(node))
+ return;
+ pushCurrentMask();
+ getNodeInfo(&node);
+ traverse(node);
+ popCurrentMask();
+ }
+ void apply(Group& node)
+ {
+ if (isCulled(node))
+ return;
+ pushCurrentMask();
+ getNodeInfo(&node);
+ traverse(node);
+ popCurrentMask();
+ }
+
+ void apply(Transform& node)
+ {
+ if (isCulled(node))
+ return;
+ pushCurrentMask();
+ ref_ptr<RefMatrix> matrix = createOrReuseMatrix(*getModelViewMatrix());
+ node.computeLocalToWorldMatrix(*matrix,this);
+ pushModelViewMatrix(matrix.get(), node.getReferenceFrame());
+ getNodeInfo(&node);
+ traverse(node);
+ popModelViewMatrix();
+ popCurrentMask();
+ }
+
+ void apply(Camera& camera)
+ {
+ // Save current cull settings
+ CullSettings saved_cull_settings(*this);
+
+ // set cull settings from this Camera
+ setCullSettings(camera);
+ // inherit the settings from above
+ inheritCullSettings(saved_cull_settings, camera.getInheritanceMask());
+
+ // set the cull mask.
+ unsigned int savedTraversalMask = getTraversalMask();
+ bool mustSetCullMask = (camera.getInheritanceMask()
+ & osg::CullSettings::CULL_MASK) == 0;
+ if (mustSetCullMask)
+ setTraversalMask(camera.getCullMask());
+
+ osg::RefMatrix* projection = 0;
+ osg::RefMatrix* modelview = 0;
+
+ if (camera.getReferenceFrame()==osg::Transform::RELATIVE_RF) {
+ if (camera.getTransformOrder()==osg::Camera::POST_MULTIPLY) {
+ projection = createOrReuseMatrix(*getProjectionMatrix()
+ *camera.getProjectionMatrix());
+ modelview = createOrReuseMatrix(*getModelViewMatrix()
+ * camera.getViewMatrix());
+ }
+ else { // pre multiply
+ projection = createOrReuseMatrix(camera.getProjectionMatrix()
+ * (*getProjectionMatrix()));
+ modelview = createOrReuseMatrix(camera.getViewMatrix()
+ * (*getModelViewMatrix()));
+ }
+ } else {
+ // an absolute reference frame
+ projection = createOrReuseMatrix(camera.getProjectionMatrix());
+ modelview = createOrReuseMatrix(camera.getViewMatrix());
+ }
+ if (camera.getViewport())
+ pushViewport(camera.getViewport());
+
+ pushProjectionMatrix(projection);
+ pushModelViewMatrix(modelview, camera.getReferenceFrame());
+
+ traverse(camera);
+
+ // restore the previous model view matrix.
+ popModelViewMatrix();
+
+ // restore the previous model view matrix.
+ popProjectionMatrix();
+
+ if (camera.getViewport()) popViewport();
+
+ // restore the previous traversal mask settings
+ if (mustSetCullMask)
+ setTraversalMask(savedTraversalMask);
+
+ // restore the previous cull settings
+ setCullSettings(saved_cull_settings);
+ }
+
+protected:
+ // sort in reverse
+ static bool freqComp(const InfoMap::iterator& lhs, const InfoMap::iterator& rhs)
+ {
+ return lhs->second > rhs->second;
+ }
+ InfoMap classInfo;
+ InfoMap nodeInfo;
+};
+
+bool printVisibleSceneInfo(FGRenderer* renderer)
+{
+ osgViewer::Viewer* viewer = renderer->getViewer();
+ VisibleSceneInfoVistor vsv;
+ Viewport* vp = 0;
+ if (!viewer->getCamera()->getViewport() && viewer->getNumSlaves() > 0) {
+ const View::Slave& slave = viewer->getSlave(0);
+ vp = slave._camera->getViewport();
+ }
+ vsv.doTraversal(viewer->getCamera(), viewer->getSceneData(), vp);
+ return true;
+}
+
+}
+// end of renderer.cxx
+
--- /dev/null
+
+#ifndef __FG_RENDERER_HXX
+#define __FG_RENDERER_HXX 1
+
+#include <simgear/scene/util/SGPickCallback.hxx>
+#include <simgear/props/props.hxx>
+#include <simgear/timing/timestamp.hxx>
+
+#include <osg/ref_ptr>
+#include <osg/Matrix>
+#include <osg/Vec3>
+
+namespace osg
+{
+class Camera;
+class Group;
+class GraphicsContext;
+}
+
+namespace osgGA
+{
+class GUIEventAdapter;
+}
+
+namespace osgShadow
+{
+class ShadowedScene;
+}
+
+namespace osgViewer
+{
+class Viewer;
+}
+
+namespace flightgear
+{
+class FGEventHandler;
+struct CameraInfo;
+class CameraGroup;
+}
+
+class SGSky;
+
+class FGRenderer {
+
+public:
+
+ FGRenderer();
+ ~FGRenderer();
+
+ void splashinit();
+ void init();
+
+ void setupView();
+
+ void resize(int width, int height );
+
+ void update();
+
+ /** Just pick into the scene and return the pick callbacks on the way ...
+ */
+ bool pick( std::vector<SGSceneryPick>& pickList,
+ const osgGA::GUIEventAdapter* ea );
+
+ /** Get and set the OSG Viewer object, if any.
+ */
+ osgViewer::Viewer* getViewer() { return viewer.get(); }
+ const osgViewer::Viewer* getViewer() const { return viewer.get(); }
+ void setViewer(osgViewer::Viewer* viewer);
+ /** Get and set the manipulator object, if any.
+ */
+ flightgear::FGEventHandler* getEventHandler() { return eventHandler.get(); }
+ const flightgear::FGEventHandler* getEventHandler() const { return eventHandler.get(); }
+ void setEventHandler(flightgear::FGEventHandler* manipulator);
+
+ /** Add a top level camera.
+ */
+ void addCamera(osg::Camera* camera, bool useSceneData);
+
+ void removeCamera(osg::Camera* camera);
+
+ /** Add a camera to the group. The camera is added to the viewer
+ * as a slave. See osgViewer::Viewer::addSlave.
+ * @param flags properties of the camera; see CameraGroup::Flags
+ * @param projection slave projection matrix
+ * @param view slave view matrix
+ * @param useMasterSceneData whether the camera displays the
+ * viewer's scene data.
+ * @return a CameraInfo object for the camera.
+ */
+ flightgear::CameraInfo* buildRenderingPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
+ const osg::Matrix& view,
+ const osg::Matrix& projection,
+ osg::GraphicsContext* gc,
+ bool useMasterSceneData);
+
+ /**
+ */
+ flightgear::CameraInfo* buildClassicalPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
+ const osg::Matrix& view,
+ const osg::Matrix& projection,
+ bool useMasterSceneData);
+
+ /**
+ */
+ flightgear::CameraInfo* buildDeferredPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
+ const osg::Matrix& view, const osg::Matrix& projection, osg::GraphicsContext* gc);
+
+ void updateShadowCamera(const flightgear::CameraInfo* info, const osg::Vec3d& position);
+ void updateShadowMapSize(int mapSize);
+ void enableShadows(bool enabled);
+ void updateCascadeFar(int index, float far_m);
+ void updateCascadeNumber(size_t num);
+
+ SGSky* getSky() const { return _sky; }
+
+ void setPlanes( double zNear, double zFar );
+
+ /**
+ * inform the renderer when the global (2D) panel is changed
+ */
+ void panelChanged();
+protected:
+ osg::ref_ptr<osgViewer::Viewer> viewer;
+ osg::ref_ptr<flightgear::FGEventHandler> eventHandler;
+ SGPropertyNode_ptr _scenery_loaded,_scenery_override;
+ SGPropertyNode_ptr _skyblend, _splash_alpha;
+ SGPropertyNode_ptr _point_sprites, _enhanced_lighting, _distance_attenuation;
+ SGPropertyNode_ptr _textures;
+ SGPropertyNode_ptr _cloud_status, _visibility_m;
+ SGPropertyNode_ptr _xsize, _ysize;
+ SGPropertyNode_ptr _panel_hotspots, _sim_delta_sec, _horizon_effect, _altitude_ft;
+ SGPropertyNode_ptr _virtual_cockpit;
+ SGTimeStamp _splash_time;
+ SGSky* _sky;
+ bool _classicalRenderer;
+ int _shadowMapSize;
+ size_t _numCascades;
+ float _cascadeFar[4];
+
+ osg::Camera* buildDeferredGeometryCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc );
+ osg::Camera* buildDeferredShadowCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc );
+ osg::Camera* buildDeferredLightingCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc );
+ void updateShadowCascade(const flightgear::CameraInfo* info, osg::Camera* camera, osg::Group* grp, int idx, double left, double right, double bottom, double top, double zNear, double f1, double f2);
+ osg::Vec3 getSunDirection() const;
+ osg::ref_ptr<osg::Uniform> _ambientFactor;
+ osg::ref_ptr<osg::Uniform> _sunDiffuse;
+ osg::ref_ptr<osg::Uniform> _sunSpecular;
+ osg::ref_ptr<osg::Uniform> _sunDirection;
+ osg::ref_ptr<osg::Uniform> _planes;
+ osg::ref_ptr<osg::Uniform> _fogColor;
+ osg::ref_ptr<osg::Uniform> _fogDensity;
+ osg::ref_ptr<osg::Uniform> _shadowNumber;
+ osg::ref_ptr<osg::Uniform> _shadowDistances;
+};
+
+bool fgDumpSceneGraphToFile(const char* filename);
+bool fgDumpTerrainBranchToFile(const char* filename);
+
+namespace flightgear
+{
+bool printVisibleSceneInfo(FGRenderer* renderer);
+}
+
+#endif
--- /dev/null
+// splash.cxx -- draws the initial splash screen
+//
+// Written by Curtis Olson, started July 1998. (With a little looking
+// at Freidemann's panel code.) :-)
+//
+// Copyright (C) 1997 Michele F. America - nomimarketing@mail.telepac.pt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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 GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// $Id$
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <osg/BlendFunc>
+#include <osg/Camera>
+#include <osg/Depth>
+#include <osg/Geometry>
+#include <osg/Node>
+#include <osg/NodeCallback>
+#include <osg/NodeVisitor>
+#include <osg/StateSet>
+#include <osg/Switch>
+#include <osg/Texture2D>
+#include <osgUtil/CullVisitor>
+#include <osgText/Text>
+#include <osgDB/ReadFile>
+
+#include <simgear/compiler.h>
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/math/sg_random.h>
+#include <simgear/misc/sg_path.hxx>
+
+#include <plib/fnt.h>
+
+#include "GUI/FGFontCache.hxx"
+#include "GUI/FGColor.hxx"
+
+#include <Main/globals.hxx>
+#include <Main/fg_props.hxx>
+#include <Main/fg_os.hxx>
+#include "splash.hxx"
+#include "renderer.hxx"
+
+class FGSplashUpdateCallback : public osg::Drawable::UpdateCallback {
+public:
+ FGSplashUpdateCallback(osg::Vec4Array* colorArray, SGPropertyNode* prop) :
+ _colorArray(colorArray),
+ _colorProperty(prop),
+ _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true))
+ { }
+ virtual void update(osg::NodeVisitor*, osg::Drawable*)
+ {
+ FGColor c(0, 0, 0);
+ if (_colorProperty) {
+ c.merge(_colorProperty);
+ (*_colorArray)[0][0] = c.red();
+ (*_colorArray)[0][1] = c.green();
+ (*_colorArray)[0][2] = c.blue();
+ }
+ (*_colorArray)[0][3] = _alphaProperty->getFloatValue();
+ _colorArray->dirty();
+ }
+private:
+ osg::ref_ptr<osg::Vec4Array> _colorArray;
+ SGSharedPtr<const SGPropertyNode> _colorProperty;
+ SGSharedPtr<const SGPropertyNode> _alphaProperty;
+};
+
+class FGSplashTextUpdateCallback : public osg::Drawable::UpdateCallback {
+public:
+ FGSplashTextUpdateCallback(const SGPropertyNode* prop) :
+ _textProperty(prop),
+ _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true)),
+ _styleProperty(fgGetNode("/sim/gui/style[0]", true))
+ {}
+ virtual void update(osg::NodeVisitor*, osg::Drawable* drawable)
+ {
+ assert(dynamic_cast<osgText::Text*>(drawable));
+ osgText::Text* text = static_cast<osgText::Text*>(drawable);
+
+ FGColor c(1.0, 0.9, 0.0);
+ c.merge(_styleProperty->getNode("colors/splash-font"));
+ float alpha = _alphaProperty->getFloatValue();
+ text->setColor(osg::Vec4(c.red(), c.green(), c.blue(), alpha));
+
+ const char* s = _textProperty->getStringValue();
+ if (s && fgGetBool("/sim/startup/splash-progress", true))
+ text->setText(s);
+ else
+ text->setText("");
+ }
+private:
+ SGSharedPtr<const SGPropertyNode> _textProperty;
+ SGSharedPtr<const SGPropertyNode> _alphaProperty;
+ SGSharedPtr<const SGPropertyNode> _styleProperty;
+};
+
+
+
+class FGSplashContentProjectionCalback : public osg::NodeCallback {
+public:
+ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
+ {
+ assert(dynamic_cast<osgUtil::CullVisitor*>(nv));
+ osgUtil::CullVisitor* cullVisitor = static_cast<osgUtil::CullVisitor*>(nv);
+
+ // adjust the projection matrix in a way that preserves the aspect ratio
+ // of the content ...
+ const osg::Viewport* viewport = cullVisitor->getViewport();
+ float viewportAspect = float(viewport->height())/float(viewport->width());
+
+ float height, width;
+ if (viewportAspect < 1) {
+ height = 1;
+ width = 1/viewportAspect;
+ } else {
+ height = viewportAspect;
+ width = 1;
+ }
+
+ osg::RefMatrix* matrix = new osg::RefMatrix;
+ matrix->makeOrtho2D(-width, width, -height, height);
+
+ // The trick is to have the projection matrix adapted independent
+ // of the scenegraph but dependent on the viewport of this current
+ // camera we cull for. Therefore we do not put that projection matrix into
+ // an additional camera rather than from within that cull callback.
+ cullVisitor->pushProjectionMatrix(matrix);
+ traverse(node, nv);
+ cullVisitor->popProjectionMatrix();
+ }
+};
+
+char *genNameString()
+{
+ std::string website = "http://www.flightgear.org";
+ std::string programName = "FlightGear";
+ char *name = new char[26];
+ name[20] = 114;
+ name[8] = 119;
+ name[5] = 47;
+ name[12] = 108;
+ name[2] = 116;
+ name[1] = 116;
+ name[16] = 116;
+ name[13] = 105;
+ name[17] = 103;
+ name[19] = 97;
+ name[25] = 0;
+ name[0] = 104;
+ name[24] = 103;
+ name[21] = 46;
+ name[15] = 104;
+ name[3] = 112;
+ name[22] = 111;
+ name[18] = 101;
+ name[7] = 119;
+ name[14] = 103;
+ name[23] = 114;
+ name[4] = 58;
+ name[11] = 102;
+ name[9] = 119;
+ name[10] = 46;
+ name[6] = 47;
+ return name;
+}
+
+static osg::Node* fgCreateSplashCamera()
+{
+ const char* splash_texture = fgGetString("/sim/startup/splash-texture");
+ SGSharedPtr<SGPropertyNode> style = fgGetNode("/sim/gui/style[0]", true);
+
+ char *namestring = genNameString();
+ fgSetString("/sim/startup/program-name", namestring);
+ delete[] namestring;
+
+ SGPath tpath;
+ if (splash_texture && strcmp(splash_texture, "")) {
+ tpath = globals->resolve_maybe_aircraft_path(splash_texture);
+ if (tpath.isNull())
+ {
+ SG_LOG( SG_VIEW, SG_ALERT, "Cannot find splash screen file '" << splash_texture
+ << "'. Using default." );
+ }
+ }
+
+ if (tpath.isNull()) {
+ // no splash screen specified - select random image
+ tpath = globals->get_fg_root();
+ // load in the texture data
+ int num = (int)(sg_random() * 5.0 + 1.0);
+ char num_str[5];
+ snprintf(num_str, 4, "%d", num);
+
+ tpath.append( "Textures/Splash" );
+ tpath.concat( num_str );
+ tpath.concat( ".png" );
+ }
+
+ osg::Texture2D* splashTexture = new osg::Texture2D;
+ splashTexture->setImage(osgDB::readImageFile(tpath.c_str()));
+
+ osg::Camera* camera = new osg::Camera;
+ camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
+ camera->setProjectionMatrix(osg::Matrix::ortho2D(-1, 1, -1, 1));
+ camera->setViewMatrix(osg::Matrix::identity());
+ camera->setRenderOrder(osg::Camera::POST_RENDER, 10000);
+ camera->setClearMask(0);
+ camera->setAllowEventFocus(false);
+ camera->setCullingActive(false);
+
+ osg::StateSet* stateSet = camera->getOrCreateStateSet();
+ stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
+ stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
+ stateSet->setAttribute(new osg::BlendFunc);
+ stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
+ stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
+ stateSet->setAttribute(new osg::Depth(osg::Depth::ALWAYS, 0, 1, false));
+ stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
+
+
+ osg::Geometry* geometry = new osg::Geometry;
+ geometry->setSupportsDisplayList(false);
+
+ osg::Vec3Array* vertexArray = new osg::Vec3Array;
+ vertexArray->push_back(osg::Vec3(-1, -1, 0));
+ vertexArray->push_back(osg::Vec3( 1, -1, 0));
+ vertexArray->push_back(osg::Vec3( 1, 1, 0));
+ vertexArray->push_back(osg::Vec3(-1, 1, 0));
+ geometry->setVertexArray(vertexArray);
+ osg::Vec4Array* colorArray = new osg::Vec4Array;
+ colorArray->push_back(osg::Vec4(0, 0, 0, 1));
+ geometry->setColorArray(colorArray);
+ geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
+ geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
+ geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray,
+ style->getNode("colors/splash-screen")));
+
+ osg::Geode* geode = new osg::Geode;
+ geode->addDrawable(geometry);
+
+ stateSet = geode->getOrCreateStateSet();
+ stateSet->setRenderBinDetails(1, "RenderBin");
+ camera->addChild(geode);
+
+
+ // The group is needed because of osg is handling the cull callbacks in a
+ // different way for groups than for a geode. It does not hurt here ...
+ osg::Group* group = new osg::Group;
+ group->setCullCallback(new FGSplashContentProjectionCalback);
+ camera->addChild(group);
+
+ geode = new osg::Geode;
+ stateSet = geode->getOrCreateStateSet();
+ stateSet->setRenderBinDetails(2, "RenderBin");
+ group->addChild(geode);
+
+
+ geometry = new osg::Geometry;
+ geometry->setSupportsDisplayList(false);
+
+ vertexArray = new osg::Vec3Array;
+ vertexArray->push_back(osg::Vec3(-0.84, -0.84, 0));
+ vertexArray->push_back(osg::Vec3( 0.84, -0.84, 0));
+ vertexArray->push_back(osg::Vec3( 0.84, 0.84, 0));
+ vertexArray->push_back(osg::Vec3(-0.84, 0.84, 0));
+ geometry->setVertexArray(vertexArray);
+ osg::Vec2Array* texCoordArray = new osg::Vec2Array;
+ texCoordArray->push_back(osg::Vec2(0, 0));
+ texCoordArray->push_back(osg::Vec2(1, 0));
+ texCoordArray->push_back(osg::Vec2(1, 1));
+ texCoordArray->push_back(osg::Vec2(0, 1));
+ geometry->setTexCoordArray(0, texCoordArray);
+ colorArray = new osg::Vec4Array;
+ colorArray->push_back(osg::Vec4(1, 1, 1, 1));
+ geometry->setColorArray(colorArray);
+ geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
+ geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
+ geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray, 0));
+ stateSet = geometry->getOrCreateStateSet();
+ stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
+ stateSet->setTextureAttribute(0, splashTexture);
+ geode->addDrawable(geometry);
+
+
+ osgText::Text* text = new osgText::Text;
+ std::string fn = style->getStringValue("fonts/splash", "");
+ text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
+ text->setCharacterSize(0.06);
+ text->setColor(osg::Vec4(1, 1, 1, 1));
+ text->setPosition(osg::Vec3(0, -0.92, 0));
+ text->setAlignment(osgText::Text::CENTER_CENTER);
+ SGPropertyNode* prop = fgGetNode("/sim/startup/splash-progress-text", true);
+ prop->setStringValue("initializing");
+ text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
+ geode->addDrawable(text);
+
+ text = new osgText::Text;
+ text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
+ text->setCharacterSize(0.08);
+ text->setColor(osg::Vec4(1, 1, 1, 1));
+ text->setPosition(osg::Vec3(0, 0.92, 0));
+ text->setAlignment(osgText::Text::CENTER_CENTER);
+ prop = fgGetNode("/sim/startup/program-name", "FlightGear");
+ text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
+ geode->addDrawable(text);
+
+
+ text = new osgText::Text;
+ text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
+ text->setCharacterSize(0.06);
+ text->setColor(osg::Vec4(1, 1, 1, 1));
+ text->setPosition(osg::Vec3(0, 0.82, 0));
+ text->setAlignment(osgText::Text::CENTER_CENTER);
+ prop = fgGetNode("/sim/startup/splash-title", true);
+ text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
+ geode->addDrawable(text);
+
+ return camera;
+}
+
+// update callback for the switch node guarding that splash
+class FGSplashGroupUpdateCallback : public osg::NodeCallback {
+public:
+ FGSplashGroupUpdateCallback() :
+ _splashAlphaNode(fgGetNode("/sim/startup/splash-alpha", true))
+ { }
+ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
+ {
+ assert(dynamic_cast<osg::Group*>(node));
+ osg::Group* group = static_cast<osg::Group*>(node);
+
+ double alpha = _splashAlphaNode->getDoubleValue();
+ if (alpha <= 0 || !fgGetBool("/sim/startup/splash-screen"))
+ group->removeChild(0, group->getNumChildren());
+ else if (group->getNumChildren() == 0)
+ group->addChild(fgCreateSplashCamera());
+
+ traverse(node, nv);
+ }
+private:
+ SGSharedPtr<const SGPropertyNode> _splashAlphaNode;
+};
+
+osg::Node* fgCreateSplashNode() {
+ osg::Group* group = new osg::Group;
+ group->setUpdateCallback(new FGSplashGroupUpdateCallback);
+ return group;
+}
+
+// Initialize the splash screen
+void fgSplashInit () {
+ SG_LOG( SG_VIEW, SG_INFO, "Initializing splash screen" );
+ globals->get_renderer()->splashinit();
+}
+
+void fgSplashProgress ( const char *text ) {
+ SG_LOG( SG_VIEW, SG_INFO, "Splash screen progress " << text );
+ fgSetString("/sim/startup/splash-progress-text", text);
+}
--- /dev/null
+// splash.hxx -- draws the initial splash screen
+//
+// Written by Curtis Olson, started July 1998. (With a little looking
+// at Freidemann's panel code.) :-)
+//
+// Copyright (C) 1997 Michele F. America - nomimarketing@mail.telepac.pt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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 GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// $Id$
+
+
+#ifndef _SPLASH_HXX
+#define _SPLASH_HXX
+
+#include <osg/Node>
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+// Initialize the splash screen
+void fgSplashInit ();
+
+// Set progress information
+void fgSplashProgress ( const char *text );
+
+// Retrieve the splash screen node ...
+osg::Node* fgCreateSplashNode();
+
+#endif // _SPLASH_HXX
+
+
--- /dev/null
+// viewer.cxx -- class for managing a viewer in the flightgear world.
+//
+// Written by Curtis Olson, started August 1997.
+// overhaul started October 2000.
+// partially rewritten by Jim Wilson jim@kelcomaine.com using interface
+// by David Megginson March 2002
+//
+// Copyright (C) 1997 - 2000 Curtis L. Olson - http://www.flightgear.org/~curt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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 GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// $Id$
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <simgear/compiler.h>
+#include <cassert>
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/constants.h>
+#include <simgear/scene/model/placement.hxx>
+#include <simgear/scene/util/OsgMath.hxx>
+
+#include <Main/fg_props.hxx>
+#include <Main/globals.hxx>
+#include <Scenery/scenery.hxx>
+#include <Model/acmodel.hxx>
+
+#include "viewer.hxx"
+
+#include "CameraGroup.hxx"
+
+using namespace flightgear;
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FGViewer.
+////////////////////////////////////////////////////////////////////////
+
+// Constructor...
+FGViewer::FGViewer( fgViewType Type, bool from_model, int from_model_index,
+ bool at_model, int at_model_index,
+ double damp_roll, double damp_pitch, double damp_heading,
+ double x_offset_m, double y_offset_m, double z_offset_m,
+ double heading_offset_deg, double pitch_offset_deg,
+ double roll_offset_deg,
+ double fov_deg, double aspect_ratio_multiplier,
+ double target_x_offset_m, double target_y_offset_m,
+ double target_z_offset_m, double near_m, bool internal ):
+ _dirty(true),
+ _roll_deg(0),
+ _pitch_deg(0),
+ _heading_deg(0),
+ _scaling_type(FG_SCALING_MAX),
+ _cameraGroup(CameraGroup::getDefault())
+{
+ _absolute_view_pos = SGVec3d(0, 0, 0);
+ _type = Type;
+ _from_model = from_model;
+ _from_model_index = from_model_index;
+ _at_model = at_model;
+ _at_model_index = at_model_index;
+
+ _internal = internal;
+
+ _dampFactor = SGVec3d::zeros();
+ _dampOutput = SGVec3d::zeros();
+ _dampTarget = SGVec3d::zeros();
+
+ if (damp_roll > 0.0)
+ _dampFactor[0] = 1.0 / pow(10.0, fabs(damp_roll));
+ if (damp_pitch > 0.0)
+ _dampFactor[1] = 1.0 / pow(10.0, fabs(damp_pitch));
+ if (damp_heading > 0.0)
+ _dampFactor[2] = 1.0 / pow(10.0, fabs(damp_heading));
+
+ _offset_m.x() = x_offset_m;
+ _offset_m.y() = y_offset_m;
+ _offset_m.z() = z_offset_m;
+ _heading_offset_deg = heading_offset_deg;
+ _pitch_offset_deg = pitch_offset_deg;
+ _roll_offset_deg = roll_offset_deg;
+ _goal_heading_offset_deg = heading_offset_deg;
+ _goal_pitch_offset_deg = pitch_offset_deg;
+ _goal_roll_offset_deg = roll_offset_deg;
+ if (fov_deg > 0) {
+ _fov_deg = fov_deg;
+ } else {
+ _fov_deg = 55;
+ }
+
+ _aspect_ratio_multiplier = aspect_ratio_multiplier;
+ _target_offset_m.x() = target_x_offset_m;
+ _target_offset_m.y() = target_y_offset_m;
+ _target_offset_m.z() = target_z_offset_m;
+ _ground_level_nearplane_m = near_m;
+ // a reasonable guess for init, so that the math doesn't blow up
+}
+
+
+// Destructor
+FGViewer::~FGViewer( void ) {
+}
+
+void
+FGViewer::init ()
+{
+}
+
+void
+FGViewer::bind ()
+{
+}
+
+void
+FGViewer::unbind ()
+{
+}
+
+void
+FGViewer::setType ( int type )
+{
+ if (type == 0)
+ _type = FG_LOOKFROM;
+ if (type == 1)
+ _type = FG_LOOKAT;
+}
+
+void
+FGViewer::setInternal ( bool internal )
+{
+ _internal = internal;
+}
+
+void
+FGViewer::setPosition (double lon_deg, double lat_deg, double alt_ft)
+{
+ _dirty = true;
+ _position = SGGeod::fromDegFt(lon_deg, lat_deg, alt_ft);
+}
+
+void
+FGViewer::setTargetPosition (double lon_deg, double lat_deg, double alt_ft)
+{
+ _dirty = true;
+ _target = SGGeod::fromDegFt(lon_deg, lat_deg, alt_ft);
+}
+
+void
+FGViewer::setRoll_deg (double roll_deg)
+{
+ _dirty = true;
+ _roll_deg = roll_deg;
+}
+
+void
+FGViewer::setPitch_deg (double pitch_deg)
+{
+ _dirty = true;
+ _pitch_deg = pitch_deg;
+}
+
+void
+FGViewer::setHeading_deg (double heading_deg)
+{
+ _dirty = true;
+ _heading_deg = heading_deg;
+}
+
+void
+FGViewer::setOrientation (double roll_deg, double pitch_deg, double heading_deg)
+{
+ _dirty = true;
+ _roll_deg = roll_deg;
+ _pitch_deg = pitch_deg;
+ _heading_deg = heading_deg;
+}
+
+void
+FGViewer::setTargetRoll_deg (double target_roll_deg)
+{
+ _dirty = true;
+ _target_roll_deg = target_roll_deg;
+}
+
+void
+FGViewer::setTargetPitch_deg (double target_pitch_deg)
+{
+ _dirty = true;
+ _target_pitch_deg = target_pitch_deg;
+}
+
+void
+FGViewer::setTargetHeading_deg (double target_heading_deg)
+{
+ _dirty = true;
+ _target_heading_deg = target_heading_deg;
+}
+
+void
+FGViewer::setTargetOrientation (double target_roll_deg, double target_pitch_deg, double target_heading_deg)
+{
+ _dirty = true;
+ _target_roll_deg = target_roll_deg;
+ _target_pitch_deg = target_pitch_deg;
+ _target_heading_deg = target_heading_deg;
+}
+
+void
+FGViewer::setXOffset_m (double x_offset_m)
+{
+ _dirty = true;
+ _offset_m.x() = x_offset_m;
+}
+
+void
+FGViewer::setYOffset_m (double y_offset_m)
+{
+ _dirty = true;
+ _offset_m.y() = y_offset_m;
+}
+
+void
+FGViewer::setZOffset_m (double z_offset_m)
+{
+ _dirty = true;
+ _offset_m.z() = z_offset_m;
+}
+
+void
+FGViewer::setTargetXOffset_m (double target_x_offset_m)
+{
+ _dirty = true;
+ _target_offset_m.x() = target_x_offset_m;
+}
+
+void
+FGViewer::setTargetYOffset_m (double target_y_offset_m)
+{
+ _dirty = true;
+ _target_offset_m.y() = target_y_offset_m;
+}
+
+void
+FGViewer::setTargetZOffset_m (double target_z_offset_m)
+{
+ _dirty = true;
+ _target_offset_m.z() = target_z_offset_m;
+}
+
+void
+FGViewer::setPositionOffsets (double x_offset_m, double y_offset_m, double z_offset_m)
+{
+ _dirty = true;
+ _offset_m.x() = x_offset_m;
+ _offset_m.y() = y_offset_m;
+ _offset_m.z() = z_offset_m;
+}
+
+void
+FGViewer::setRollOffset_deg (double roll_offset_deg)
+{
+ _dirty = true;
+ _roll_offset_deg = roll_offset_deg;
+}
+
+void
+FGViewer::setPitchOffset_deg (double pitch_offset_deg)
+{
+ _dirty = true;
+ _pitch_offset_deg = pitch_offset_deg;
+}
+
+void
+FGViewer::setHeadingOffset_deg (double heading_offset_deg)
+{
+ _dirty = true;
+ if (_at_model && (_offset_m.x() == 0.0)&&(_offset_m.z() == 0.0))
+ {
+ /* avoid optical effects (e.g. rotating sky) when "looking at" with
+ * heading offsets x==z==0 (view heading cannot change). */
+ _heading_offset_deg = 0.0;
+ }
+ else
+ _heading_offset_deg = heading_offset_deg;
+}
+
+void
+FGViewer::setGoalRollOffset_deg (double goal_roll_offset_deg)
+{
+ _dirty = true;
+ _goal_roll_offset_deg = goal_roll_offset_deg;
+}
+
+void
+FGViewer::setGoalPitchOffset_deg (double goal_pitch_offset_deg)
+{
+ _dirty = true;
+ _goal_pitch_offset_deg = goal_pitch_offset_deg;
+ if ( _goal_pitch_offset_deg < -90 ) {
+ _goal_pitch_offset_deg = -90.0;
+ }
+ if ( _goal_pitch_offset_deg > 90.0 ) {
+ _goal_pitch_offset_deg = 90.0;
+ }
+
+}
+
+void
+FGViewer::setGoalHeadingOffset_deg (double goal_heading_offset_deg)
+{
+ _dirty = true;
+ if (_at_model && (_offset_m.x() == 0.0)&&(_offset_m.z() == 0.0))
+ {
+ /* avoid optical effects (e.g. rotating sky) when "looking at" with
+ * heading offsets x==z==0 (view heading cannot change). */
+ _goal_heading_offset_deg = 0.0;
+ return;
+ }
+
+ _goal_heading_offset_deg = goal_heading_offset_deg;
+ while ( _goal_heading_offset_deg < 0.0 ) {
+ _goal_heading_offset_deg += 360;
+ }
+ while ( _goal_heading_offset_deg > 360 ) {
+ _goal_heading_offset_deg -= 360;
+ }
+}
+
+void
+FGViewer::setOrientationOffsets (double roll_offset_deg, double pitch_offset_deg, double heading_offset_deg)
+{
+ _dirty = true;
+ _roll_offset_deg = roll_offset_deg;
+ _pitch_offset_deg = pitch_offset_deg;
+ _heading_offset_deg = heading_offset_deg;
+}
+
+// recalc() is done every time one of the setters is called (making the
+// cached data "dirty") on the next "get". It calculates all the outputs
+// for viewer.
+void
+FGViewer::recalc ()
+{
+ if (_type == FG_LOOKFROM) {
+ recalcLookFrom();
+ } else {
+ recalcLookAt();
+ }
+
+ set_clean();
+}
+
+// recalculate for LookFrom view type...
+void
+FGViewer::recalcLookFrom ()
+{
+ // Update location data ...
+ if ( _from_model ) {
+ SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
+ _position = placement->getPosition();
+
+ _heading_deg = placement->getHeadingDeg();
+ _pitch_deg = placement->getPitchDeg();
+ _roll_deg = placement->getRollDeg();
+ }
+
+ double head = _heading_deg;
+ double pitch = _pitch_deg;
+ double roll = _roll_deg;
+ if ( !_from_model ) {
+ // update from our own data...
+ setDampTarget(roll, pitch, head);
+ getDampOutput(roll, pitch, head);
+ }
+
+ // The rotation rotating from the earth centerd frame to
+ // the horizontal local frame
+ SGQuatd hlOr = SGQuatd::fromLonLat(_position);
+
+ // The rotation from the horizontal local frame to the basic view orientation
+ SGQuatd hlToBody = SGQuatd::fromYawPitchRollDeg(head, pitch, roll);
+
+ // The rotation offset, don't know why heading is negative here ...
+ mViewOffsetOr
+ = SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg, _pitch_offset_deg,
+ _roll_offset_deg);
+
+ // Compute the eyepoints orientation and position
+ // wrt the earth centered frame - that is global coorinates
+ SGQuatd ec2body = hlOr*hlToBody;
+
+ // The cartesian position of the basic view coordinate
+ SGVec3d position = SGVec3d::fromGeod(_position);
+
+ // This is rotates the x-forward, y-right, z-down coordinate system the where
+ // simulation runs into the OpenGL camera system with x-right, y-up, z-back.
+ SGQuatd q(-0.5, -0.5, 0.5, 0.5);
+
+ _absolute_view_pos = position + (ec2body*q).backTransform(_offset_m);
+ mViewOrientation = ec2body*mViewOffsetOr*q;
+}
+
+void
+FGViewer::recalcLookAt ()
+{
+ // The geodetic position of our target to look at
+ if ( _at_model ) {
+ SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
+ _target = placement->getPosition();
+ _target_heading_deg = placement->getHeadingDeg();
+ _target_pitch_deg = placement->getPitchDeg();
+ _target_roll_deg = placement->getRollDeg();
+ } else {
+ // if not model then calculate our own target position...
+ setDampTarget(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
+ getDampOutput(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
+ }
+
+ SGQuatd geodTargetOr = SGQuatd::fromYawPitchRollDeg(_target_heading_deg,
+ _target_pitch_deg,
+ _target_roll_deg);
+ SGQuatd geodTargetHlOr = SGQuatd::fromLonLat(_target);
+
+
+ if ( _from_model ) {
+ SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
+ _position = placement->getPosition();
+ _heading_deg = placement->getHeadingDeg();
+ _pitch_deg = placement->getPitchDeg();
+ _roll_deg = placement->getRollDeg();
+ } else {
+ // update from our own data, just the rotation here...
+ setDampTarget(_roll_deg, _pitch_deg, _heading_deg);
+ getDampOutput(_roll_deg, _pitch_deg, _heading_deg);
+ }
+ SGQuatd geodEyeOr = SGQuatd::fromYawPitchRollDeg(_heading_deg, _pitch_deg, _roll_deg);
+ SGQuatd geodEyeHlOr = SGQuatd::fromLonLat(_position);
+
+ // the rotation offset, don't know why heading is negative here ...
+ mViewOffsetOr =
+ SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg + 180, _pitch_offset_deg,
+ _roll_offset_deg);
+
+ // Offsets to the eye position
+ SGVec3d eyeOff(-_offset_m.z(), _offset_m.x(), -_offset_m.y());
+ SGQuatd ec2eye = geodEyeHlOr*geodEyeOr;
+ SGVec3d eyeCart = SGVec3d::fromGeod(_position);
+ eyeCart += (ec2eye*mViewOffsetOr).backTransform(eyeOff);
+
+ SGVec3d atCart = SGVec3d::fromGeod(_target);
+
+ // add target offsets to at_position...
+ SGVec3d target_pos_off(-_target_offset_m.z(), _target_offset_m.x(),
+ -_target_offset_m.y());
+ target_pos_off = (geodTargetHlOr*geodTargetOr).backTransform(target_pos_off);
+ atCart += target_pos_off;
+ eyeCart += target_pos_off;
+
+ // Compute the eyepoints orientation and position
+ // wrt the earth centered frame - that is global coorinates
+ _absolute_view_pos = eyeCart;
+
+ // the view direction
+ SGVec3d dir = normalize(atCart - eyeCart);
+ // the up directon
+ SGVec3d up = ec2eye.backTransform(SGVec3d(0, 0, -1));
+ // rotate -dir to the 2-th unit vector
+ // rotate up to 1-th unit vector
+ // Note that this matches the OpenGL camera coordinate system
+ // with x-right, y-up, z-back.
+ mViewOrientation = SGQuatd::fromRotateTo(-dir, 2, up, 1);
+}
+
+void
+FGViewer::setDampTarget(double roll, double pitch, double heading)
+{
+ _dampTarget = SGVec3d(roll, pitch, heading);
+}
+
+void
+FGViewer::getDampOutput(double& roll, double& pitch, double& heading)
+{
+ roll = _dampOutput[0];
+ pitch = _dampOutput[1];
+ heading = _dampOutput[2];
+}
+
+
+void
+FGViewer::updateDampOutput(double dt)
+{
+ static FGViewer *last_view = 0;
+ if ((last_view != this) || (dt > 1.0)) {
+ _dampOutput = _dampTarget;
+ last_view = this;
+ return;
+ }
+
+ const double interval = 0.01;
+ while (dt > interval) {
+
+ for (unsigned int i=0; i<3; ++i) {
+ if (_dampFactor[i] <= 0.0) {
+ // axis is un-damped, set output to target directly
+ _dampOutput[i] = _dampTarget[i];
+ continue;
+ }
+
+ double d = _dampOutput[i] - _dampTarget[i];
+ if (d > 180.0) {
+ _dampOutput[i] -= 360.0;
+ } else if (d < -180.0) {
+ _dampOutput[i] += 360.0;
+ }
+
+ _dampOutput[i] = (_dampTarget[i] * _dampFactor[i]) +
+ (_dampOutput[i] * (1.0 - _dampFactor[i]));
+ } // of axis iteration
+
+ dt -= interval;
+ } // of dt subdivision by interval
+}
+
+double
+FGViewer::get_h_fov()
+{
+ double aspectRatio = _cameraGroup->getMasterAspectRatio();
+ switch (_scaling_type) {
+ case FG_SCALING_WIDTH: // h_fov == fov
+ return _fov_deg;
+ case FG_SCALING_MAX:
+ if (aspectRatio < 1.0) {
+ // h_fov == fov
+ return _fov_deg;
+ } else {
+ // v_fov == fov
+ return
+ atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
+ / (aspectRatio*_aspect_ratio_multiplier))
+ * SG_RADIANS_TO_DEGREES * 2;
+ }
+ default:
+ assert(false);
+ }
+ return 0.0;
+}
+
+
+
+double
+FGViewer::get_v_fov()
+{
+ double aspectRatio = _cameraGroup->getMasterAspectRatio();
+ switch (_scaling_type) {
+ case FG_SCALING_WIDTH: // h_fov == fov
+ return
+ atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
+ * (aspectRatio*_aspect_ratio_multiplier))
+ * SG_RADIANS_TO_DEGREES * 2;
+ case FG_SCALING_MAX:
+ if (aspectRatio < 1.0) {
+ // h_fov == fov
+ return
+ atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
+ * (aspectRatio*_aspect_ratio_multiplier))
+ * SG_RADIANS_TO_DEGREES * 2;
+ } else {
+ // v_fov == fov
+ return _fov_deg;
+ }
+ default:
+ assert(false);
+ }
+ return 0.0;
+}
+
+void
+FGViewer::update (double dt)
+{
+ updateDampOutput(dt);
+
+ int i;
+ int dt_ms = int(dt * 1000);
+ for ( i = 0; i < dt_ms; i++ ) {
+ if ( fabs( _goal_heading_offset_deg - _heading_offset_deg) < 1 ) {
+ setHeadingOffset_deg( _goal_heading_offset_deg );
+ break;
+ } else {
+ // move current_view.headingoffset towards
+ // current_view.goal_view_offset
+ if ( _goal_heading_offset_deg > _heading_offset_deg )
+ {
+ if ( _goal_heading_offset_deg - _heading_offset_deg < 180 ){
+ incHeadingOffset_deg( 0.5 );
+ } else {
+ incHeadingOffset_deg( -0.5 );
+ }
+ } else {
+ if ( _heading_offset_deg - _goal_heading_offset_deg < 180 ){
+ incHeadingOffset_deg( -0.5 );
+ } else {
+ incHeadingOffset_deg( 0.5 );
+ }
+ }
+ if ( _heading_offset_deg > 360 ) {
+ incHeadingOffset_deg( -360 );
+ } else if ( _heading_offset_deg < 0 ) {
+ incHeadingOffset_deg( 360 );
+ }
+ }
+ }
+
+ for ( i = 0; i < dt_ms; i++ ) {
+ if ( fabs( _goal_pitch_offset_deg - _pitch_offset_deg ) < 1 ) {
+ setPitchOffset_deg( _goal_pitch_offset_deg );
+ break;
+ } else {
+ // move current_view.pitch_offset_deg towards
+ // current_view.goal_pitch_offset
+ if ( _goal_pitch_offset_deg > _pitch_offset_deg )
+ {
+ incPitchOffset_deg( 1.0 );
+ } else {
+ incPitchOffset_deg( -1.0 );
+ }
+ if ( _pitch_offset_deg > 90 ) {
+ setPitchOffset_deg(90);
+ } else if ( _pitch_offset_deg < -90 ) {
+ setPitchOffset_deg( -90 );
+ }
+ }
+ }
+
+
+ for ( i = 0; i < dt_ms; i++ ) {
+ if ( fabs( _goal_roll_offset_deg - _roll_offset_deg ) < 1 ) {
+ setRollOffset_deg( _goal_roll_offset_deg );
+ break;
+ } else {
+ // move current_view.roll_offset_deg towards
+ // current_view.goal_roll_offset
+ if ( _goal_roll_offset_deg > _roll_offset_deg )
+ {
+ incRollOffset_deg( 1.0 );
+ } else {
+ incRollOffset_deg( -1.0 );
+ }
+ if ( _roll_offset_deg > 90 ) {
+ setRollOffset_deg(90);
+ } else if ( _roll_offset_deg < -90 ) {
+ setRollOffset_deg( -90 );
+ }
+ }
+ }
+ recalc();
+ if( fgGetBool( "/sim/rendering/draw-otw", true ) ) {
+ _cameraGroup->update(toOsg(_absolute_view_pos), toOsg(mViewOrientation));
+ _cameraGroup->setCameraParameters(get_v_fov(), get_aspect_ratio());
+ }
+}
+
+double FGViewer::get_aspect_ratio() const
+{
+ return _cameraGroup->getMasterAspectRatio();
+}
--- /dev/null
+// viewer.hxx -- class for managing a viewer in the flightgear world.
+//
+// Written by Curtis Olson, started August 1997.
+// overhaul started October 2000.
+// partially rewritten by Jim Wilson jim@kelcomaine.com using interface
+// by David Megginson March 2002
+//
+// Copyright (C) 1997 - 2000 Curtis L. Olson - http://www.flightgear.org/~curt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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 GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// $Id$
+
+
+#ifndef _VIEWER_HXX
+#define _VIEWER_HXX
+
+namespace flightgear
+{
+class CameraGroup;
+}
+
+#include <osg/ref_ptr>
+
+#include <simgear/compiler.h>
+#include <simgear/constants.h>
+#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/math/SGMath.hxx>
+
+#define FG_FOV_MIN 0.1
+#define FG_FOV_MAX 179.9
+
+enum fgViewType {
+ FG_LOOKFROM = 0,
+ FG_LOOKAT = 1
+};
+
+// Define a structure containing view information
+class FGViewer : public SGSubsystem {
+
+public:
+
+ enum fgScalingType { // nominal Field Of View actually applies to ...
+ FG_SCALING_WIDTH, // window width
+ FG_SCALING_MAX // max(width, height)
+ // FG_SCALING_G_MEAN, // geometric_mean(width, height)
+ // FG_SCALING_INDEPENDENT // whole screen
+ };
+
+ // Constructor
+ FGViewer( fgViewType Type, bool from_model, int from_model_index,
+ bool at_model, int at_model_index,
+ double damp_roll, double damp_pitch, double damp_heading,
+ double x_offset_m, double y_offset_m, double z_offset_m,
+ double heading_offset_deg, double pitch_offset_deg,
+ double roll_offset_deg,
+ double fov_deg, double aspect_ratio_multiplier,
+ double target_x_offset_m, double target_y_offset_m,
+ double target_z_offset_m, double near_m, bool internal );
+
+ // Destructor
+ virtual ~FGViewer( void );
+
+ //////////////////////////////////////////////////////////////////////
+ // Part 1: standard SGSubsystem implementation.
+ //////////////////////////////////////////////////////////////////////
+
+ virtual void init ();
+ virtual void bind ();
+ virtual void unbind ();
+ void update (double dt);
+
+
+ //////////////////////////////////////////////////////////////////////
+ // Part 2: user settings.
+ //////////////////////////////////////////////////////////////////////
+
+ virtual fgViewType getType() const { return _type; }
+ virtual void setType( int type );
+
+ virtual bool getInternal() const { return _internal; }
+ virtual void setInternal( bool internal );
+
+ // Reference geodetic position of view from position...
+ // These are the actual aircraft position (pilot in
+ // pilot view, model in model view).
+ // FIXME: the model view position (ie target positions)
+ // should be in the model class.
+ virtual void setPosition (double lon_deg, double lat_deg, double alt_ft);
+ const SGGeod& getPosition() const { return _position; }
+
+ // Reference geodetic target position...
+ virtual void setTargetPosition (double lon_deg, double lat_deg, double alt_ft);
+ const SGGeod& getTargetPosition() const { return _target; }
+
+
+
+ // Position offsets from reference
+ // These offsets position they "eye" in the scene according to a given
+ // location. For example in pilot view they are used to position the
+ // head inside the aircraft.
+ // Note that in pilot view these are applied "before" the orientation
+ // rotations (see below) so that the orientation rotations have the
+ // effect of the pilot staying in his seat and "looking out" in
+ // different directions.
+ // In chase view these are applied "after" the application of the
+ // orientation rotations listed below. This has the effect of the
+ // eye moving around and "looking at" the object (model) from
+ // different angles.
+ virtual SGVec3d getOffset_m () const { return _offset_m; }
+ virtual double getXOffset_m () const { return _offset_m.x(); }
+ virtual double getYOffset_m () const { return _offset_m.y(); }
+ virtual double getZOffset_m () const { return _offset_m.z(); }
+ virtual double getTargetXOffset_m () const { return _target_offset_m.x(); }
+ virtual double getTargetYOffset_m () const { return _target_offset_m.y(); }
+ virtual double getTargetZOffset_m () const { return _target_offset_m.z(); }
+ virtual void setXOffset_m (double x_offset_m);
+ virtual void setYOffset_m (double y_offset_m);
+ virtual void setZOffset_m (double z_offset_m);
+ virtual void setTargetXOffset_m (double x_offset_m);
+ virtual void setTargetYOffset_m (double y_offset_m);
+ virtual void setTargetZOffset_m (double z_offset_m);
+ virtual void setPositionOffsets (double x_offset_m,
+ double y_offset_m,
+ double z_offset_m);
+
+
+
+
+ // Reference orientation rotations...
+ // These are rotations that represent the plane attitude effect on
+ // the view (in Pilot view). IE The view frustrum rotates as the plane
+ // turns, pitches, and rolls.
+ // In model view (lookat/chaseview) these end up changing the angle that
+ // the eye is looking at the ojbect (ie the model).
+ // FIXME: the FGModel class should have its own version of these so that
+ // it can generate it's own model rotations.
+ virtual double getRoll_deg () const { return _roll_deg; }
+ virtual double getPitch_deg () const {return _pitch_deg; }
+ virtual double getHeading_deg () const {return _heading_deg; }
+ virtual void setRoll_deg (double roll_deg);
+ virtual void setPitch_deg (double pitch_deg);
+ virtual void setHeading_deg (double heading_deg);
+ virtual void setOrientation (double roll_deg, double pitch_deg, double heading_deg);
+ virtual double getTargetRoll_deg () const { return _target_roll_deg; }
+ virtual double getTargetPitch_deg () const {return _target_pitch_deg; }
+ virtual double getTargetHeading_deg () const {return _target_heading_deg; }
+ virtual void setTargetRoll_deg (double roll_deg);
+ virtual void setTargetPitch_deg (double pitch_deg);
+ virtual void setTargetHeading_deg (double heading_deg);
+ virtual void setTargetOrientation (double roll_deg, double pitch_deg, double heading_deg);
+
+
+
+
+ // Orientation offsets rotations from reference orientation.
+ // Goal settings are for smooth transition from prior
+ // offset when changing view direction.
+ // These offsets are in ADDITION to the orientation rotations listed
+ // above.
+ // In pilot view they are applied after the position offsets in order to
+ // give the effect of the pilot looking around.
+ // In lookat view they are applied before the position offsets so that
+ // the effect is the eye moving around looking at the object (ie the model)
+ // from different angles.
+ virtual double getRollOffset_deg () const { return _roll_offset_deg; }
+ virtual double getPitchOffset_deg () const { return _pitch_offset_deg; }
+ virtual double getHeadingOffset_deg () const { return _heading_offset_deg; }
+ virtual double getGoalRollOffset_deg () const { return _goal_roll_offset_deg; }
+ virtual double getGoalPitchOffset_deg () const { return _goal_pitch_offset_deg; }
+ virtual double getGoalHeadingOffset_deg () const {return _goal_heading_offset_deg; }
+ virtual void setRollOffset_deg (double roll_offset_deg);
+ virtual void setPitchOffset_deg (double pitch_offset_deg);
+ virtual void setHeadingOffset_deg (double heading_offset_deg);
+ virtual void setGoalRollOffset_deg (double goal_roll_offset_deg);
+ virtual void setGoalPitchOffset_deg (double goal_pitch_offset_deg);
+ virtual void setGoalHeadingOffset_deg (double goal_heading_offset_deg);
+ virtual void setOrientationOffsets (double roll_offset_deg,
+ double heading_offset_deg,
+ double pitch_offset_deg);
+
+
+
+ //////////////////////////////////////////////////////////////////////
+ // Part 3: output vectors and matrices in FlightGear coordinates.
+ //////////////////////////////////////////////////////////////////////
+
+ // Vectors and positions...
+
+ const SGVec3d& get_view_pos() { if ( _dirty ) { recalc(); } return _absolute_view_pos; }
+ const SGVec3d& getViewPosition() { if ( _dirty ) { recalc(); } return _absolute_view_pos; }
+ const SGQuatd& getViewOrientation() { if ( _dirty ) { recalc(); } return mViewOrientation; }
+ const SGQuatd& getViewOrientationOffset() { if ( _dirty ) { recalc(); } return mViewOffsetOr; }
+
+ //////////////////////////////////////////////////////////////////////
+ // Part 4: View and frustrum data setters and getters
+ //////////////////////////////////////////////////////////////////////
+
+ virtual void set_fov( double fov_deg ) {
+ _fov_deg = fov_deg;
+ }
+ virtual double get_fov() const { return _fov_deg; }
+ virtual double get_h_fov(); // Get horizontal fov, in degrees.
+ virtual double get_v_fov(); // Get vertical fov, in degrees.
+
+ virtual double get_aspect_ratio() const;
+
+ virtual void set_aspect_ratio_multiplier( double m ) {
+ _aspect_ratio_multiplier = m;
+ }
+ virtual double get_aspect_ratio_multiplier() const {
+ return _aspect_ratio_multiplier;
+ }
+
+ virtual double getNear_m () const { return _ground_level_nearplane_m; }
+ inline void setNear_m (double near_m) {
+ _ground_level_nearplane_m = near_m;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // Part 5: misc setters and getters
+ //////////////////////////////////////////////////////////////////////
+
+ inline void set_dirty() { _dirty = true; }
+ inline void set_clean() { _dirty = false; }
+
+private:
+
+ //////////////////////////////////////////////////////////////////
+ // private data //
+ //////////////////////////////////////////////////////////////////
+
+ // flag forcing a recalc of derived view parameters
+ bool _dirty;
+
+ SGQuatd mViewOrientation;
+ SGQuatd mViewOffsetOr;
+ SGVec3d _absolute_view_pos;
+
+ SGGeod _position;
+ SGGeod _target;
+
+ double _roll_deg;
+ double _pitch_deg;
+ double _heading_deg;
+ double _target_roll_deg;
+ double _target_pitch_deg;
+ double _target_heading_deg;
+
+ SGVec3d _dampTarget; ///< current target value we are damping towards
+ SGVec3d _dampOutput; ///< current output of damping filter
+ SGVec3d _dampFactor; ///< weighting of the damping filter
+
+ // Position offsets from FDM origin. The X axis is positive
+ // out the tail, Y is out the right wing, and Z is positive up.
+ // distance in meters
+ SGVec3d _offset_m;
+
+ // Target offsets from FDM origin (for "lookat" targets) The X
+ // axis is positive out the tail, Y is out the right wing, and Z
+ // is positive up. distance in meters
+ SGVec3d _target_offset_m;
+
+
+ // orientation offsets from reference (_goal* are for smoothed transitions)
+ double _roll_offset_deg;
+ double _pitch_offset_deg;
+ double _heading_offset_deg;
+ double _goal_roll_offset_deg;
+ double _goal_pitch_offset_deg;
+ double _goal_heading_offset_deg;
+
+ // used to set nearplane when at ground level for this view
+ double _ground_level_nearplane_m;
+
+ fgViewType _type;
+ fgScalingType _scaling_type;
+
+ // internal view (e.g. cockpit) flag
+ bool _internal;
+
+ // view is looking from a model
+ bool _from_model;
+ int _from_model_index; // number of model (for multi model)
+
+ // view is looking at a model
+ bool _at_model;
+ int _at_model_index; // number of model (for multi model)
+
+ // the nominal field of view (angle, in degrees)
+ double _fov_deg;
+
+ // default = 1.0, this value is user configurable and is
+ // multiplied into the aspect_ratio to get the actual vertical fov
+ double _aspect_ratio_multiplier;
+
+ // camera group controled by this view
+ osg::ref_ptr<flightgear::CameraGroup> _cameraGroup;
+ //////////////////////////////////////////////////////////////////
+ // private functions //
+ //////////////////////////////////////////////////////////////////
+
+ void recalc ();
+ void recalcLookFrom();
+ void recalcLookAt();
+
+ void setDampTarget(double h, double p, double r);
+ void getDampOutput(double& roll, double& pitch, double& heading);
+
+ void updateDampOutput(double dt);
+
+ // add to _heading_offset_deg
+ inline void incHeadingOffset_deg( double amt ) {
+ set_dirty();
+ _heading_offset_deg += amt;
+ }
+
+ // add to _pitch_offset_deg
+ inline void incPitchOffset_deg( double amt ) {
+ set_dirty();
+ _pitch_offset_deg += amt;
+ }
+
+ // add to _roll_offset_deg
+ inline void incRollOffset_deg( double amt ) {
+ set_dirty();
+ _roll_offset_deg += amt;
+ }
+
+};
+
+
+#endif // _VIEWER_HXX
--- /dev/null
+// viewmgr.cxx -- class for managing all the views in the flightgear world.
+//
+// Written by Curtis Olson, started October 2000.
+// partially rewritten by Jim Wilson March 2002
+//
+// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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 GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// $Id$
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "viewmgr.hxx"
+
+#include <string.h> // strcmp
+
+#include <simgear/compiler.h>
+#include <simgear/sound/soundmgr_openal.hxx>
+#include <Model/acmodel.hxx>
+#include <Main/fg_props.hxx>
+#include "viewer.hxx"
+
+// Constructor
+FGViewMgr::FGViewMgr( void ) :
+ axis_long(0),
+ axis_lat(0),
+ inited(false),
+ view_number(fgGetNode("/sim/current-view/view-number", true)),
+ config_list(fgGetNode("/sim", true)->getChildren("view")),
+ abs_viewer_position(SGVec3d::zeros()),
+ current(0),
+ current_view_orientation(SGQuatd::zeros()),
+ current_view_or_offset(SGQuatd::zeros()),
+ smgr(globals->get_soundmgr())
+{
+}
+
+// Destructor
+FGViewMgr::~FGViewMgr( void ) {
+}
+
+void
+FGViewMgr::init ()
+{
+ if (inited) {
+ SG_LOG(SG_VIEW, SG_WARN, "duplicate init of view manager");
+ return;
+ }
+
+ inited = true;
+
+ double aspect_ratio_multiplier
+ = fgGetDouble("/sim/current-view/aspect-ratio-multiplier");
+
+ for (unsigned int i = 0; i < config_list.size(); i++) {
+ SGPropertyNode *n = config_list[i];
+
+ // find out if this is an internal view (e.g. in cockpit, low near plane)
+ bool internal = n->getBoolValue("internal", false);
+
+ // FIXME:
+ // this is assumed to be an aircraft model...we will need to read
+ // model-from-type as well.
+
+ // find out if this is a model we are looking from...
+ bool from_model = n->getBoolValue("config/from-model");
+ int from_model_index = n->getIntValue("config/from-model-idx");
+
+ double x_offset_m = n->getDoubleValue("config/x-offset-m");
+ double y_offset_m = n->getDoubleValue("config/y-offset-m");
+ double z_offset_m = n->getDoubleValue("config/z-offset-m");
+
+ double heading_offset_deg = n->getDoubleValue("config/heading-offset-deg");
+ n->setDoubleValue("config/heading-offset-deg", heading_offset_deg);
+ double pitch_offset_deg = n->getDoubleValue("config/pitch-offset-deg");
+ n->setDoubleValue("config/pitch-offset-deg", pitch_offset_deg);
+ double roll_offset_deg = n->getDoubleValue("config/roll-offset-deg");
+ n->setDoubleValue("config/roll-offset-deg", roll_offset_deg);
+
+ double fov_deg = n->getDoubleValue("config/default-field-of-view-deg");
+ double near_m = n->getDoubleValue("config/ground-level-nearplane-m");
+
+ // supporting two types "lookat" = 1 and "lookfrom" = 0
+ const char *type = n->getStringValue("type");
+ if (!strcmp(type, "lookat")) {
+
+ bool at_model = n->getBoolValue("config/at-model");
+ int at_model_index = n->getIntValue("config/at-model-idx");
+
+ double damp_roll = n->getDoubleValue("config/at-model-roll-damping");
+ double damp_pitch = n->getDoubleValue("config/at-model-pitch-damping");
+ double damp_heading = n->getDoubleValue("config/at-model-heading-damping");
+
+ double target_x_offset_m = n->getDoubleValue("config/target-x-offset-m");
+ double target_y_offset_m = n->getDoubleValue("config/target-y-offset-m");
+ double target_z_offset_m = n->getDoubleValue("config/target-z-offset-m");
+
+ add_view(new FGViewer ( FG_LOOKAT, from_model, from_model_index,
+ at_model, at_model_index,
+ damp_roll, damp_pitch, damp_heading,
+ x_offset_m, y_offset_m,z_offset_m,
+ heading_offset_deg, pitch_offset_deg,
+ roll_offset_deg, fov_deg, aspect_ratio_multiplier,
+ target_x_offset_m, target_y_offset_m,
+ target_z_offset_m, near_m, internal ));
+ } else {
+ add_view(new FGViewer ( FG_LOOKFROM, from_model, from_model_index,
+ false, 0, 0.0, 0.0, 0.0,
+ x_offset_m, y_offset_m, z_offset_m,
+ heading_offset_deg, pitch_offset_deg,
+ roll_offset_deg, fov_deg, aspect_ratio_multiplier,
+ 0, 0, 0, near_m, internal ));
+ }
+ }
+
+ copyToCurrent();
+ do_bind();
+}
+
+void
+FGViewMgr::reinit ()
+{
+ // reset offsets and fov to configuration defaults
+ for (unsigned int i = 0; i < config_list.size(); i++) {
+ SGPropertyNode *n = config_list[i];
+ setView(i);
+
+ fgSetDouble("/sim/current-view/x-offset-m",
+ n->getDoubleValue("config/x-offset-m"));
+ fgSetDouble("/sim/current-view/y-offset-m",
+ n->getDoubleValue("config/y-offset-m"));
+ fgSetDouble("/sim/current-view/z-offset-m",
+ n->getDoubleValue("config/z-offset-m"));
+ fgSetDouble("/sim/current-view/pitch-offset-deg",
+ n->getDoubleValue("config/pitch-offset-deg"));
+ fgSetDouble("/sim/current-view/heading-offset-deg",
+ n->getDoubleValue("config/heading-offset-deg"));
+ fgSetDouble("/sim/current-view/roll-offset-deg",
+ n->getDoubleValue("config/roll-offset-deg"));
+
+ double fov_deg = n->getDoubleValue("config/default-field-of-view-deg");
+ if (fov_deg < 10.0)
+ fov_deg = 55.0;
+ fgSetDouble("/sim/current-view/field-of-view", fov_deg);
+
+ // target offsets for lookat mode only...
+ fgSetDouble("/sim/current-view/target-x-offset-m",
+ n->getDoubleValue("config/target-x-offset-m"));
+ fgSetDouble("/sim/current-view/target-y-offset-m",
+ n->getDoubleValue("config/target-y-offset-m"));
+ fgSetDouble("/sim/current-view/target-z-offset-m",
+ n->getDoubleValue("config/target-z-offset-m"));
+ }
+ setView(0);
+}
+
+typedef double (FGViewMgr::*double_getter)() const;
+
+void
+FGViewMgr::bind()
+{
+ // view-manager code was designed to init before bind, so
+ // this is a no-op; init() calls the real bind() impl below
+}
+
+void
+FGViewMgr::do_bind()
+{
+ // these are bound to the current view properties
+ _tiedProperties.setRoot(fgGetNode("/sim/current-view", true));
+ _tiedProperties.Tie("heading-offset-deg", this,
+ &FGViewMgr::getViewHeadingOffset_deg,
+ &FGViewMgr::setViewHeadingOffset_deg);
+ fgSetArchivable("/sim/current-view/heading-offset-deg");
+ _tiedProperties.Tie("goal-heading-offset-deg", this,
+ &FGViewMgr::getViewGoalHeadingOffset_deg,
+ &FGViewMgr::setViewGoalHeadingOffset_deg);
+ fgSetArchivable("/sim/current-view/goal-heading-offset-deg");
+ _tiedProperties.Tie("pitch-offset-deg", this,
+ &FGViewMgr::getViewPitchOffset_deg,
+ &FGViewMgr::setViewPitchOffset_deg);
+ fgSetArchivable("/sim/current-view/pitch-offset-deg");
+ _tiedProperties.Tie("goal-pitch-offset-deg", this,
+ &FGViewMgr::getGoalViewPitchOffset_deg,
+ &FGViewMgr::setGoalViewPitchOffset_deg);
+ fgSetArchivable("/sim/current-view/goal-pitch-offset-deg");
+ _tiedProperties.Tie("roll-offset-deg", this,
+ &FGViewMgr::getViewRollOffset_deg,
+ &FGViewMgr::setViewRollOffset_deg);
+ fgSetArchivable("/sim/current-view/roll-offset-deg");
+ _tiedProperties.Tie("goal-roll-offset-deg", this,
+ &FGViewMgr::getGoalViewRollOffset_deg,
+ &FGViewMgr::setGoalViewRollOffset_deg);
+ fgSetArchivable("/sim/current-view/goal-roll-offset-deg");
+
+ _tiedProperties.Tie("view-number", this,
+ &FGViewMgr::getView, &FGViewMgr::setView);
+ fgSetArchivable("/sim/current-view/view-number", false);
+
+ _tiedProperties.Tie("axes/long", this,
+ (double_getter)0, &FGViewMgr::setViewAxisLong);
+ fgSetArchivable("/sim/current-view/axes/long");
+
+ _tiedProperties.Tie("axes/lat", this,
+ (double_getter)0, &FGViewMgr::setViewAxisLat);
+ fgSetArchivable("/sim/current-view/axes/lat");
+
+ _tiedProperties.Tie("field-of-view", this,
+ &FGViewMgr::getFOV_deg, &FGViewMgr::setFOV_deg);
+ fgSetArchivable("/sim/current-view/field-of-view");
+
+ _tiedProperties.Tie("aspect-ratio-multiplier", this,
+ &FGViewMgr::getARM_deg, &FGViewMgr::setARM_deg);
+ fgSetArchivable("/sim/current-view/field-of-view");
+
+ _tiedProperties.Tie("ground-level-nearplane-m", this,
+ &FGViewMgr::getNear_m, &FGViewMgr::setNear_m);
+ fgSetArchivable("/sim/current-view/ground-level-nearplane-m");
+
+ SGPropertyNode *n = fgGetNode("/sim/current-view", true);
+ _tiedProperties.Tie(n->getNode("viewer-x-m", true),SGRawValuePointer<double>(&abs_viewer_position[0]));
+ _tiedProperties.Tie(n->getNode("viewer-y-m", true),SGRawValuePointer<double>(&abs_viewer_position[1]));
+ _tiedProperties.Tie(n->getNode("viewer-z-m", true),SGRawValuePointer<double>(&abs_viewer_position[2]));
+
+ _tiedProperties.Tie("debug/orientation-w", this,
+ &FGViewMgr::getCurrentViewOrientation_w);
+ _tiedProperties.Tie("debug/orientation-x", this,
+ &FGViewMgr::getCurrentViewOrientation_x);
+ _tiedProperties.Tie("debug/orientation-y", this,
+ &FGViewMgr::getCurrentViewOrientation_y);
+ _tiedProperties.Tie("debug/orientation-z", this,
+ &FGViewMgr::getCurrentViewOrientation_z);
+
+ _tiedProperties.Tie("debug/orientation_offset-w", this,
+ &FGViewMgr::getCurrentViewOrOffset_w);
+ _tiedProperties.Tie("debug/orientation_offset-x", this,
+ &FGViewMgr::getCurrentViewOrOffset_x);
+ _tiedProperties.Tie("debug/orientation_offset-y", this,
+ &FGViewMgr::getCurrentViewOrOffset_y);
+ _tiedProperties.Tie("debug/orientation_offset-z", this,
+ &FGViewMgr::getCurrentViewOrOffset_z);
+
+ _tiedProperties.Tie("debug/frame-w", this,
+ &FGViewMgr::getCurrentViewFrame_w);
+ _tiedProperties.Tie("debug/frame-x", this,
+ &FGViewMgr::getCurrentViewFrame_x);
+ _tiedProperties.Tie("debug/frame-y", this,
+ &FGViewMgr::getCurrentViewFrame_y);
+ _tiedProperties.Tie("debug/frame-z", this,
+ &FGViewMgr::getCurrentViewFrame_z);
+}
+
+void
+FGViewMgr::unbind ()
+{
+ _tiedProperties.Untie();
+}
+
+void
+FGViewMgr::update (double dt)
+{
+ FGViewer *loop_view = (FGViewer *)get_current_view();
+ if (loop_view == 0) return;
+
+ SGPropertyNode *n = config_list[current];
+ double lon_deg, lat_deg, alt_ft, roll_deg, pitch_deg, heading_deg;
+
+ // Set up view location and orientation
+
+ if (!n->getBoolValue("config/from-model")) {
+ lon_deg = fgGetDouble(n->getStringValue("config/eye-lon-deg-path"));
+ lat_deg = fgGetDouble(n->getStringValue("config/eye-lat-deg-path"));
+ alt_ft = fgGetDouble(n->getStringValue("config/eye-alt-ft-path"));
+ roll_deg = fgGetDouble(n->getStringValue("config/eye-roll-deg-path"));
+ pitch_deg = fgGetDouble(n->getStringValue("config/eye-pitch-deg-path"));
+ heading_deg = fgGetDouble(n->getStringValue("config/eye-heading-deg-path"));
+
+ loop_view->setPosition(lon_deg, lat_deg, alt_ft);
+ loop_view->setOrientation(roll_deg, pitch_deg, heading_deg);
+ } else {
+ // force recalc in viewer
+ loop_view->set_dirty();
+ }
+
+ // if lookat (type 1) then get target data...
+ if (loop_view->getType() == FG_LOOKAT) {
+ if (!n->getBoolValue("config/from-model")) {
+ lon_deg = fgGetDouble(n->getStringValue("config/target-lon-deg-path"));
+ lat_deg = fgGetDouble(n->getStringValue("config/target-lat-deg-path"));
+ alt_ft = fgGetDouble(n->getStringValue("config/target-alt-ft-path"));
+ roll_deg = fgGetDouble(n->getStringValue("config/target-roll-deg-path"));
+ pitch_deg = fgGetDouble(n->getStringValue("config/target-pitch-deg-path"));
+ heading_deg = fgGetDouble(n->getStringValue("config/target-heading-deg-path"));
+
+ loop_view->setTargetPosition(lon_deg, lat_deg, alt_ft);
+ loop_view->setTargetOrientation(roll_deg, pitch_deg, heading_deg);
+ } else {
+ loop_view->set_dirty();
+ }
+ }
+
+ setViewXOffset_m(fgGetDouble("/sim/current-view/x-offset-m"));
+ setViewYOffset_m(fgGetDouble("/sim/current-view/y-offset-m"));
+ setViewZOffset_m(fgGetDouble("/sim/current-view/z-offset-m"));
+
+ setViewTargetXOffset_m(fgGetDouble("/sim/current-view/target-x-offset-m"));
+ setViewTargetYOffset_m(fgGetDouble("/sim/current-view/target-y-offset-m"));
+ setViewTargetZOffset_m(fgGetDouble("/sim/current-view/target-z-offset-m"));
+
+ current_view_orientation = loop_view->getViewOrientation();
+ current_view_or_offset = loop_view->getViewOrientationOffset();
+
+ // Update the current view
+ do_axes();
+ loop_view->update(dt);
+ abs_viewer_position = loop_view->getViewPosition();
+
+ // update audio listener values
+ // set the viewer position in Cartesian coordinates in meters
+ smgr->set_position( abs_viewer_position, loop_view->getPosition() );
+ smgr->set_orientation( current_view_orientation );
+
+ // get the model velocity
+ SGVec3d velocity = SGVec3d::zeros();
+ if ( !stationary() ) {
+ velocity = globals->get_aircraft_model()->getVelocity();
+ }
+ smgr->set_velocity( velocity );
+}
+
+void
+FGViewMgr::copyToCurrent()
+{
+ if (!inited) {
+ return;
+ }
+
+ SGPropertyNode *n = config_list[current];
+ fgSetString("/sim/current-view/name", n->getStringValue("name"));
+ fgSetString("/sim/current-view/type", n->getStringValue("type"));
+
+ // copy certain view config data for default values
+ fgSetDouble("/sim/current-view/config/heading-offset-deg",
+ n->getDoubleValue("config/default-heading-offset-deg"));
+ fgSetDouble("/sim/current-view/config/pitch-offset-deg",
+ n->getDoubleValue("config/pitch-offset-deg"));
+ fgSetDouble("/sim/current-view/config/roll-offset-deg",
+ n->getDoubleValue("config/roll-offset-deg"));
+ fgSetDouble("/sim/current-view/config/default-field-of-view-deg",
+ n->getDoubleValue("config/default-field-of-view-deg"));
+ fgSetBool("/sim/current-view/config/from-model",
+ n->getBoolValue("config/from-model"));
+
+ // copy view data
+ fgSetDouble("/sim/current-view/x-offset-m", getViewXOffset_m());
+ fgSetDouble("/sim/current-view/y-offset-m", getViewYOffset_m());
+ fgSetDouble("/sim/current-view/z-offset-m", getViewZOffset_m());
+
+ fgSetDouble("/sim/current-view/goal-heading-offset-deg",
+ get_current_view()->getGoalHeadingOffset_deg());
+ fgSetDouble("/sim/current-view/goal-pitch-offset-deg",
+ get_current_view()->getGoalPitchOffset_deg());
+ fgSetDouble("/sim/current-view/goal-roll-offset-deg",
+ get_current_view()->getRollOffset_deg());
+ fgSetDouble("/sim/current-view/heading-offset-deg",
+ get_current_view()->getHeadingOffset_deg());
+ fgSetDouble("/sim/current-view/pitch-offset-deg",
+ get_current_view()->getPitchOffset_deg());
+ fgSetDouble("/sim/current-view/roll-offset-deg",
+ get_current_view()->getRollOffset_deg());
+ fgSetDouble("/sim/current-view/target-x-offset-m",
+ get_current_view()->getTargetXOffset_m());
+ fgSetDouble("/sim/current-view/target-y-offset-m",
+ get_current_view()->getTargetYOffset_m());
+ fgSetDouble("/sim/current-view/target-z-offset-m",
+ get_current_view()->getTargetZOffset_m());
+ fgSetBool("/sim/current-view/internal",
+ get_current_view()->getInternal());
+}
+
+void FGViewMgr::clear()
+{
+ views.clear();
+}
+
+FGViewer*
+FGViewMgr::get_current_view()
+{
+ if ( current < (int)views.size() ) {
+ return views[current];
+ } else {
+ return NULL;
+ }
+}
+
+const FGViewer*
+FGViewMgr::get_current_view() const
+{
+ if ( current < (int)views.size() ) {
+ return views[current];
+ } else {
+ return NULL;
+ }
+}
+
+
+FGViewer*
+FGViewMgr::get_view( int i )
+{
+ if ( i < 0 ) { i = 0; }
+ if ( i >= (int)views.size() ) { i = views.size() - 1; }
+ return views[i];
+}
+
+const FGViewer*
+FGViewMgr::get_view( int i ) const
+{
+ if ( i < 0 ) { i = 0; }
+ if ( i >= (int)views.size() ) { i = views.size() - 1; }
+ return views[i];
+}
+
+FGViewer*
+FGViewMgr::next_view()
+{
+ setView((current+1 < (int)views.size()) ? (current + 1) : 0);
+ view_number->fireValueChanged();
+ return views[current];
+}
+
+FGViewer*
+FGViewMgr::prev_view()
+{
+ setView((0 < current) ? (current - 1) : (views.size() - 1));
+ view_number->fireValueChanged();
+ return views[current];
+}
+
+void
+FGViewMgr::add_view( FGViewer * v )
+{
+ views.push_back(v);
+ v->init();
+}
+
+double
+FGViewMgr::getViewHeadingOffset_deg () const
+{
+ const FGViewer * view = get_current_view();
+ return (view == 0 ? 0 : view->getHeadingOffset_deg());
+}
+
+void
+FGViewMgr::setViewHeadingOffset_deg (double offset)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0) {
+ view->setGoalHeadingOffset_deg(offset);
+ view->setHeadingOffset_deg(offset);
+ }
+}
+
+double
+FGViewMgr::getViewGoalHeadingOffset_deg () const
+{
+ const FGViewer * view = get_current_view();
+ return (view == 0 ? 0 : view->getGoalHeadingOffset_deg());
+}
+
+void
+FGViewMgr::setViewGoalHeadingOffset_deg (double offset)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0)
+ view->setGoalHeadingOffset_deg(offset);
+}
+
+double
+FGViewMgr::getViewPitchOffset_deg () const
+{
+ const FGViewer * view = get_current_view();
+ return (view == 0 ? 0 : view->getPitchOffset_deg());
+}
+
+void
+FGViewMgr::setViewPitchOffset_deg (double tilt)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0) {
+ view->setGoalPitchOffset_deg(tilt);
+ view->setPitchOffset_deg(tilt);
+ }
+}
+
+double
+FGViewMgr::getGoalViewPitchOffset_deg () const
+{
+ const FGViewer * view = get_current_view();
+ return (view == 0 ? 0 : view->getGoalPitchOffset_deg());
+}
+
+void
+FGViewMgr::setGoalViewPitchOffset_deg (double tilt)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0)
+ view->setGoalPitchOffset_deg(tilt);
+}
+
+double
+FGViewMgr::getViewRollOffset_deg () const
+{
+ const FGViewer * view = get_current_view();
+ return (view == 0 ? 0 : view->getRollOffset_deg());
+}
+
+void
+FGViewMgr::setViewRollOffset_deg (double tilt)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0) {
+ view->setGoalRollOffset_deg(tilt);
+ view->setRollOffset_deg(tilt);
+ }
+}
+
+double
+FGViewMgr::getGoalViewRollOffset_deg () const
+{
+ const FGViewer * view = get_current_view();
+ return (view == 0 ? 0 : view->getGoalRollOffset_deg());
+}
+
+void
+FGViewMgr::setGoalViewRollOffset_deg (double tilt)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0)
+ view->setGoalRollOffset_deg(tilt);
+}
+
+double
+FGViewMgr::getViewXOffset_m () const
+{
+ const FGViewer * view = get_current_view();
+ if (view != 0) {
+ return ((FGViewer *)view)->getXOffset_m();
+ } else {
+ return 0;
+ }
+}
+
+void
+FGViewMgr::setViewXOffset_m (double x)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0) {
+ view->setXOffset_m(x);
+ }
+}
+
+double
+FGViewMgr::getViewYOffset_m () const
+{
+ const FGViewer * view = get_current_view();
+ if (view != 0) {
+ return ((FGViewer *)view)->getYOffset_m();
+ } else {
+ return 0;
+ }
+}
+
+void
+FGViewMgr::setViewYOffset_m (double y)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0) {
+ view->setYOffset_m(y);
+ }
+}
+
+double
+FGViewMgr::getViewZOffset_m () const
+{
+ const FGViewer * view = get_current_view();
+ if (view != 0) {
+ return ((FGViewer *)view)->getZOffset_m();
+ } else {
+ return 0;
+ }
+}
+
+void
+FGViewMgr::setViewZOffset_m (double z)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0) {
+ view->setZOffset_m(z);
+ }
+}
+
+bool
+FGViewMgr::stationary () const
+{
+ const FGViewer * view = get_current_view();
+ if (view != 0) {
+ if (((FGViewer *)view)->getXOffset_m() == 0.0 &&
+ ((FGViewer *)view)->getYOffset_m() == 0.0 &&
+ ((FGViewer *)view)->getZOffset_m() == 0.0)
+ return true;
+ }
+
+ return false;
+}
+
+double
+FGViewMgr::getViewTargetXOffset_m () const
+{
+ const FGViewer * view = get_current_view();
+ if (view != 0) {
+ return ((FGViewer *)view)->getTargetXOffset_m();
+ } else {
+ return 0;
+ }
+}
+
+void
+FGViewMgr::setViewTargetXOffset_m (double x)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0) {
+ view->setTargetXOffset_m(x);
+ }
+}
+
+double
+FGViewMgr::getViewTargetYOffset_m () const
+{
+ const FGViewer * view = get_current_view();
+ if (view != 0) {
+ return ((FGViewer *)view)->getTargetYOffset_m();
+ } else {
+ return 0;
+ }
+}
+
+void
+FGViewMgr::setViewTargetYOffset_m (double y)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0) {
+ view->setTargetYOffset_m(y);
+ }
+}
+
+double
+FGViewMgr::getViewTargetZOffset_m () const
+{
+ const FGViewer * view = get_current_view();
+ if (view != 0) {
+ return ((FGViewer *)view)->getTargetZOffset_m();
+ } else {
+ return 0;
+ }
+}
+
+void
+FGViewMgr::setViewTargetZOffset_m (double z)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0) {
+ view->setTargetZOffset_m(z);
+ }
+}
+
+int
+FGViewMgr::getView () const
+{
+ return ( current );
+}
+
+void
+FGViewMgr::setView (int newview)
+{
+ // negative numbers -> set view with node index -newview
+ if (newview < 0) {
+ for (int i = 0; i < (int)config_list.size(); i++) {
+ int index = -config_list[i]->getIndex();
+ if (index == newview)
+ newview = i;
+ }
+ if (newview < 0)
+ return;
+ }
+
+ // if newview number too low wrap to last view...
+ if (newview < 0)
+ newview = (int)views.size() - 1;
+
+ // if newview number to high wrap to zero...
+ if (newview >= (int)views.size())
+ newview = 0;
+
+ // set new view
+ current = newview;
+ // copy in view data
+ copyToCurrent();
+}
+
+
+double
+FGViewMgr::getFOV_deg () const
+{
+ const FGViewer * view = get_current_view();
+ return (view == 0 ? 0 : view->get_fov());
+}
+
+void
+FGViewMgr::setFOV_deg (double fov)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0)
+ view->set_fov(fov);
+}
+
+double
+FGViewMgr::getARM_deg () const
+{
+ const FGViewer * view = get_current_view();
+ return (view == 0 ? 0 : view->get_aspect_ratio_multiplier());
+}
+
+void
+FGViewMgr::setARM_deg (double aspect_ratio_multiplier)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0)
+ view->set_aspect_ratio_multiplier(aspect_ratio_multiplier);
+}
+
+double
+FGViewMgr::getNear_m () const
+{
+ const FGViewer * view = get_current_view();
+ return (view == 0 ? 0.5f : view->getNear_m());
+}
+
+void
+FGViewMgr::setNear_m (double near_m)
+{
+ FGViewer * view = get_current_view();
+ if (view != 0)
+ view->setNear_m(near_m);
+}
+
+void
+FGViewMgr::setViewAxisLong (double axis)
+{
+ axis_long = axis;
+}
+
+void
+FGViewMgr::setViewAxisLat (double axis)
+{
+ axis_lat = axis;
+}
+
+// reference frame orientation.
+// This is the view orientation you get when you have no
+// view offset, i.e. the offset operator is the identity.
+//
+// For example, in the familiar "cockpit lookfrom" view,
+// the reference frame is equal to the aircraft attitude,
+// i.e. it is the view looking towards 12:00 straight ahead.
+//
+// FIXME: Somebody needs to figure out what is the reference
+// frame view for the other view modes.
+//
+// Conceptually, this quat represents a rotation relative
+// to the ECEF reference orientation, as described at
+// http://www.av8n.com/physics/coords.htm#sec-orientation
+//
+// See the NOTE concerning reference orientations, below.
+//
+// The components of this quat are expressed in
+// the conventional aviation basis set,
+// i.e. x=forward, y=starboard, z=bottom
+double FGViewMgr::getCurrentViewFrame_w() const{
+ return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).w();
+}
+double FGViewMgr::getCurrentViewFrame_x() const{
+ return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).x();
+}
+double FGViewMgr::getCurrentViewFrame_y() const{
+ return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).y();
+}
+double FGViewMgr::getCurrentViewFrame_z() const{
+ return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).z();
+}
+
+
+// view offset.
+// This rotation takes you from the aforementioned
+// reference frame view orientation to whatever
+// actual current view orientation is.
+//
+// The components of this quaternion are expressed in
+// the conventional aviation basis set,
+// i.e. x=forward, y=starboard, z=bottom
+double FGViewMgr::getCurrentViewOrOffset_w() const{
+ return current_view_or_offset.w();
+}
+double FGViewMgr::getCurrentViewOrOffset_x() const{
+ return current_view_or_offset.x();
+}
+double FGViewMgr::getCurrentViewOrOffset_y() const{
+ return current_view_or_offset.y();
+}
+double FGViewMgr::getCurrentViewOrOffset_z() const{
+ return current_view_or_offset.z();
+}
+
+
+// current view orientation.
+// This is a rotation relative to the earth-centered (ec)
+// reference frame.
+//
+// NOTE: Here we remove a factor of fsb2sta so that
+// the components of this quat are displayed using the
+// conventional ECEF basis set. This is *not* the way
+// the view orientation is stored in the views[] array,
+// but is easier for non-graphics hackers to understand.
+// If we did not remove this factor of fsb2sta here and
+// in getCurrentViewFrame, that would be equivalent to
+// the following peculiar reference orientation:
+// Suppose you are over the Gulf of Guinea, at (lat,lon) = (0,0).
+// Then the reference frame orientation can be achieved via:
+// -- The aircraft X-axis (nose) headed south.
+// -- The aircraft Y-axis (starboard wingtip) pointing up.
+// -- The aircraft Z-axis (belly) pointing west.
+// To say the same thing in other words, and perhaps more to the
+// point: If we use the OpenGL camera orientation conventions,
+// i.e. Xprime=starboard, Yprime=top, Zprime=aft, then the
+// aforementioned peculiar reference orientation at (lat,lon)
+// = (0,0) can be described as:
+// -- aircraft Xprime axis (starboard) pointed up
+// -- aircraft Yprime axis (top) pointed east
+// -- aircraft Zprime axis (aft) pointed north
+// meaning the OpenGL axes are aligned with the ECEF axes.
+double FGViewMgr::getCurrentViewOrientation_w() const{
+ return (current_view_orientation * conj(fsb2sta())).w();
+}
+double FGViewMgr::getCurrentViewOrientation_x() const{
+ return (current_view_orientation * conj(fsb2sta())).x();
+}
+double FGViewMgr::getCurrentViewOrientation_y() const{
+ return (current_view_orientation * conj(fsb2sta())).y();
+}
+double FGViewMgr::getCurrentViewOrientation_z() const{
+ return (current_view_orientation * conj(fsb2sta())).z();
+}
+
+void
+FGViewMgr::do_axes ()
+{
+ // Take no action when hat is centered
+ if ( ( axis_long < 0.01 ) &&
+ ( axis_long > -0.01 ) &&
+ ( axis_lat < 0.01 ) &&
+ ( axis_lat > -0.01 )
+ )
+ return;
+
+ double viewDir = 999;
+
+ /* Do all the quick and easy cases */
+ if (axis_long < 0) { // Longitudinal axis forward
+ if (axis_lat == axis_long)
+ viewDir = fgGetDouble("/sim/view/config/front-left-direction-deg");
+ else if (axis_lat == - axis_long)
+ viewDir = fgGetDouble("/sim/view/config/front-right-direction-deg");
+ else if (axis_lat == 0)
+ viewDir = fgGetDouble("/sim/view/config/front-direction-deg");
+ } else if (axis_long > 0) { // Longitudinal axis backward
+ if (axis_lat == - axis_long)
+ viewDir = fgGetDouble("/sim/view/config/back-left-direction-deg");
+ else if (axis_lat == axis_long)
+ viewDir = fgGetDouble("/sim/view/config/back-right-direction-deg");
+ else if (axis_lat == 0)
+ viewDir = fgGetDouble("/sim/view/config/back-direction-deg");
+ } else if (axis_long == 0) { // Longitudinal axis neutral
+ if (axis_lat < 0)
+ viewDir = fgGetDouble("/sim/view/config/left-direction-deg");
+ else if (axis_lat > 0)
+ viewDir = fgGetDouble("/sim/view/config/right-direction-deg");
+ else return; /* And assertion failure maybe? */
+ }
+
+ // Do all the difficult cases
+ if ( viewDir > 900 )
+ viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axis_lat, -axis_long );
+ if ( viewDir < -1 ) viewDir += 360;
+
+ get_current_view()->setGoalHeadingOffset_deg(viewDir);
+}
--- /dev/null
+// viewmgr.hxx -- class for managing all the views in the flightgear world.
+//
+// Written by Curtis Olson, started October 2000.
+//
+// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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 GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// $Id$
+
+
+#ifndef _VIEWMGR_HXX
+#define _VIEWMGR_HXX
+
+#include <vector>
+
+#include <simgear/compiler.h>
+#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/props/props.hxx>
+#include <simgear/props/tiedpropertylist.hxx>
+#include <simgear/math/SGMath.hxx>
+
+// forward decls
+class FGViewer;
+class SGSoundMgr;
+typedef SGSharedPtr<FGViewer> FGViewerPtr;
+
+// Define a structure containing view information
+class FGViewMgr : public SGSubsystem
+{
+
+public:
+
+ // Constructor
+ FGViewMgr( void );
+
+ // Destructor
+ ~FGViewMgr( void );
+
+ virtual void init ();
+ virtual void bind ();
+ virtual void unbind ();
+ virtual void update (double dt);
+ virtual void reinit ();
+
+ // getters
+ inline int size() const { return views.size(); }
+ inline int get_current() const { return current; }
+
+ FGViewer *get_current_view();
+ const FGViewer *get_current_view() const;
+
+ FGViewer *get_view( int i );
+ const FGViewer *get_view( int i ) const;
+
+ FGViewer *next_view();
+ FGViewer *prev_view();
+
+ // setters
+ void clear();
+
+ void add_view( FGViewer * v );
+
+private:
+ void do_bind();
+
+ simgear::TiedPropertyList _tiedProperties;
+
+ double axis_long;
+ double axis_lat;
+
+ void do_axes ();
+
+ // callbacks in manager to access viewer methods
+ double getViewHeadingOffset_deg () const;
+ void setViewHeadingOffset_deg (double offset);
+ double getViewGoalHeadingOffset_deg () const;
+ void setViewGoalHeadingOffset_deg (double offset);
+ double getViewPitchOffset_deg () const;
+ void setViewPitchOffset_deg (double tilt);
+ double getGoalViewPitchOffset_deg () const;
+ void setGoalViewRollOffset_deg (double tilt);
+ double getViewRollOffset_deg () const;
+ void setViewRollOffset_deg (double tilt);
+ double getGoalViewRollOffset_deg () const;
+ void setGoalViewPitchOffset_deg (double tilt);
+ double getViewXOffset_m () const;
+ void setViewXOffset_m (double x);
+ double getViewYOffset_m () const;
+ void setViewYOffset_m (double y);
+ double getViewZOffset_m () const;
+ void setViewZOffset_m (double z);
+ double getViewTargetXOffset_m () const;
+ void setViewTargetXOffset_m (double x);
+ double getViewTargetYOffset_m () const;
+ void setViewTargetYOffset_m (double y);
+ double getViewTargetZOffset_m () const;
+ void setViewTargetZOffset_m (double z);
+ double getFOV_deg () const;
+ void setFOV_deg (double fov);
+ double getARM_deg () const; // Aspect Ratio Multiplier
+ void setARM_deg (double fov);
+ double getNear_m () const;
+ void setNear_m (double near_m);
+ void setViewAxisLong (double axis);
+ void setViewAxisLat (double axis);
+ int getView () const;
+ void setView (int newview);
+
+// quaternion accessors, for debugging:
+ double getCurrentViewOrientation_w() const;
+ double getCurrentViewOrientation_x() const;
+ double getCurrentViewOrientation_y() const;
+ double getCurrentViewOrientation_z() const;
+ double getCurrentViewOrOffset_w() const;
+ double getCurrentViewOrOffset_x() const;
+ double getCurrentViewOrOffset_y() const;
+ double getCurrentViewOrOffset_z() const;
+ double getCurrentViewFrame_w() const;
+ double getCurrentViewFrame_x() const;
+ double getCurrentViewFrame_y() const;
+ double getCurrentViewFrame_z() const;
+
+ bool stationary () const;
+
+ // copies current offset settings to current-view path...
+ void copyToCurrent ();
+
+ bool inited;
+ SGPropertyNode_ptr view_number;
+ std::vector<SGPropertyNode_ptr> config_list;
+ typedef std::vector<FGViewerPtr> viewer_list;
+ viewer_list views;
+ SGVec3d abs_viewer_position;
+
+ int current;
+ SGQuatd current_view_orientation, current_view_or_offset;
+
+ SGSoundMgr *smgr;
+
+};
+
+// This takes the conventional aviation XYZ body system
+// i.e. x=forward, y=starboard, z=bottom
+// which is widely used in FGFS
+// and rotates it into the OpenGL camera system
+// i.e. Xprime=starboard, Yprime=top, Zprime=aft.
+inline const SGQuatd fsb2sta()
+{
+ return SGQuatd(-0.5, -0.5, 0.5, 0.5);
+}
+
+#endif // _VIEWMGR_HXX