1
0
Fork 0

Allow placing canvas on scenery objects.

This commit is contained in:
Thomas Geymayer 2013-03-21 01:16:01 +01:00
parent 6f80df0b8d
commit eba03b5e46
7 changed files with 228 additions and 55 deletions

View file

@ -21,18 +21,45 @@
#include <Canvas/FGCanvasSystemAdapter.hxx> #include <Canvas/FGCanvasSystemAdapter.hxx>
#include <Cockpit/od_gauge.hxx> #include <Cockpit/od_gauge.hxx>
#include <Main/fg_props.hxx> #include <Main/fg_props.hxx>
#include <Scripting/NasalModelData.hxx>
#include <Viewer/CameraGroup.hxx> #include <Viewer/CameraGroup.hxx>
#include <simgear/canvas/Canvas.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(): CanvasMgr::CanvasMgr():
simgear::canvas::CanvasMgr simgear::canvas::CanvasMgr
( (
fgGetNode("/canvas/by-index", true), fgGetNode("/canvas/by-index", true),
simgear::canvas::SystemAdapterPtr( new canvas::FGCanvasSystemAdapter ) sc::SystemAdapterPtr( new canvas::FGCanvasSystemAdapter )
), ),
_cb_model_reinit _cb_model_reinit
( (
@ -41,17 +68,19 @@ CanvasMgr::CanvasMgr():
fgGetNode("/sim/signals/model-reinit", true) fgGetNode("/sim/signals/model-reinit", true)
) )
{ {
Canvas::addPlacementFactory sc::Canvas::addPlacementFactory
( (
"object", "object",
boost::bind boost::bind
( (
&FGODGauge::set_texture, &FGODGauge::set_aircraft_texture,
_1, _1,
boost::bind(&Canvas::getTexture, _2), boost::bind(&sc::Canvas::getTexture, _2),
boost::bind(&Canvas::getCullCallback, _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*) void CanvasMgr::handleModelReinit(SGPropertyNode*)
{ {
for(size_t i = 0; i < _elements.size(); ++i) 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"); ->reloadPlacements("object");
} }

View file

@ -303,23 +303,51 @@ class ReplaceStaticTextureVisitor:
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
simgear::canvas::Placements simgear::canvas::Placements
FGODGauge::set_texture( const char* name, FGODGauge::set_texture( osg::Node* branch,
const char * name,
osg::Texture2D* new_texture ) osg::Texture2D* new_texture )
{ {
osg::Group* root = globals->get_scenery()->get_aircraft_branch();
ReplaceStaticTextureVisitor visitor(name, new_texture); ReplaceStaticTextureVisitor visitor(name, new_texture);
root->accept(visitor); branch->accept(visitor);
return visitor.getPlacements(); return visitor.getPlacements();
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
simgear::canvas::Placements 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::Texture2D* new_texture,
osg::NodeCallback* cull_callback ) osg::NodeCallback* cull_callback )
{ {
osg::Group* root = globals->get_scenery()->get_aircraft_branch();
ReplaceStaticTextureVisitor visitor(placement, new_texture, cull_callback); ReplaceStaticTextureVisitor visitor(placement, new_texture, cull_callback);
root->accept(visitor); branch->accept(visitor);
return visitor.getPlacements(); 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
);
}

View file

@ -39,24 +39,42 @@ class FGODGauge:
virtual ~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 * 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 * @return A list of groups which override the given texture
*/ */
static static
simgear::canvas::Placements set_texture( const char * name, simgear::canvas::Placements set_texture( osg::Node* branch,
const char * name,
osg::Texture2D* new_texture ); osg::Texture2D* new_texture );
/** /**
* Replace an opengl texture name inside the aircraft scene graph. * 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 * 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 * is base on certain filtering criteria which have to be stored in string
* value childs of the placement node. Recognized nodes are: * value childs of the placement node. Recognized nodes are:
* - texture Match the name of the texture * - texture Match the name of the texture
* - node Match the name of the object * - node Match the name of the object
* - parent Match any of the object parents names (all the tree upwards) * - parent Match any of the object parents names (all the tree upwards)
*
* @param placement the node containing the replacement criteria * @param placement the node containing the replacement criteria
* @param new_texture dynamic texture to replace the old one * @param new_texture dynamic texture to replace the old one
* @param an optional cull callback which will be installed on any matching * @param an optional cull callback which will be installed on any matching
@ -65,10 +83,26 @@ class FGODGauge:
*/ */
static static
simgear::canvas::Placements simgear::canvas::Placements
set_texture( SGPropertyNode* placement, set_texture( osg::Node* branch,
SGPropertyNode* placement,
osg::Texture2D* new_texture, osg::Texture2D* new_texture,
osg::NodeCallback* cull_callback = 0 ); 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 #endif // _OD_GAUGE_HXX

View file

@ -1,24 +1,50 @@
#include "NasalModelData.hxx" #include "NasalModelData.hxx"
#include <cstring> // for strlen
#include <simgear/debug/logstream.hxx>
#include "NasalSys.hxx" #include "NasalSys.hxx"
#include <Main/globals.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 // FGNasalModelData class. If sgLoad3DModel() is called with a pointer to
// such a class, then it lets modelLoaded() run the <load> script, and the // such a class, then it lets modelLoaded() run the <load> script, and the
// destructor the <unload> script. The latter happens when the model branch // destructor the <unload> script. The latter happens when the model branch
// is removed from the scene graph. // 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() void FGNasalModelData::load()
{ {
std::stringstream m; std::stringstream m;
m << "__model" << _module_id++; m << "__model" << _module_id;
_module = m.str(); _module = m.str();
SG_LOG(SG_NASAL, SG_DEBUG, "Loading nasal module " << _module.c_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() : ""; const char *s = _load ? _load->getStringValue() : "";
FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal"); 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]; naRef arg[2];
arg[0] = nasalSys->propNodeGhost(_root); arg[0] = nasalSys->propNodeGhost(_root);
arg[1] = nasalSys->propNodeGhost(_prop); arg[1] = nasalSys->propNodeGhost(_prop);
@ -33,31 +63,66 @@ void FGNasalModelData::load()
_root, 2, arg); _root, 2, arg);
} }
//------------------------------------------------------------------------------
void FGNasalModelData::unload() void FGNasalModelData::unload()
{ {
if (_module.empty()) if (_module.empty())
return; return;
FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal"); FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
if(!nasalSys) { if(!nasalSys) {
SG_LOG(SG_NASAL, SG_WARN, "Trying to run an <unload> script " SG_LOG(SG_NASAL, SG_WARN, "Trying to run an <unload> script "
"without Nasal subsystem present."); "without Nasal subsystem present.");
return; return;
} }
SG_LOG(SG_NASAL, SG_DEBUG, "Unloading nasal module " << _module.c_str()); SG_LOG(SG_NASAL, SG_DEBUG, "Unloading nasal module " << _module.c_str());
if (_unload) if (_unload)
{ {
const char *s = _unload->getStringValue(); const char *s = _unload->getStringValue();
nasalSys->createModule(_module.c_str(), _module.c_str(), s, strlen(s), _root); nasalSys->createModule(_module.c_str(), _module.c_str(), s, strlen(s), _root);
} }
nasalSys->deleteModule(_module.c_str()); 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"); FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
if(!nasalSys) { if(!nasalSys) {
@ -79,17 +144,8 @@ void FGNasalModelDataProxy::modelLoaded(const std::string& path, SGPropertyNode
if ((!load) && (!unload)) if ((!load) && (!unload))
return; 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. // register Nasal module to be created and loaded in the main thread.
nasalSys->registerToLoad(_data); 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);
}

View file

@ -20,7 +20,9 @@
#include <simgear/nasal/nasal.h> #include <simgear/nasal/nasal.h>
#include <simgear/scene/model/modellib.hxx> #include <simgear/scene/model/modellib.hxx>
using std::string; class FGNasalModelData;
typedef SGSharedPtr<FGNasalModelData> FGNasalModelDataRef;
typedef std::list<FGNasalModelData*> FGNasalModelDataList;
/** Nasal model data container. /** Nasal model data container.
* load and unload methods must be run in main thread (not thread-safe). */ * load and unload methods must be run in main thread (not thread-safe). */
@ -28,26 +30,45 @@ class FGNasalModelData : public SGReferenced
{ {
public: public:
/** Constructor to be run in an arbitrary thread. */ /** Constructor to be run in an arbitrary thread. */
FGNasalModelData(SGPropertyNode *root, const string& path, SGPropertyNode *prop, FGNasalModelData( SGPropertyNode *root,
SGPropertyNode* load, SGPropertyNode* unload) : const std::string& path,
_path(path), SGPropertyNode *prop,
_root(root), _prop(prop), SGPropertyNode* load,
_load(load), _unload(unload) SGPropertyNode* unload,
{ osg::Node* branch );
}
~FGNasalModelData();
/** Load hook. Always call from inside the main loop. */ /** Load hook. Always call from inside the main loop. */
void load(); void load();
/** Unload hook. Always call from inside the main loop. */ /** Unload hook. Always call from inside the main loop. */
void unload(); 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: private:
static unsigned int _module_id; static unsigned int _max_module_id;
static FGNasalModelDataList _loaded_models;
string _module, _path;
std::string _module, _path;
SGPropertyNode_ptr _root, _prop; SGPropertyNode_ptr _root, _prop;
SGConstPropertyNode_ptr _load, _unload; SGConstPropertyNode_ptr _load, _unload;
osg::Node *_branch;
unsigned int _module_id;
}; };
/** Thread-safe proxy for FGNasalModelData. /** Thread-safe proxy for FGNasalModelData.
@ -64,11 +85,13 @@ public:
~FGNasalModelDataProxy(); ~FGNasalModelDataProxy();
void modelLoaded(const string& path, SGPropertyNode *prop, osg::Node *); void modelLoaded( const std::string& path,
SGPropertyNode *prop,
osg::Node *branch );
protected: protected:
SGPropertyNode_ptr _root; SGPropertyNode_ptr _root;
SGSharedPtr<FGNasalModelData> _data; FGNasalModelDataRef _data;
}; };
#endif // of NASAL_MODEL_DATA_HXX #endif // of NASAL_MODEL_DATA_HXX

View file

@ -822,8 +822,7 @@ naRef FGNasalSys::wrappedPropsNode(SGPropertyNode* aProps)
{ {
static naRef wrapNodeFunc = naNil(); static naRef wrapNodeFunc = naNil();
if (naIsNil(wrapNodeFunc)) { if (naIsNil(wrapNodeFunc)) {
nasal::Hash g(_globals, _context); nasal::Hash props = getGlobals().get<nasal::Hash>("props");
nasal::Hash props = g.get<nasal::Hash>("props");
wrapNodeFunc = props.get("wrapNode"); wrapNodeFunc = props.get("wrapNode");
} }

View file

@ -4,6 +4,7 @@
#include <simgear/misc/sg_path.hxx> #include <simgear/misc/sg_path.hxx>
#include <simgear/structure/subsystem_mgr.hxx> #include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/misc/sg_dir.hxx> #include <simgear/misc/sg_dir.hxx>
#include <simgear/nasal/cppbind/NasalHash.hxx>
#include <simgear/nasal/nasal.h> #include <simgear/nasal/nasal.h>
#include <simgear/threads/SGQueue.hxx> #include <simgear/threads/SGQueue.hxx>
#include <simgear/props/props.hxx> #include <simgear/props/props.hxx>
@ -108,6 +109,9 @@ public:
naContext context() const naContext context() const
{ return _context; } { return _context; }
nasal::Hash getGlobals() const
{ return nasal::Hash(_globals, _context); }
// This mechanism is here to allow naRefs to be passed to // This mechanism is here to allow naRefs to be passed to
// locations "outside" the interpreter. Normally, such a // locations "outside" the interpreter. Normally, such a