Make SGLight configurable at runtime.
This commit is contained in:
@@ -2800,12 +2800,12 @@ namespace simgear
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SGPropertyNode::copy(SGPropertyNode *to)
|
void SGPropertyNode::copy(SGPropertyNode *to) const
|
||||||
{
|
{
|
||||||
if (nChildren())
|
if (nChildren())
|
||||||
{
|
{
|
||||||
for (int i = 0; i < nChildren(); i++) {
|
for (int i = 0; i < nChildren(); i++) {
|
||||||
SGPropertyNode *child = getChild(i);
|
const SGPropertyNode *child = getChild(i);
|
||||||
SGPropertyNode *to_child = to->getChild(child->getName());
|
SGPropertyNode *to_child = to->getChild(child->getName());
|
||||||
if (!to_child)
|
if (!to_child)
|
||||||
to_child = to->addChild(child->getName());
|
to_child = to->addChild(child->getName());
|
||||||
|
|||||||
@@ -1098,7 +1098,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* deep copy one node to another.
|
* deep copy one node to another.
|
||||||
*/
|
*/
|
||||||
void copy(SGPropertyNode *to);
|
void copy(SGPropertyNode *to) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a pointer to another node by relative path.
|
* Get a pointer to another node by relative path.
|
||||||
|
|||||||
@@ -39,99 +39,74 @@ private:
|
|||||||
osg::ref_ptr<osg::Switch> _sw;
|
osg::ref_ptr<osg::Switch> _sw;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SGLightConfigListener : public SGPropertyChangeListener {
|
||||||
|
public:
|
||||||
|
SGLightConfigListener(SGLight *light) : _light(light) {}
|
||||||
|
|
||||||
|
virtual void valueChanged(SGPropertyNode *node) {
|
||||||
|
while (strcmp(node->getName(), "light") && node->getParent()) {
|
||||||
|
node = node->getParent();
|
||||||
|
}
|
||||||
|
_light->configure(node);
|
||||||
|
auto *cb = _light->getUpdateCallback();
|
||||||
|
if (cb != nullptr) {
|
||||||
|
dynamic_cast<SGLight::UpdateCallback*>(cb)->configure(_light->getAmbient(), _light->getDiffuse(), _light->getSpecular());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
SGLight *_light;
|
||||||
|
};
|
||||||
|
|
||||||
|
SGLight::SGLight(const SGLight& l, const osg::CopyOp& copyop) :
|
||||||
|
osg::Node(l, copyop),
|
||||||
|
_type(l._type),
|
||||||
|
_range(l._range),
|
||||||
|
_ambient(l._ambient),
|
||||||
|
_diffuse(l._diffuse),
|
||||||
|
_specular(l._specular),
|
||||||
|
_constant_attenuation(l._constant_attenuation),
|
||||||
|
_linear_attenuation(l._linear_attenuation),
|
||||||
|
_quadratic_attenuation(l._quadratic_attenuation),
|
||||||
|
_spot_exponent(l._spot_exponent),
|
||||||
|
_spot_cutoff(l._spot_cutoff)
|
||||||
|
{}
|
||||||
|
|
||||||
osg::Node *
|
osg::Node *
|
||||||
SGLight::appendLight(const SGPropertyNode *configNode,
|
SGLight::appendLight(const SGPropertyNode *configNode,
|
||||||
SGPropertyNode *modelRoot,
|
SGPropertyNode *modelRoot,
|
||||||
const osgDB::Options *options)
|
const osgDB::Options *options)
|
||||||
{
|
{
|
||||||
SGConstPropertyNode_ptr p;
|
//-- create return variable
|
||||||
|
|
||||||
SGLight *light = new SGLight;
|
|
||||||
|
|
||||||
if((p = configNode->getNode("type")) != NULL) {
|
|
||||||
std::string type = p->getStringValue();
|
|
||||||
if (type == "point")
|
|
||||||
light->setType(SGLight::POINT);
|
|
||||||
else if (type == "spot")
|
|
||||||
light->setType(SGLight::SPOT);
|
|
||||||
else
|
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "ignoring unknown light type '" << type << "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
light->setRange(configNode->getFloatValue("range-m"));
|
|
||||||
|
|
||||||
std::string priority = configNode->getStringValue("priority", "low");
|
|
||||||
if (priority == "high")
|
|
||||||
light->setPriority(SGLight::HIGH);
|
|
||||||
else if (priority == "medium")
|
|
||||||
light->setPriority(SGLight::MEDIUM);
|
|
||||||
else
|
|
||||||
light->setPriority(SGLight::LOW);
|
|
||||||
|
|
||||||
#define SGLIGHT_GET_COLOR_VALUE(n) \
|
|
||||||
osg::Vec4(configNode->getFloatValue(n "/r"), \
|
|
||||||
configNode->getFloatValue(n "/g"), \
|
|
||||||
configNode->getFloatValue(n "/b"), \
|
|
||||||
configNode->getFloatValue(n "/a"))
|
|
||||||
light->setAmbient(SGLIGHT_GET_COLOR_VALUE("ambient"));
|
|
||||||
light->setDiffuse(SGLIGHT_GET_COLOR_VALUE("diffuse"));
|
|
||||||
light->setSpecular(SGLIGHT_GET_COLOR_VALUE("specular"));
|
|
||||||
#undef SGLIGHT_GET_COLOR_VALUE
|
|
||||||
|
|
||||||
light->setConstantAttenuation(configNode->getFloatValue("attenuation/c"));
|
|
||||||
light->setLinearAttenuation(configNode->getFloatValue("attenuation/l"));
|
|
||||||
light->setQuadraticAttenuation(configNode->getFloatValue("attenuation/q"));
|
|
||||||
|
|
||||||
light->setSpotExponent(configNode->getFloatValue("spot-exponent"));
|
|
||||||
light->setSpotCutoff(configNode->getFloatValue("spot-cutoff"));
|
|
||||||
|
|
||||||
osg::MatrixTransform *align = new osg::MatrixTransform;
|
osg::MatrixTransform *align = new osg::MatrixTransform;
|
||||||
|
|
||||||
|
SGLight *light = new SGLight(align);
|
||||||
align->addChild(light);
|
align->addChild(light);
|
||||||
|
|
||||||
osg::Matrix t;
|
//-- copy config to prop tree --
|
||||||
osg::Vec3 pos(configNode->getFloatValue("position/x-m"),
|
const std::string propPath {"/scenery/lights"};
|
||||||
configNode->getFloatValue("position/y-m"),
|
const std::string propName {"light"};
|
||||||
configNode->getFloatValue("position/z-m"));
|
SGPropertyNode *_pConfig = simgear::getPropertyRoot()->getNode(propPath, true)
|
||||||
t.makeTranslate(pos);
|
->addChild(propName);
|
||||||
|
configNode->copy(_pConfig);
|
||||||
osg::Matrix r;
|
|
||||||
if (const SGPropertyNode *dirNode = configNode->getNode("direction")) {
|
//-- setup osg::NodeCallback --
|
||||||
if (dirNode->hasValue("pitch-deg")) {
|
|
||||||
r.makeRotate(
|
|
||||||
dirNode->getFloatValue("pitch-deg")*SG_DEGREES_TO_RADIANS,
|
|
||||||
osg::Vec3(0, 1, 0),
|
|
||||||
dirNode->getFloatValue("roll-deg")*SG_DEGREES_TO_RADIANS,
|
|
||||||
osg::Vec3(1, 0, 0),
|
|
||||||
dirNode->getFloatValue("heading-deg")*SG_DEGREES_TO_RADIANS,
|
|
||||||
osg::Vec3(0, 0, 1));
|
|
||||||
} else if (dirNode->hasValue("lookat-x-m")) {
|
|
||||||
osg::Vec3 lookAt(dirNode->getFloatValue("lookat-x-m"),
|
|
||||||
dirNode->getFloatValue("lookat-y-m"),
|
|
||||||
dirNode->getFloatValue("lookat-z-m"));
|
|
||||||
osg::Vec3 dir = lookAt - pos;
|
|
||||||
r.makeRotate(osg::Vec3(0, 0, -1), dir);
|
|
||||||
} else {
|
|
||||||
r.makeRotate(osg::Vec3(0, 0, -1),
|
|
||||||
osg::Vec3(dirNode->getFloatValue("x"),
|
|
||||||
dirNode->getFloatValue("y"),
|
|
||||||
dirNode->getFloatValue("z")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
align->setMatrix(r * t);
|
|
||||||
|
|
||||||
const SGPropertyNode *dim_factor = configNode->getChild("dim-factor");
|
const SGPropertyNode *dim_factor = configNode->getChild("dim-factor");
|
||||||
if (dim_factor) {
|
if (dim_factor) {
|
||||||
const SGExpressiond *expression =
|
const SGExpressiond *expression =
|
||||||
read_value(dim_factor, modelRoot, "", 0, 1);
|
read_value(dim_factor, modelRoot, "", 0, 1);
|
||||||
if (expression) {
|
if (expression)
|
||||||
light->setUpdateCallback(
|
light->setUpdateCallback(new SGLight::UpdateCallback(expression));
|
||||||
new SGLight::UpdateCallback(expression,
|
|
||||||
light->getAmbient(),
|
|
||||||
light->getDiffuse(),
|
|
||||||
light->getSpecular()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
//need UpdateCallback to activate config changes at runtime
|
||||||
|
light->setUpdateCallback(new SGLight::UpdateCallback());
|
||||||
|
}
|
||||||
|
|
||||||
|
//-- configure light and add listener to conf in prop tree
|
||||||
|
light->configure(configNode);
|
||||||
|
_pConfig->addChangeListener(new SGLightConfigListener(light), true);
|
||||||
|
|
||||||
|
//-- debug visualisation --
|
||||||
osg::Shape *debug_shape = nullptr;
|
osg::Shape *debug_shape = nullptr;
|
||||||
if (light->getType() == SGLight::Type::POINT) {
|
if (light->getType() == SGLight::Type::POINT) {
|
||||||
debug_shape = new osg::Sphere(osg::Vec3(0, 0, 0), light->getRange());
|
debug_shape = new osg::Sphere(osg::Vec3(0, 0, 0), light->getRange());
|
||||||
@@ -165,7 +140,9 @@ SGLight::appendLight(const SGPropertyNode *configNode,
|
|||||||
simgear::getPropertyRoot()->getNode("/sim/debug/show-light-volumes", true)->
|
simgear::getPropertyRoot()->getNode("/sim/debug/show-light-volumes", true)->
|
||||||
addChangeListener(new SGLightDebugListener(debug_switch), true);
|
addChangeListener(new SGLightDebugListener(debug_switch), true);
|
||||||
align->addChild(debug_switch);
|
align->addChild(debug_switch);
|
||||||
|
//-- end debug visualisation --
|
||||||
|
|
||||||
|
SGConstPropertyNode_ptr p;
|
||||||
if ((p = configNode->getNode("name")) != NULL)
|
if ((p = configNode->getNode("name")) != NULL)
|
||||||
align->setName(p->getStringValue());
|
align->setName(p->getStringValue());
|
||||||
else
|
else
|
||||||
@@ -174,21 +151,16 @@ SGLight::appendLight(const SGPropertyNode *configNode,
|
|||||||
return align;
|
return align;
|
||||||
}
|
}
|
||||||
|
|
||||||
SGLight::SGLight() :
|
SGLight::SGLight()
|
||||||
_type(Type::POINT),
|
|
||||||
_range(0.0f),
|
|
||||||
_priority(Priority::LOW)
|
|
||||||
{
|
{
|
||||||
// Default values taken from osg::Light
|
// Default values taken from osg::Light
|
||||||
// They don't matter anyway as they are overwritten by the XML config values
|
// They don't matter anyway as they are overwritten by the XML config values
|
||||||
|
|
||||||
|
//TODO: can this be moved to initalizer in hxx?
|
||||||
_ambient.set(0.05f, 0.05f, 0.05f, 1.0f);
|
_ambient.set(0.05f, 0.05f, 0.05f, 1.0f);
|
||||||
_diffuse.set(0.8f, 0.8f, 0.8f, 1.0f);
|
_diffuse.set(0.8f, 0.8f, 0.8f, 1.0f);
|
||||||
_specular.set(0.05f, 0.05f, 0.05f, 1.0f);
|
_specular.set(0.05f, 0.05f, 0.05f, 1.0f);
|
||||||
_constant_attenuation = 1.0f;
|
|
||||||
_linear_attenuation = 0.0f;
|
|
||||||
_quadratic_attenuation = 0.0f;
|
|
||||||
_spot_exponent = 0.0f;
|
|
||||||
_spot_cutoff = 180.0f;
|
|
||||||
// Do not let OSG cull lights by default, we usually leave that job to
|
// Do not let OSG cull lights by default, we usually leave that job to
|
||||||
// other algorithms, like clustered shading.
|
// other algorithms, like clustered shading.
|
||||||
setCullingActive(false);
|
setCullingActive(false);
|
||||||
@@ -198,3 +170,73 @@ SGLight::~SGLight()
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SGLight::configure(const SGPropertyNode *configNode)
|
||||||
|
{
|
||||||
|
SGConstPropertyNode_ptr p;
|
||||||
|
if((p = configNode->getNode("type")) != NULL) {
|
||||||
|
std::string type = p->getStringValue();
|
||||||
|
if (type == "point")
|
||||||
|
setType(SGLight::Type::POINT);
|
||||||
|
else if (type == "spot")
|
||||||
|
setType(SGLight::Type::SPOT);
|
||||||
|
else
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "ignoring unknown light type '" << type << "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string priority = configNode->getStringValue("priority", "low");
|
||||||
|
if (priority == "high")
|
||||||
|
setPriority(SGLight::HIGH);
|
||||||
|
else if (priority == "medium")
|
||||||
|
setPriority(SGLight::MEDIUM);
|
||||||
|
|
||||||
|
setRange(configNode->getFloatValue("range-m"));
|
||||||
|
|
||||||
|
#define SGLIGHT_GET_COLOR_VALUE(n) \
|
||||||
|
osg::Vec4(configNode->getFloatValue(n "/r"), \
|
||||||
|
configNode->getFloatValue(n "/g"), \
|
||||||
|
configNode->getFloatValue(n "/b"), \
|
||||||
|
configNode->getFloatValue(n "/a"))
|
||||||
|
setAmbient(SGLIGHT_GET_COLOR_VALUE("ambient"));
|
||||||
|
setDiffuse(SGLIGHT_GET_COLOR_VALUE("diffuse"));
|
||||||
|
setSpecular(SGLIGHT_GET_COLOR_VALUE("specular"));
|
||||||
|
#undef SGLIGHT_GET_COLOR_VALUE
|
||||||
|
|
||||||
|
setConstantAttenuation(configNode->getFloatValue("attenuation/c"));
|
||||||
|
setLinearAttenuation(configNode->getFloatValue("attenuation/l"));
|
||||||
|
setQuadraticAttenuation(configNode->getFloatValue("attenuation/q"));
|
||||||
|
|
||||||
|
setSpotExponent(configNode->getFloatValue("spot-exponent"));
|
||||||
|
setSpotCutoff(configNode->getFloatValue("spot-cutoff"));
|
||||||
|
|
||||||
|
osg::Matrix t;
|
||||||
|
osg::Vec3 pos(configNode->getFloatValue("position/x-m"),
|
||||||
|
configNode->getFloatValue("position/y-m"),
|
||||||
|
configNode->getFloatValue("position/z-m"));
|
||||||
|
t.makeTranslate(pos);
|
||||||
|
|
||||||
|
osg::Matrix r;
|
||||||
|
if (const SGPropertyNode *dirNode = configNode->getNode("direction")) {
|
||||||
|
if (dirNode->hasValue("pitch-deg")) {
|
||||||
|
r.makeRotate(
|
||||||
|
dirNode->getFloatValue("pitch-deg")*SG_DEGREES_TO_RADIANS,
|
||||||
|
osg::Vec3(0, 1, 0),
|
||||||
|
dirNode->getFloatValue("roll-deg")*SG_DEGREES_TO_RADIANS,
|
||||||
|
osg::Vec3(1, 0, 0),
|
||||||
|
dirNode->getFloatValue("heading-deg")*SG_DEGREES_TO_RADIANS,
|
||||||
|
osg::Vec3(0, 0, 1));
|
||||||
|
} else if (dirNode->hasValue("lookat-x-m")) {
|
||||||
|
osg::Vec3 lookAt(dirNode->getFloatValue("lookat-x-m"),
|
||||||
|
dirNode->getFloatValue("lookat-y-m"),
|
||||||
|
dirNode->getFloatValue("lookat-z-m"));
|
||||||
|
osg::Vec3 dir = lookAt - pos;
|
||||||
|
r.makeRotate(osg::Vec3(0, 0, -1), dir);
|
||||||
|
} else {
|
||||||
|
r.makeRotate(osg::Vec3(0, 0, -1),
|
||||||
|
osg::Vec3(dirNode->getFloatValue("x"),
|
||||||
|
dirNode->getFloatValue("y"),
|
||||||
|
dirNode->getFloatValue("z")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_transform) _transform->setMatrix(r * t);
|
||||||
|
}
|
||||||
@@ -38,12 +38,20 @@ public:
|
|||||||
|
|
||||||
class UpdateCallback : public osg::NodeCallback {
|
class UpdateCallback : public osg::NodeCallback {
|
||||||
public:
|
public:
|
||||||
UpdateCallback(const SGExpressiond *expression,
|
UpdateCallback(const SGExpressiond *expression) : _expression(expression) {}
|
||||||
osg::Vec4 ambient, osg::Vec4 diffuse, osg::Vec4 specular) :
|
UpdateCallback() {}
|
||||||
_expression(expression),
|
|
||||||
_ambient(ambient), _diffuse(diffuse), _specular(specular) {}
|
void configure(const osg::Vec4 ambient, const osg::Vec4 diffuse, const osg::Vec4 specular) {
|
||||||
|
_ambient = ambient;
|
||||||
|
_diffuse = diffuse;
|
||||||
|
_specular = specular;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void operator()(osg::Node *node, osg::NodeVisitor *nv) {
|
virtual void operator()(osg::Node *node, osg::NodeVisitor *nv) {
|
||||||
double value = _expression->getValue();
|
double value = 1;
|
||||||
|
if (_expression) {
|
||||||
|
value = _expression->getValue();
|
||||||
|
}
|
||||||
if (value != _prev_value) {
|
if (value != _prev_value) {
|
||||||
SGLight *light = dynamic_cast<SGLight *>(node);
|
SGLight *light = dynamic_cast<SGLight *>(node);
|
||||||
if (light) {
|
if (light) {
|
||||||
@@ -51,30 +59,18 @@ public:
|
|||||||
light->setDiffuse(_diffuse * value);
|
light->setDiffuse(_diffuse * value);
|
||||||
light->setSpecular(_specular * value);
|
light->setSpecular(_specular * value);
|
||||||
}
|
}
|
||||||
|
_prev_value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
SGSharedPtr<SGExpressiond const> _expression;
|
SGSharedPtr<SGExpressiond const> _expression {nullptr};
|
||||||
osg::Vec4 _ambient, _diffuse, _specular;
|
osg::Vec4 _ambient, _diffuse, _specular;
|
||||||
double _prev_value = -1.0;
|
double _prev_value = -1.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
SGLight();
|
SGLight();
|
||||||
|
SGLight(const SGLight& l, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
|
||||||
SGLight(const SGLight& l,
|
SGLight(osg::MatrixTransform *transform) : SGLight() { _transform = transform; };
|
||||||
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) :
|
|
||||||
osg::Node(l, copyop),
|
|
||||||
_type(l._type),
|
|
||||||
_range(l._range),
|
|
||||||
_ambient(l._ambient),
|
|
||||||
_diffuse(l._diffuse),
|
|
||||||
_specular(l._specular),
|
|
||||||
_constant_attenuation(l._constant_attenuation),
|
|
||||||
_linear_attenuation(l._linear_attenuation),
|
|
||||||
_quadratic_attenuation(l._quadratic_attenuation),
|
|
||||||
_spot_exponent(l._spot_exponent),
|
|
||||||
_spot_cutoff(l._spot_cutoff)
|
|
||||||
{}
|
|
||||||
|
|
||||||
META_Node(simgear, SGLight);
|
META_Node(simgear, SGLight);
|
||||||
|
|
||||||
@@ -82,6 +78,8 @@ public:
|
|||||||
SGPropertyNode *modelRoot,
|
SGPropertyNode *modelRoot,
|
||||||
const osgDB::Options *options);
|
const osgDB::Options *options);
|
||||||
|
|
||||||
|
void configure(const SGPropertyNode *config_root);
|
||||||
|
|
||||||
void setType(Type type) { _type = type; }
|
void setType(Type type) { _type = type; }
|
||||||
Type getType() const { return _type; }
|
Type getType() const { return _type; }
|
||||||
|
|
||||||
@@ -118,21 +116,21 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
virtual ~SGLight();
|
virtual ~SGLight();
|
||||||
|
|
||||||
Type _type;
|
Type _type {Type::POINT};
|
||||||
|
|
||||||
float _range;
|
float _range {0.0f};
|
||||||
|
|
||||||
osg::Vec4 _ambient;
|
osg::Vec4 _ambient;
|
||||||
osg::Vec4 _diffuse;
|
osg::Vec4 _diffuse;
|
||||||
osg::Vec4 _specular;
|
osg::Vec4 _specular;
|
||||||
|
|
||||||
float _constant_attenuation;
|
float _constant_attenuation {1.0f};
|
||||||
float _linear_attenuation;
|
float _linear_attenuation {0.0f};
|
||||||
float _quadratic_attenuation;
|
float _quadratic_attenuation {0.0f};
|
||||||
float _spot_exponent;
|
float _spot_exponent {0.0f};
|
||||||
float _spot_cutoff;
|
float _spot_cutoff {180.0f};
|
||||||
|
Priority _priority {Priority::LOW};
|
||||||
Priority _priority;
|
osg::MatrixTransform *_transform {nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<osg::ref_ptr<SGLight>> SGLightList;
|
typedef std::vector<osg::ref_ptr<SGLight>> SGLightList;
|
||||||
|
|||||||
@@ -56,13 +56,8 @@ SGLightAnimation::SGLightAnimation(simgear::SGTransientModelData &modelData) :
|
|||||||
if (dim_factor) {
|
if (dim_factor) {
|
||||||
const SGExpressiond *expression =
|
const SGExpressiond *expression =
|
||||||
read_value(dim_factor, modelData.getModelRoot(), "", 0, 1);
|
read_value(dim_factor, modelData.getModelRoot(), "", 0, 1);
|
||||||
if (expression) {
|
if (expression)
|
||||||
light->setUpdateCallback(
|
light->setUpdateCallback(new SGLight::UpdateCallback(expression));
|
||||||
new SGLight::UpdateCallback(expression,
|
|
||||||
light->getAmbient(),
|
|
||||||
light->getDiffuse(),
|
|
||||||
light->getSpecular()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
align->setName(getConfig()->getStringValue("name"));
|
align->setName(getConfig()->getStringValue("name"));
|
||||||
|
|||||||
Reference in New Issue
Block a user