Allow placing canvas on scenery objects.
This commit is contained in:
parent
6f80df0b8d
commit
eba03b5e46
7 changed files with 228 additions and 55 deletions
|
@ -21,18 +21,45 @@
|
|||
#include <Canvas/FGCanvasSystemAdapter.hxx>
|
||||
#include <Cockpit/od_gauge.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Scripting/NasalModelData.hxx>
|
||||
#include <Viewer/CameraGroup.hxx>
|
||||
|
||||
#include <simgear/canvas/Canvas.hxx>
|
||||
|
||||
using simgear::canvas::Canvas;
|
||||
namespace sc = simgear::canvas;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static sc::Placements addSceneObjectPlacement( SGPropertyNode* placement,
|
||||
sc::CanvasPtr canvas )
|
||||
{
|
||||
int module_id = placement->getIntValue("module-id", -1);
|
||||
if( module_id < 0 )
|
||||
return sc::Placements();
|
||||
|
||||
FGNasalModelData* model_data =
|
||||
FGNasalModelData::getByModuleId( static_cast<unsigned int>(module_id) );
|
||||
|
||||
if( !model_data )
|
||||
return sc::Placements();
|
||||
|
||||
if( !model_data->getNode() )
|
||||
return sc::Placements();
|
||||
|
||||
return FGODGauge::set_texture
|
||||
(
|
||||
model_data->getNode(),
|
||||
placement,
|
||||
canvas->getTexture(),
|
||||
canvas->getCullCallback()
|
||||
);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
CanvasMgr::CanvasMgr():
|
||||
simgear::canvas::CanvasMgr
|
||||
(
|
||||
fgGetNode("/canvas/by-index", true),
|
||||
simgear::canvas::SystemAdapterPtr( new canvas::FGCanvasSystemAdapter )
|
||||
sc::SystemAdapterPtr( new canvas::FGCanvasSystemAdapter )
|
||||
),
|
||||
_cb_model_reinit
|
||||
(
|
||||
|
@ -41,17 +68,19 @@ CanvasMgr::CanvasMgr():
|
|||
fgGetNode("/sim/signals/model-reinit", true)
|
||||
)
|
||||
{
|
||||
Canvas::addPlacementFactory
|
||||
sc::Canvas::addPlacementFactory
|
||||
(
|
||||
"object",
|
||||
boost::bind
|
||||
(
|
||||
&FGODGauge::set_texture,
|
||||
&FGODGauge::set_aircraft_texture,
|
||||
_1,
|
||||
boost::bind(&Canvas::getTexture, _2),
|
||||
boost::bind(&Canvas::getCullCallback, _2)
|
||||
boost::bind(&sc::Canvas::getTexture, _2),
|
||||
boost::bind(&sc::Canvas::getCullCallback, _2)
|
||||
)
|
||||
);
|
||||
|
||||
sc::Canvas::addPlacementFactory("scenery-object", &addSceneObjectPlacement);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -87,6 +116,6 @@ CanvasMgr::getCanvasTexId(const simgear::canvas::CanvasPtr& canvas) const
|
|||
void CanvasMgr::handleModelReinit(SGPropertyNode*)
|
||||
{
|
||||
for(size_t i = 0; i < _elements.size(); ++i)
|
||||
boost::static_pointer_cast<Canvas>(_elements[i])
|
||||
boost::static_pointer_cast<sc::Canvas>(_elements[i])
|
||||
->reloadPlacements("object");
|
||||
}
|
||||
|
|
|
@ -303,23 +303,51 @@ class ReplaceStaticTextureVisitor:
|
|||
|
||||
//------------------------------------------------------------------------------
|
||||
simgear::canvas::Placements
|
||||
FGODGauge::set_texture( const char* name,
|
||||
FGODGauge::set_texture( osg::Node* branch,
|
||||
const char * name,
|
||||
osg::Texture2D* new_texture )
|
||||
{
|
||||
osg::Group* root = globals->get_scenery()->get_aircraft_branch();
|
||||
ReplaceStaticTextureVisitor visitor(name, new_texture);
|
||||
root->accept(visitor);
|
||||
branch->accept(visitor);
|
||||
return visitor.getPlacements();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
simgear::canvas::Placements
|
||||
FGODGauge::set_texture( SGPropertyNode* placement,
|
||||
FGODGauge::set_aircraft_texture( const char* name,
|
||||
osg::Texture2D* new_texture )
|
||||
{
|
||||
return set_texture
|
||||
(
|
||||
globals->get_scenery()->get_aircraft_branch(),
|
||||
name,
|
||||
new_texture
|
||||
);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
simgear::canvas::Placements
|
||||
FGODGauge::set_texture( osg::Node* branch,
|
||||
SGPropertyNode* placement,
|
||||
osg::Texture2D* new_texture,
|
||||
osg::NodeCallback* cull_callback )
|
||||
{
|
||||
osg::Group* root = globals->get_scenery()->get_aircraft_branch();
|
||||
ReplaceStaticTextureVisitor visitor(placement, new_texture, cull_callback);
|
||||
root->accept(visitor);
|
||||
branch->accept(visitor);
|
||||
return visitor.getPlacements();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
simgear::canvas::Placements
|
||||
FGODGauge::set_aircraft_texture( SGPropertyNode* placement,
|
||||
osg::Texture2D* new_texture,
|
||||
osg::NodeCallback* cull_callback )
|
||||
{
|
||||
return set_texture
|
||||
(
|
||||
globals->get_scenery()->get_aircraft_branch(),
|
||||
placement,
|
||||
new_texture,
|
||||
cull_callback
|
||||
);
|
||||
}
|
||||
|
|
|
@ -39,24 +39,42 @@ class FGODGauge:
|
|||
virtual ~FGODGauge();
|
||||
|
||||
/**
|
||||
* Replace an opengl texture name inside the aircraft scene graph.
|
||||
* Replace an opengl texture name inside a given branch of the scene graph.
|
||||
* This is to replace a static texture by a dynamic one
|
||||
* @param name texture filename
|
||||
* @param new_texture dynamic texture to replace the old one
|
||||
*
|
||||
* @param branch Scene graph branch to use for search
|
||||
* @param name texture filename
|
||||
* @param new_texture dynamic texture to replace the old one
|
||||
* @return A list of groups which override the given texture
|
||||
*/
|
||||
static
|
||||
simgear::canvas::Placements set_texture( const char * name,
|
||||
simgear::canvas::Placements set_texture( osg::Node* branch,
|
||||
const char * name,
|
||||
osg::Texture2D* new_texture );
|
||||
|
||||
/**
|
||||
* Replace an opengl texture name inside the aircraft scene graph.
|
||||
* This is to replace a static texture by a dynamic one
|
||||
*
|
||||
* @param branch Scene graph branch to search for matching
|
||||
* @param name texture filename
|
||||
* @param new_texture dynamic texture to replace the old one
|
||||
* @return A list of groups which override the given texture
|
||||
*/
|
||||
static
|
||||
simgear::canvas::Placements
|
||||
set_aircraft_texture( const char * name,
|
||||
osg::Texture2D* new_texture );
|
||||
|
||||
/**
|
||||
* Replace an opengl texture name inside a given branch of the scene graph.
|
||||
* This is to replace a static texture by a dynamic one. The replacement
|
||||
* is base on certain filtering criteria which have to be stored in string
|
||||
* value childs of the placement node. Recognized nodes are:
|
||||
* - texture Match the name of the texture
|
||||
* - node Match the name of the object
|
||||
* - parent Match any of the object parents names (all the tree upwards)
|
||||
*
|
||||
* @param placement the node containing the replacement criteria
|
||||
* @param new_texture dynamic texture to replace the old one
|
||||
* @param an optional cull callback which will be installed on any matching
|
||||
|
@ -65,10 +83,26 @@ class FGODGauge:
|
|||
*/
|
||||
static
|
||||
simgear::canvas::Placements
|
||||
set_texture( SGPropertyNode* placement,
|
||||
set_texture( osg::Node* branch,
|
||||
SGPropertyNode* placement,
|
||||
osg::Texture2D* new_texture,
|
||||
osg::NodeCallback* cull_callback = 0 );
|
||||
|
||||
/**
|
||||
* Replace an opengl texture name inside the aircraft scene graph.
|
||||
*
|
||||
* @param placement the node containing the replacement criteria
|
||||
* @param new_texture dynamic texture to replace the old one
|
||||
* @param an optional cull callback which will be installed on any matching
|
||||
* object
|
||||
* @return A list of groups which override the given texture
|
||||
*/
|
||||
static
|
||||
simgear::canvas::Placements
|
||||
set_aircraft_texture( SGPropertyNode* placement,
|
||||
osg::Texture2D* new_texture,
|
||||
osg::NodeCallback* cull_callback = 0 );
|
||||
|
||||
};
|
||||
|
||||
#endif // _OD_GAUGE_HXX
|
||||
|
|
|
@ -1,24 +1,50 @@
|
|||
|
||||
#include "NasalModelData.hxx"
|
||||
|
||||
#include <cstring> // for strlen
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "NasalSys.hxx"
|
||||
#include <Main/globals.hxx>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring> // for strlen
|
||||
|
||||
// FGNasalModelData class. If sgLoad3DModel() is called with a pointer to
|
||||
// such a class, then it lets modelLoaded() run the <load> script, and the
|
||||
// destructor the <unload> script. The latter happens when the model branch
|
||||
// is removed from the scene graph.
|
||||
|
||||
unsigned int FGNasalModelData::_module_id = 0;
|
||||
unsigned int FGNasalModelData::_max_module_id = 0;
|
||||
FGNasalModelDataList FGNasalModelData::_loaded_models;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FGNasalModelData::FGNasalModelData( SGPropertyNode *root,
|
||||
const std::string& path,
|
||||
SGPropertyNode *prop,
|
||||
SGPropertyNode* load,
|
||||
SGPropertyNode* unload,
|
||||
osg::Node* branch ):
|
||||
_path(path),
|
||||
_root(root), _prop(prop),
|
||||
_load(load), _unload(unload),
|
||||
_branch(branch),
|
||||
_module_id( _max_module_id++ )
|
||||
{
|
||||
_loaded_models.push_back(this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FGNasalModelData::~FGNasalModelData()
|
||||
{
|
||||
_loaded_models.remove(this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FGNasalModelData::load()
|
||||
{
|
||||
std::stringstream m;
|
||||
m << "__model" << _module_id++;
|
||||
m << "__model" << _module_id;
|
||||
_module = m.str();
|
||||
|
||||
SG_LOG(SG_NASAL, SG_DEBUG, "Loading nasal module " << _module.c_str());
|
||||
|
@ -26,6 +52,10 @@ void FGNasalModelData::load()
|
|||
const char *s = _load ? _load->getStringValue() : "";
|
||||
FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
|
||||
|
||||
// Add _module_id to script local hash to allow placing canvasses on objects
|
||||
// inside the model.
|
||||
nasalSys->getGlobals().createHash(_module).set("_module_id", _module_id);
|
||||
|
||||
naRef arg[2];
|
||||
arg[0] = nasalSys->propNodeGhost(_root);
|
||||
arg[1] = nasalSys->propNodeGhost(_prop);
|
||||
|
@ -33,31 +63,66 @@ void FGNasalModelData::load()
|
|||
_root, 2, arg);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FGNasalModelData::unload()
|
||||
{
|
||||
if (_module.empty())
|
||||
return;
|
||||
|
||||
|
||||
FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
|
||||
if(!nasalSys) {
|
||||
SG_LOG(SG_NASAL, SG_WARN, "Trying to run an <unload> script "
|
||||
"without Nasal subsystem present.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SG_LOG(SG_NASAL, SG_DEBUG, "Unloading nasal module " << _module.c_str());
|
||||
|
||||
|
||||
if (_unload)
|
||||
{
|
||||
const char *s = _unload->getStringValue();
|
||||
nasalSys->createModule(_module.c_str(), _module.c_str(), s, strlen(s), _root);
|
||||
}
|
||||
|
||||
|
||||
nasalSys->deleteModule(_module.c_str());
|
||||
}
|
||||
|
||||
void FGNasalModelDataProxy::modelLoaded(const std::string& path, SGPropertyNode *prop,
|
||||
osg::Node *)
|
||||
//------------------------------------------------------------------------------
|
||||
osg::Node* FGNasalModelData::getNode()
|
||||
{
|
||||
return _branch;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FGNasalModelData* FGNasalModelData::getByModuleId(unsigned int id)
|
||||
{
|
||||
FGNasalModelDataList::iterator it = std::find_if
|
||||
(
|
||||
_loaded_models.begin(),
|
||||
_loaded_models.end(),
|
||||
boost::bind(&FGNasalModelData::_module_id, _1) == id
|
||||
);
|
||||
|
||||
if( it != _loaded_models.end() )
|
||||
return *it;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FGNasalModelDataProxy::~FGNasalModelDataProxy()
|
||||
{
|
||||
FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
|
||||
// when necessary, register Nasal module to be destroyed/unloaded
|
||||
// in the main thread.
|
||||
if ((_data.valid())&&(nasalSys))
|
||||
nasalSys->registerToUnload(_data);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FGNasalModelDataProxy::modelLoaded( const std::string& path,
|
||||
SGPropertyNode *prop,
|
||||
osg::Node *branch )
|
||||
{
|
||||
FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
|
||||
if(!nasalSys) {
|
||||
|
@ -79,17 +144,8 @@ void FGNasalModelDataProxy::modelLoaded(const std::string& path, SGPropertyNode
|
|||
if ((!load) && (!unload))
|
||||
return;
|
||||
|
||||
_data = new FGNasalModelData(_root, path, prop, load, unload);
|
||||
_data = new FGNasalModelData(_root, path, prop, load, unload, branch);
|
||||
|
||||
// register Nasal module to be created and loaded in the main thread.
|
||||
nasalSys->registerToLoad(_data);
|
||||
}
|
||||
|
||||
FGNasalModelDataProxy::~FGNasalModelDataProxy()
|
||||
{
|
||||
FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
|
||||
// when necessary, register Nasal module to be destroyed/unloaded
|
||||
// in the main thread.
|
||||
if ((_data.valid())&&(nasalSys))
|
||||
nasalSys->registerToUnload(_data);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
#include <simgear/nasal/nasal.h>
|
||||
#include <simgear/scene/model/modellib.hxx>
|
||||
|
||||
using std::string;
|
||||
class FGNasalModelData;
|
||||
typedef SGSharedPtr<FGNasalModelData> FGNasalModelDataRef;
|
||||
typedef std::list<FGNasalModelData*> FGNasalModelDataList;
|
||||
|
||||
/** Nasal model data container.
|
||||
* load and unload methods must be run in main thread (not thread-safe). */
|
||||
|
@ -28,26 +30,45 @@ class FGNasalModelData : public SGReferenced
|
|||
{
|
||||
public:
|
||||
/** Constructor to be run in an arbitrary thread. */
|
||||
FGNasalModelData(SGPropertyNode *root, const string& path, SGPropertyNode *prop,
|
||||
SGPropertyNode* load, SGPropertyNode* unload) :
|
||||
_path(path),
|
||||
_root(root), _prop(prop),
|
||||
_load(load), _unload(unload)
|
||||
{
|
||||
}
|
||||
FGNasalModelData( SGPropertyNode *root,
|
||||
const std::string& path,
|
||||
SGPropertyNode *prop,
|
||||
SGPropertyNode* load,
|
||||
SGPropertyNode* unload,
|
||||
osg::Node* branch );
|
||||
|
||||
~FGNasalModelData();
|
||||
|
||||
/** Load hook. Always call from inside the main loop. */
|
||||
void load();
|
||||
|
||||
/** Unload hook. Always call from inside the main loop. */
|
||||
void unload();
|
||||
|
||||
/**
|
||||
* Get osg scenegraph node of model
|
||||
*/
|
||||
osg::Node* getNode();
|
||||
|
||||
/**
|
||||
* Get FGNasalModelData for model with the given module id. Every scenery
|
||||
* model containing a nasal load or unload tag gets assigned a module id
|
||||
* automatically.
|
||||
*
|
||||
* @param id Module id
|
||||
* @return model data or NULL if does not exists
|
||||
*/
|
||||
static FGNasalModelData* getByModuleId(unsigned int id);
|
||||
|
||||
private:
|
||||
static unsigned int _module_id;
|
||||
|
||||
string _module, _path;
|
||||
static unsigned int _max_module_id;
|
||||
static FGNasalModelDataList _loaded_models;
|
||||
|
||||
std::string _module, _path;
|
||||
SGPropertyNode_ptr _root, _prop;
|
||||
SGConstPropertyNode_ptr _load, _unload;
|
||||
osg::Node *_branch;
|
||||
unsigned int _module_id;
|
||||
};
|
||||
|
||||
/** Thread-safe proxy for FGNasalModelData.
|
||||
|
@ -64,11 +85,13 @@ public:
|
|||
|
||||
~FGNasalModelDataProxy();
|
||||
|
||||
void modelLoaded(const string& path, SGPropertyNode *prop, osg::Node *);
|
||||
void modelLoaded( const std::string& path,
|
||||
SGPropertyNode *prop,
|
||||
osg::Node *branch );
|
||||
|
||||
protected:
|
||||
SGPropertyNode_ptr _root;
|
||||
SGSharedPtr<FGNasalModelData> _data;
|
||||
FGNasalModelDataRef _data;
|
||||
};
|
||||
|
||||
#endif // of NASAL_MODEL_DATA_HXX
|
||||
|
|
|
@ -822,8 +822,7 @@ naRef FGNasalSys::wrappedPropsNode(SGPropertyNode* aProps)
|
|||
{
|
||||
static naRef wrapNodeFunc = naNil();
|
||||
if (naIsNil(wrapNodeFunc)) {
|
||||
nasal::Hash g(_globals, _context);
|
||||
nasal::Hash props = g.get<nasal::Hash>("props");
|
||||
nasal::Hash props = getGlobals().get<nasal::Hash>("props");
|
||||
wrapNodeFunc = props.get("wrapNode");
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <simgear/misc/sg_dir.hxx>
|
||||
#include <simgear/nasal/cppbind/NasalHash.hxx>
|
||||
#include <simgear/nasal/nasal.h>
|
||||
#include <simgear/threads/SGQueue.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
@ -108,6 +109,9 @@ public:
|
|||
|
||||
naContext context() const
|
||||
{ return _context; }
|
||||
|
||||
nasal::Hash getGlobals() const
|
||||
{ return nasal::Hash(_globals, _context); }
|
||||
|
||||
// This mechanism is here to allow naRefs to be passed to
|
||||
// locations "outside" the interpreter. Normally, such a
|
||||
|
|
Loading…
Add table
Reference in a new issue