20,741
edits
m (→Canvas & Slave Cameras: https://forum.flightgear.org/viewtopic.php?f=71&t=23929#p317448) |
|||
| Line 118: | Line 118: | ||
|script_version = 0.40 | |script_version = 0.40 | ||
}}</ref> | }}</ref> | ||
{{collapsible script | |||
| type = C++ diff | |||
| title = Proof of concept implementing slaved camera views rendering to a FBO/RTT | |||
| script = From 9637fb0ac157d3df21feb60b279a7c8ccb8adf57 Mon Sep 17 00:00:00 2001 | |||
From: =?UTF-8?q?Cl=C3=A9ment=20de=20l=27Hamaide?= <cl-----e---ma----ez@hotmail.fr> | |||
Date: Tue, 23 Feb 2016 21:42:11 +0100 | |||
Subject: [PATCH] Implement CameraDisplay instrument | |||
--- | |||
src/Cockpit/CMakeLists.txt | 4 +- | |||
src/Cockpit/CameraDisplay.cxx | 239 +++++++++++++++++++++++++++++++++ | |||
src/Cockpit/CameraDisplay.hxx | 73 ++++++++++ | |||
src/Cockpit/cockpitDisplayManager.cxx | 6 +- | |||
src/Instrumentation/instrument_mgr.cxx | 3 +- | |||
5 files changed, 322 insertions(+), 3 deletions(-) | |||
create mode 100644 src/Cockpit/CameraDisplay.cxx | |||
create mode 100644 src/Cockpit/CameraDisplay.hxx | |||
diff --git a/src/Cockpit/CMakeLists.txt b/src/Cockpit/CMakeLists.txt | |||
index 42b03ba..6d722ea 100644 | |||
--- a/src/Cockpit/CMakeLists.txt | |||
+++ b/src/Cockpit/CMakeLists.txt | |||
@@ -11,6 +11,7 @@ set(SOURCES | |||
render_area_2d.cxx | |||
wxradar.cxx | |||
NavDisplay.cxx | |||
+ CameraDisplay.cxx | |||
) | |||
set(HEADERS | |||
@@ -24,7 +25,8 @@ set(HEADERS | |||
render_area_2d.hxx | |||
wxradar.hxx | |||
NavDisplay.hxx | |||
+ CameraDisplay.hxx | |||
) | |||
-flightgear_component(Cockpit "${SOURCES}" "${HEADERS}") | |||
\ No newline at end of file | |||
+flightgear_component(Cockpit "${SOURCES}" "${HEADERS}") | |||
diff --git a/src/Cockpit/CameraDisplay.cxx b/src/Cockpit/CameraDisplay.cxx | |||
new file mode 100644 | |||
index 0000000..51c1d0a | |||
--- /dev/null | |||
+++ b/src/Cockpit/CameraDisplay.cxx | |||
@@ -0,0 +1,239 @@ | |||
+// camera display texture | |||
+// | |||
+// Written by Clément de l'Hamaide | |||
+// | |||
+// | |||
+// 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 <osg/ImageStream> | |||
+ | |||
+#include <Main/fg_props.hxx> | |||
+#include <Viewer/viewmgr.hxx> | |||
+#include <Scenery/scenery.hxx> | |||
+#include <Viewer/renderer.hxx> | |||
+ | |||
+#include <simgear/scene/material/EffectGeode.hxx> | |||
+#include <simgear/scene/util/OsgMath.hxx> | |||
+ | |||
+#include "CameraDisplay.hxx" | |||
+#include "panel.hxx" | |||
+ | |||
+ | |||
+ | |||
+class FindAndReplaceStaticTextureVisitor : public osg::NodeVisitor | |||
+{ | |||
+ public: | |||
+ FindAndReplaceStaticTextureVisitor( const char* name, osg::Texture2D* new_texture ) : | |||
+ osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), | |||
+ _tex_name( osgDB::getSimpleFileName(name) ), | |||
+ _new_texture(new_texture) | |||
+ {} | |||
+ | |||
+ virtual void apply(osg::Geode& node) | |||
+ { | |||
+ simgear::EffectGeode* eg = dynamic_cast<simgear::EffectGeode*>(&node); | |||
+ if( !eg ) | |||
+ return; | |||
+ simgear::Effect* eff = eg->getEffect(); | |||
+ if (!eff) | |||
+ return; | |||
+ osg::StateSet* ss = eff->getDefaultStateSet(); | |||
+ if( !ss ) | |||
+ return; | |||
+ | |||
+ for( size_t unit = 0; unit < ss->getNumTextureAttributeLists(); ++unit ) { | |||
+ osg::Texture2D* tex = dynamic_cast<osg::Texture2D*>( ss->getTextureAttribute(unit, osg::StateAttribute::TEXTURE) ); | |||
+ if( !tex || !tex->getImage() || tex == _new_texture ) | |||
+ continue; | |||
+ | |||
+ if( !_tex_name.empty() ) { | |||
+ std::string tex_name = tex->getImage()->getFileName(); | |||
+ std::string tex_name_simple = osgDB::getSimpleFileName(tex_name); | |||
+ if( !osgDB::equalCaseInsensitive(_tex_name, tex_name_simple) ) | |||
+ continue; | |||
+ } | |||
+ | |||
+ // insert a new group between the geode an it's parent which overrides the texture | |||
+ osg::ref_ptr<osg::Group> group = new osg::Group; | |||
+ group->setName("canvas texture group"); | |||
+ group->addChild(eg); | |||
+ osg::ref_ptr<osg::Group> parent = node.getParent(0); | |||
+ parent->removeChild(eg); | |||
+ parent->addChild(group); | |||
+ | |||
+ osg::StateSet* stateSet = group->getOrCreateStateSet(); | |||
+ stateSet->setTextureAttribute( unit, _new_texture, osg::StateAttribute::OVERRIDE ); | |||
+ stateSet->setTextureMode( unit, GL_TEXTURE_2D, osg::StateAttribute::ON ); | |||
+ | |||
+ SG_LOG(SG_INSTR, SG_DEBUG, "CameraDislay: replaced texture '" << _tex_name << "'" << " for object '" << parent->getName() << "'"); | |||
+ return; | |||
+ } | |||
+ } | |||
+ | |||
+ protected: | |||
+ std::string _tex_name; | |||
+ osg::Texture2D *_new_texture; | |||
+}; | |||
+ | |||
+ | |||
+ | |||
+CameraDisplay::CameraDisplay(SGPropertyNode *node) : | |||
+ _num(node->getIntValue("number", 0)), | |||
+ _viewNum(node->getIntValue("view-number", 0)), | |||
+ _enabled(true), | |||
+ _initialized(false), | |||
+ _name(node->getStringValue("name", "cd")), | |||
+ _texturePath(node->getStringValue("texture-path", | |||
+ "Aircraft/Instruments/Textures/camera-display.rgb")) | |||
+{} | |||
+ | |||
+ | |||
+CameraDisplay::~CameraDisplay() | |||
+{ | |||
+ if( !_initialized ) | |||
+ return; | |||
+} | |||
+ | |||
+ | |||
+void CameraDisplay::bind() | |||
+{ | |||
+ _instrument_node = fgGetNode("/instrumentation/camera-display", _num, true); | |||
+ _name_node = _instrument_node->getChild( "name", 0, true); | |||
+ _texture_node = _instrument_node->getChild( "texture", 0, true); | |||
+ _enabled_node = _instrument_node->getChild( "enabled", 0, true ); | |||
+ _view_node = _instrument_node->getChild( "view-number", 0, true ); | |||
+ | |||
+ _view_node->setIntValue(_viewNum); | |||
+ _name_node->setStringValue(_name); | |||
+ _enabled_node->setBoolValue(_enabled); | |||
+ _texture_node->setStringValue(_texturePath); | |||
+ | |||
+ _view_node->addChangeListener(this); | |||
+ _enabled_node->addChangeListener(this); | |||
+} | |||
+ | |||
+ | |||
+void CameraDisplay::init() | |||
+{ | |||
+ if(_initialized) | |||
+ return; | |||
+ | |||
+ if ( !fgGetNode("/sim/view", _viewNum, false) ) { | |||
+ SG_LOG(SG_INSTR, SG_DEBUG, "CameraDisplay: can't find view-number " << _viewNum); | |||
+ return; | |||
+ } | |||
+ | |||
+ std::string path = _texture_node->getStringValue(); | |||
+ SGPath tpath = globals->resolve_aircraft_path( path ); | |||
+ if (!tpath.exists()) { | |||
+ SG_LOG(SG_INSTR, SG_WARN, "CameraDisplay: display texture not found:" << path); | |||
+ return; | |||
+ } | |||
+ | |||
+ _initialized = true; | |||
+} | |||
+ | |||
+ | |||
+void CameraDisplay::postinit() | |||
+{ | |||
+ if( !_initialized ) | |||
+ return; | |||
+ | |||
+ setView( _view_node->getIntValue() ); | |||
+ | |||
+ //TODO: setup an osg::Texture | |||
+ // setup an osg::Camera | |||
+ // attach the osg::Camera to the osg::Texture2D | |||
+ // in a way the camera draw on the osg::Texture2D | |||
+ // attach the osg::Texture2D to the 3D model | |||
+ // in a way the current 3D model texture being replaced by the osg::Texure2D | |||
+#if 1 | |||
+ int tex_width = 512, tex_height = 512; | |||
+ _texture = new osg::Texture2D; | |||
+ _texture->setTextureSize( tex_width, tex_height ); | |||
+ _texture->setInternalFormat( GL_RGBA ); | |||
+ _texture->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR ); | |||
+ _texture->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR ); | |||
+ | |||
+ FindAndReplaceStaticTextureVisitor ftv( _texture_node->getStringValue(), _texture.get() ); | |||
+ globals->get_scenery()->get_aircraft_branch()->accept(ftv); | |||
+ | |||
+ _camera = new osg::Camera; | |||
+ _camera->setViewport( 0, 0, tex_width, tex_height ); | |||
+ _camera->setClearColor( osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f) ); | |||
+ _camera->setClearMask( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); | |||
+ _camera->setRenderOrder( osg::Camera::PRE_RENDER ); | |||
+ _camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT ); | |||
+ _camera->attach( osg::Camera::COLOR_BUFFER, _texture.get() ); | |||
+ _camera->setReferenceFrame( osg::Camera::ABSOLUTE_RF ); | |||
+ _camera->addChild( globals->get_scenery()->get_scene_graph() ); | |||
+ _camera->setProjectionMatrixAsPerspective(/*fov*/ 85.0, /*ratio*/ 1.88, /*near*/ 0.1, /*far*/ 120000.0); | |||
+ globals->get_renderer()->addCamera(_camera, false); | |||
+#endif | |||
+} | |||
+ | |||
+ | |||
+void CameraDisplay::update(double dt) | |||
+{ | |||
+ if( !_initialized || !_enabled ) | |||
+ return; | |||
+#if 1 | |||
+ if( _view != globals->get_current_view() ) | |||
+ _view->update(dt); | |||
+ | |||
+ osg::Vec3f position( toOsg(_view->getViewPosition()) ); | |||
+ osg::Quat orientation( toOsg(_view->getViewOrientation()) ); | |||
+ osg::Matrix viewMatrix( osg::Matrix::translate(-position) * osg::Matrix::rotate(orientation.inverse()) ); | |||
+ | |||
+ _camera->setViewMatrix( viewMatrix ); | |||
+#endif | |||
+} | |||
+ | |||
+ | |||
+void CameraDisplay::valueChanged(SGPropertyNode *node) | |||
+{ | |||
+ if(!_initialized) | |||
+ return; | |||
+ | |||
+ if (node == _enabled_node) { | |||
+ _enabled = node->getBoolValue(); | |||
+ return; | |||
+ } | |||
+ | |||
+ if (node == _view_node) { | |||
+ _view = globals->get_viewmgr()->get_view( node->getIntValue() ); | |||
+ setView( node->getIntValue() ); | |||
+ return; | |||
+ } | |||
+} | |||
+ | |||
+ | |||
+void CameraDisplay::setView(int v) | |||
+{ | |||
+ std::vector<SGPropertyNode_ptr> viewList = fgGetNode("/sim", true)->getChildren("view"); | |||
+ for (unsigned int i = 0; i < viewList.size(); i++) { | |||
+ if( viewList[i]->getIndex() == v ) { | |||
+ _view = globals->get_viewmgr()->get_view(i); | |||
+ break; | |||
+ } | |||
+ } | |||
+} | |||
+ | |||
diff --git a/src/Cockpit/CameraDisplay.hxx b/src/Cockpit/CameraDisplay.hxx | |||
new file mode 100644 | |||
index 0000000..69e432a | |||
--- /dev/null | |||
+++ b/src/Cockpit/CameraDisplay.hxx | |||
@@ -0,0 +1,73 @@ | |||
+// camera display texture | |||
+// | |||
+// Written by Clément de l'Hamaide | |||
+// | |||
+// | |||
+// 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 _INST_CAMDISPLAY_HXX | |||
+#define _INST_CAMDISPLAY_HXX | |||
+ | |||
+#include <Viewer/view.hxx> | |||
+ | |||
+#include "od_gauge.hxx" | |||
+ | |||
+/* | |||
+ * CameraDisplay class | |||
+ * | |||
+ * A subsystem instrument who reproduces a camera and its display | |||
+ */ | |||
+ | |||
+class CameraDisplay : public SGSubsystem, public SGPropertyChangeListener | |||
+{ | |||
+ public: | |||
+ CameraDisplay(SGPropertyNode *node); | |||
+ virtual ~CameraDisplay(); | |||
+ | |||
+ virtual void bind(); | |||
+ virtual void init(); | |||
+ virtual void postinit(); | |||
+ virtual void update(double dt); | |||
+ virtual void valueChanged(SGPropertyNode *node); | |||
+ | |||
+ void setView(int v); | |||
+ | |||
+ protected: | |||
+ | |||
+ | |||
+ private: | |||
+ int _num; | |||
+ int _viewNum; | |||
+ bool _enabled; | |||
+ bool _initialized; | |||
+ FGODGauge *_odg; | |||
+ std::string _name; | |||
+ std::string _texturePath; | |||
+ flightgear::View *_view; | |||
+ SGPropertyNode_ptr _name_node; | |||
+ SGPropertyNode_ptr _view_node; | |||
+ SGPropertyNode_ptr _enabled_node; | |||
+ SGPropertyNode_ptr _texture_node; | |||
+ SGPropertyNode_ptr _instrument_node; | |||
+ osg::ref_ptr<osg::Camera> _camera; | |||
+ osg::ref_ptr<osg::Texture2D> _texture; | |||
+ osg::Matrix _viewMatrix; | |||
+ /*osg::Camera *_camera; | |||
+ osg::Texture2D *_texture;*/ | |||
+}; | |||
+ | |||
+#endif | |||
diff --git a/src/Cockpit/cockpitDisplayManager.cxx b/src/Cockpit/cockpitDisplayManager.cxx | |||
index 18e6e7d..0a46ff8 100644 | |||
--- a/src/Cockpit/cockpitDisplayManager.cxx | |||
+++ b/src/Cockpit/cockpitDisplayManager.cxx | |||
@@ -37,6 +37,7 @@ | |||
#include "NavDisplay.hxx" | |||
#include "groundradar.hxx" | |||
#include "wxradar.hxx" | |||
+#include "CameraDisplay.hxx" | |||
namespace flightgear | |||
{ | |||
@@ -112,7 +113,10 @@ bool CockpitDisplayManager::build (SGPropertyNode* config_props) | |||
} else if ( name == "navigation-display" ) { | |||
set_subsystem( id, new NavDisplay( node ) ); | |||
- | |||
+ | |||
+ } else if ( name == "camera-display" ) { | |||
+ set_subsystem( id, new CameraDisplay( node ) ); | |||
+ | |||
} else { | |||
// probably a regular instrument | |||
continue; | |||
diff --git a/src/Instrumentation/instrument_mgr.cxx b/src/Instrumentation/instrument_mgr.cxx | |||
index 751f6c7..3bd1dfa 100644 | |||
--- a/src/Instrumentation/instrument_mgr.cxx | |||
+++ b/src/Instrumentation/instrument_mgr.cxx | |||
@@ -209,7 +209,8 @@ bool FGInstrumentMgr::build (SGPropertyNode* config_props) | |||
} else if (( name == "groundradar" ) || | |||
( name == "radar" ) || | |||
( name == "air-ground-radar" ) || | |||
- ( name == "navigation-display" )) | |||
+ ( name == "navigation-display" ) || | |||
+ ( name == "camera-display" )) | |||
{ | |||
// these instruments are handled by the CockpitDisplayManager | |||
// catch them here so we can still warn about bogus names in | |||
-- | |||
1.9.1 | |||
| lang = diff | |||
}} | |||
=== G1000 & MapStructure improvements === | === G1000 & MapStructure improvements === | ||