Reset: refactor static CameraGroup ownership
This commit is contained in:
parent
98078cdd55
commit
d2962ffb2d
5 changed files with 356 additions and 259 deletions
|
@ -63,6 +63,7 @@ void fgOSCloseWindow();
|
|||
void fgOSFullScreen();
|
||||
int fgOSMainLoop();
|
||||
void fgOSExit(int code);
|
||||
void fgOSResetProperties();
|
||||
|
||||
void fgSetMouseCursor(int cursor);
|
||||
int fgGetMouseCursor();
|
||||
|
|
|
@ -387,7 +387,8 @@ int fgMainInit( int argc, char **argv ) {
|
|||
|
||||
// Clouds3D requires an alpha channel
|
||||
fgOSOpenWindow(true /* request stencil buffer */);
|
||||
|
||||
fgOSResetProperties();
|
||||
|
||||
// Initialize the splash screen right away
|
||||
fntInit();
|
||||
fgSplashInit();
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <simgear/math/SGRect.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/props/props_io.hxx> // for copyProperties
|
||||
#include <simgear/structure/OSGUtils.hxx>
|
||||
#include <simgear/structure/OSGVersion.hxx>
|
||||
#include <simgear/scene/material/EffectCullVisitor.hxx>
|
||||
|
@ -57,79 +58,116 @@
|
|||
#include <osgViewer/GraphicsWindow>
|
||||
#include <osgViewer/Renderer>
|
||||
|
||||
namespace flightgear {
|
||||
const char* MAIN_CAMERA = "main";
|
||||
const char* FAR_CAMERA = "far";
|
||||
const char* GEOMETRY_CAMERA = "geometry";
|
||||
const char* SHADOW_CAMERA = "shadow";
|
||||
const char* LIGHTING_CAMERA = "lighting";
|
||||
const char* DISPLAY_CAMERA = "display";
|
||||
}
|
||||
using namespace osg;
|
||||
|
||||
static osg::Matrix
|
||||
invert(const osg::Matrix& matrix)
|
||||
namespace
|
||||
{
|
||||
return osg::Matrix::inverse(matrix);
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// 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);
|
||||
}
|
||||
} // of anonymous namespace
|
||||
|
||||
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;
|
||||
}
|
||||
typedef std::vector<SGPropertyNode_ptr> SGPropertyNodeVec;
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
|
@ -138,59 +176,121 @@ using namespace osg;
|
|||
using std::strcmp;
|
||||
using std::string;
|
||||
|
||||
ref_ptr<CameraGroup> CameraGroup::_defaultGroup;
|
||||
class CameraGroupListener : public SGPropertyChangeListener
|
||||
{
|
||||
public:
|
||||
CameraGroupListener(CameraGroup* cg, SGPropertyNode* gnode) :
|
||||
_groupNode(gnode),
|
||||
_cameraGroup(cg)
|
||||
{
|
||||
listenToNode("znear", 0.1f);
|
||||
listenToNode("zfar", 120000.0f);
|
||||
listenToNode("near-field", 100.0f);
|
||||
}
|
||||
|
||||
virtual ~CameraGroupListener()
|
||||
{
|
||||
unlisten("znear");
|
||||
unlisten("zfar");
|
||||
unlisten("near-field");
|
||||
}
|
||||
|
||||
virtual void valueChanged(SGPropertyNode* prop)
|
||||
{
|
||||
if (!strcmp(prop->getName(), "znear")) {
|
||||
_cameraGroup->setZNear(prop->getFloatValue());
|
||||
} else if (!strcmp(prop->getName(), "zfar")) {
|
||||
_cameraGroup->setZFar(prop->getFloatValue());
|
||||
} else if (!strcmp(prop->getName(), "near-field")) {
|
||||
_cameraGroup->setNearField(prop->getFloatValue());
|
||||
}
|
||||
}
|
||||
private:
|
||||
void listenToNode(const std::string& name, double val)
|
||||
{
|
||||
SGPropertyNode* n = _groupNode->getChild(name);
|
||||
if (!n) {
|
||||
n = _groupNode->getChild(name, 0 /* index */, true);
|
||||
n->setDoubleValue(val);
|
||||
}
|
||||
n->addChangeListener(this);
|
||||
valueChanged(n); // propogate initial state through
|
||||
}
|
||||
|
||||
void unlisten(const std::string& name)
|
||||
{
|
||||
_groupNode->getChild(name)->removeChangeListener(this);
|
||||
}
|
||||
|
||||
SGPropertyNode_ptr _groupNode;
|
||||
CameraGroup* _cameraGroup; // non-owning reference
|
||||
|
||||
};
|
||||
|
||||
class CameraViewportListener : public SGPropertyChangeListener
|
||||
{
|
||||
public:
|
||||
CameraViewportListener(CameraInfo* info,
|
||||
SGPropertyNode* vnode,
|
||||
const osg::GraphicsContext::Traits *traits) :
|
||||
_viewportNode(vnode),
|
||||
_camera(info)
|
||||
{
|
||||
listenToNode("x", 0.0f);
|
||||
listenToNode("y", 0.0f);
|
||||
listenToNode("width", traits->width);
|
||||
listenToNode("height", traits->height);
|
||||
}
|
||||
|
||||
virtual ~CameraViewportListener()
|
||||
{
|
||||
unlisten("x");
|
||||
unlisten("y");
|
||||
unlisten("width");
|
||||
unlisten("height");
|
||||
}
|
||||
|
||||
virtual void valueChanged(SGPropertyNode* prop)
|
||||
{
|
||||
if (!strcmp(prop->getName(), "x")) {
|
||||
_camera->x = prop->getDoubleValue();
|
||||
} else if (!strcmp(prop->getName(), "y")) {
|
||||
_camera->y = prop->getDoubleValue();
|
||||
} else if (!strcmp(prop->getName(), "width")) {
|
||||
_camera->width = prop->getDoubleValue();
|
||||
} else if (!strcmp(prop->getName(), "height")) {
|
||||
_camera->height = prop->getDoubleValue();
|
||||
}
|
||||
}
|
||||
private:
|
||||
void listenToNode(const std::string& name, double val)
|
||||
{
|
||||
SGPropertyNode* n = _viewportNode->getChild(name);
|
||||
if (!n) {
|
||||
n = _viewportNode->getChild(name, 0 /* index */, true);
|
||||
n->setDoubleValue(val);
|
||||
}
|
||||
n->addChangeListener(this);
|
||||
valueChanged(n); // propogate initial state through
|
||||
}
|
||||
|
||||
void unlisten(const std::string& name)
|
||||
{
|
||||
_viewportNode->getChild(name)->removeChangeListener(this);
|
||||
}
|
||||
|
||||
SGPropertyNode_ptr _viewportNode;
|
||||
CameraInfo* _camera;
|
||||
|
||||
};
|
||||
|
||||
const char* MAIN_CAMERA = "main";
|
||||
const char* FAR_CAMERA = "far";
|
||||
const char* GEOMETRY_CAMERA = "geometry";
|
||||
const char* SHADOW_CAMERA = "shadow";
|
||||
const char* LIGHTING_CAMERA = "lighting";
|
||||
const char* DISPLAY_CAMERA = "display";
|
||||
|
||||
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 ) );
|
||||
|
@ -259,6 +359,11 @@ void CameraInfo::resized(double w, double h)
|
|||
}
|
||||
}
|
||||
|
||||
CameraInfo::~CameraInfo()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
osg::Camera* CameraInfo::getCamera(const std::string& k) const
|
||||
{
|
||||
CameraMap::const_iterator ii = cameras.find( k );
|
||||
|
@ -292,6 +397,21 @@ void CameraInfo::setMatrices(osg::Camera* c)
|
|||
worldPosGeod->set( osg::Vec3f( pos2.getLongitudeRad(), pos2.getLatitudeRad(), pos2.getElevationM() ) );
|
||||
}
|
||||
|
||||
CameraGroup::~CameraGroup()
|
||||
{
|
||||
|
||||
for (CameraList::iterator i = _cameras.begin(); i != _cameras.end(); ++i) {
|
||||
CameraInfo* info = *i;
|
||||
for (CameraMap::iterator ii = info->cameras.begin(); ii != info->cameras.end(); ++ii) {
|
||||
RenderStageInfo& rsi = ii->second;
|
||||
unsigned int slaveIndex = _viewer->findSlaveIndexForCamera(rsi.camera);
|
||||
_viewer->removeSlave(slaveIndex);
|
||||
}
|
||||
}
|
||||
|
||||
_cameras.clear();
|
||||
}
|
||||
|
||||
void CameraGroup::update(const osg::Vec3d& position,
|
||||
const osg::Quat& orientation)
|
||||
{
|
||||
|
@ -447,6 +567,13 @@ void CameraGroup::update(const osg::Vec3d& position,
|
|||
globals->get_renderer()->setPlanes( _zNear, _zFar );
|
||||
}
|
||||
|
||||
ref_ptr<CameraGroup> CameraGroup::_defaultGroup;
|
||||
|
||||
CameraGroup::CameraGroup(osgViewer::Viewer* viewer) :
|
||||
_viewer(viewer)
|
||||
{
|
||||
}
|
||||
|
||||
void CameraGroup::setCameraParameters(float vfov, float aspectRatio)
|
||||
{
|
||||
if (vfov != 0.0f && aspectRatio != 0.0f)
|
||||
|
@ -473,74 +600,6 @@ double CameraGroup::getMasterAspectRatio() const
|
|||
|
||||
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
|
||||
|
||||
|
@ -958,6 +1017,7 @@ CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
|
|||
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;
|
||||
|
@ -970,10 +1030,13 @@ CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
|
|||
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->viewportListener.reset(new CameraViewportListener(info, viewportNode, window->gc->getTraits()));
|
||||
|
||||
info->updateCameras();
|
||||
// Distortion camera needs the viewport which is created by addCamera().
|
||||
if (psNode) {
|
||||
|
@ -1033,7 +1096,9 @@ CameraInfo* CameraGroup::buildGUICamera(SGPropertyNode* cameraNode,
|
|||
// 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());
|
||||
|
||||
result->viewportListener.reset(new CameraViewportListener(result, viewportNode,
|
||||
window->gc->getTraits()));
|
||||
|
||||
// Disable statistics for the GUI camera.
|
||||
camera->setStats(0);
|
||||
|
@ -1045,6 +1110,8 @@ CameraGroup* CameraGroup::buildCameraGroup(osgViewer::Viewer* viewer,
|
|||
SGPropertyNode* gnode)
|
||||
{
|
||||
CameraGroup* cgroup = new CameraGroup(viewer);
|
||||
cgroup->_listener.reset(new CameraGroupListener(cgroup, gnode));
|
||||
|
||||
for (int i = 0; i < gnode->nChildren(); ++i) {
|
||||
SGPropertyNode* pNode = gnode->getChild(i);
|
||||
const char* name = pNode->getName();
|
||||
|
@ -1056,10 +1123,7 @@ CameraGroup* CameraGroup::buildCameraGroup(osgViewer::Viewer* viewer,
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -1266,4 +1330,50 @@ void warpGUIPointer(CameraGroup* cgroup, int x, int y)
|
|||
* (eventState->getYmax() - eventState->getYmin())));
|
||||
cgroup->getViewer()->getEventQueue()->mouseWarped(viewerX, viewerY);
|
||||
}
|
||||
|
||||
void CameraGroup::buildDefaultGroup(osgViewer::Viewer* viewer)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
SGPropertyNodeVec cameras(cgroupNode->getChildren("camera"));
|
||||
SGPropertyNode* masterCamera = 0;
|
||||
SGPropertyNodeVec::const_iterator it;
|
||||
for (it = cameras.begin(); it != cameras.end(); ++it) {
|
||||
if ((*it)->getDoubleValue("shear-x", 0.0) == 0.0
|
||||
&& (*it)->getDoubleValue("shear-y", 0.0) == 0.0) {
|
||||
masterCamera = it->ptr();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!masterCamera) {
|
||||
WindowBuilder *windowBuilder = WindowBuilder::getWindowBuilder();
|
||||
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* cgroup = buildCameraGroup(viewer, cgroupNode);
|
||||
setDefault(cgroup);
|
||||
}
|
||||
|
||||
} // of namespace flightgear
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <osg/Matrix>
|
||||
#include <osg/ref_ptr>
|
||||
|
@ -48,7 +49,9 @@ namespace flightgear
|
|||
{
|
||||
|
||||
class GraphicsWindow;
|
||||
|
||||
class CameraViewportListener;
|
||||
class CameraGroupListener;
|
||||
|
||||
struct RenderBufferInfo {
|
||||
RenderBufferInfo(osg::Texture2D* t = 0, float s = 1.0 ) : texture(t), scaleFactor(s) {}
|
||||
osg::ref_ptr<osg::Texture2D> texture;
|
||||
|
@ -106,10 +109,13 @@ struct CameraInfo : public osg::Referenced
|
|||
shadowMatrix[3] = new osg::Uniform("fg_ShadowMatrix_3", osg::Matrixf());
|
||||
}
|
||||
|
||||
~CameraInfo();
|
||||
|
||||
/** Update and resize cameras
|
||||
*/
|
||||
void updateCameras();
|
||||
void resized(double w, double h);
|
||||
|
||||
/** The name as given in the config file.
|
||||
*/
|
||||
std::string name;
|
||||
|
@ -161,6 +167,8 @@ struct CameraInfo : public osg::Referenced
|
|||
osg::ref_ptr<osg::Uniform> dv;
|
||||
osg::ref_ptr<osg::Uniform> shadowMatrix[4];
|
||||
|
||||
std::auto_ptr<CameraViewportListener> viewportListener;
|
||||
|
||||
void setMatrices( osg::Camera* c );
|
||||
|
||||
osgUtil::RenderBin::RenderBinList savedTransparentBins;
|
||||
|
@ -172,10 +180,6 @@ struct CameraInfo : public osg::Referenced
|
|||
osg::Vec2d thisReference[2];
|
||||
};
|
||||
|
||||
/** Update the OSG cameras from the camera info.
|
||||
*/
|
||||
void updateCameras(const CameraInfo* info);
|
||||
|
||||
class CameraGroup : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
@ -198,6 +202,9 @@ public:
|
|||
* @param viewer the viewer
|
||||
*/
|
||||
CameraGroup(osgViewer::Viewer* viewer);
|
||||
|
||||
~CameraGroup();
|
||||
|
||||
/** Get the camera group's Viewer.
|
||||
* @return the viewer
|
||||
*/
|
||||
|
@ -236,11 +243,15 @@ public:
|
|||
* matters at this time.
|
||||
* @param group the group to set.
|
||||
*/
|
||||
|
||||
static void buildDefaultGroup(osgViewer::Viewer* viewer);
|
||||
|
||||
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;
|
||||
|
@ -253,12 +264,6 @@ public:
|
|||
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);
|
||||
|
@ -278,16 +283,30 @@ public:
|
|||
* find the GUI camera if one is defined
|
||||
*/
|
||||
const CameraInfo* getGUICamera() const;
|
||||
|
||||
void setZNear(float f) { _zNear = f; }
|
||||
void setZFar(float f) { _zFar = f; }
|
||||
void setNearField(float f) { _nearField = f; }
|
||||
protected:
|
||||
CameraList _cameras;
|
||||
osg::ref_ptr<osgViewer::Viewer> _viewer;
|
||||
static osg::ref_ptr<CameraGroup> _defaultGroup;
|
||||
std::auto_ptr<CameraGroupListener> _listener;
|
||||
|
||||
// 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;
|
||||
|
||||
/** 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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ using namespace std;
|
|||
using namespace flightgear;
|
||||
using namespace osg;
|
||||
|
||||
static osg::ref_ptr<osgViewer::Viewer> viewer;
|
||||
osg::ref_ptr<osgViewer::Viewer> viewer;
|
||||
static osg::ref_ptr<osg::Camera> mainCamera;
|
||||
|
||||
static void setStereoMode( const char * mode )
|
||||
|
@ -251,12 +251,9 @@ void fgOSOpenWindow(bool stencil)
|
|||
{
|
||||
osg::setNotifyHandler(new NotifyLogger);
|
||||
|
||||
SGPropertyNode* osgLevel = fgGetNode("/sim/rendering/osg-notify-level", true);
|
||||
osgLevel->addChangeListener(new NotifyLevelListener, true);
|
||||
|
||||
viewer = new osgViewer::Viewer;
|
||||
viewer->setDatabasePager(FGScenery::getPagerSingleton());
|
||||
CameraGroup* cameraGroup = 0;
|
||||
|
||||
std::string mode;
|
||||
mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
|
||||
if (mode == "AutomaticSelection")
|
||||
|
@ -270,49 +267,8 @@ void fgOSOpenWindow(bool stencil)
|
|||
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());
|
||||
}
|
||||
CameraGroup::buildDefaultGroup(viewer.get());
|
||||
|
||||
FGEventHandler* manipulator = globals->get_renderer()->getEventHandler();
|
||||
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
|
||||
if (wsa->windows.size() != 1) {
|
||||
|
@ -325,8 +281,20 @@ void fgOSOpenWindow(bool stencil)
|
|||
// The viewer won't start without some root.
|
||||
viewer->setSceneData(new osg::Group);
|
||||
globals->get_renderer()->setViewer(viewer.get());
|
||||
CameraGroup::setDefault(cameraGroup);
|
||||
}
|
||||
|
||||
void fgOSResetProperties()
|
||||
{
|
||||
SGPropertyNode* osgLevel = fgGetNode("/sim/rendering/osg-notify-level", true);
|
||||
osgLevel->addChangeListener(new NotifyLevelListener, true);
|
||||
|
||||
osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
|
||||
if (guiCamera) {
|
||||
Viewport* guiViewport = guiCamera->getViewport();
|
||||
fgSetInt("/sim/startup/xsize", guiViewport->width());
|
||||
fgSetInt("/sim/startup/ysize", guiViewport->height());
|
||||
}
|
||||
|
||||
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 );
|
||||
|
@ -350,13 +318,11 @@ void fgOSExit(int 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();
|
||||
fgIdleHandler idleFunc = globals->get_renderer()->getEventHandler()->getIdleHandler();
|
||||
if (idleFunc)
|
||||
(*idleFunc)();
|
||||
globals->get_renderer()->update();
|
||||
|
|
Loading…
Add table
Reference in a new issue