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 <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");
}

View file

@ -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
);
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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");
}

View file

@ -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