412 lines
16 KiB
C++
412 lines
16 KiB
C++
/*
|
|
This file is part of Mitsuba, a physically based rendering system.
|
|
|
|
Copyright (c) 2007-2012 by Wenzel Jakob and others.
|
|
|
|
Mitsuba is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License Version 3
|
|
as published by the Free Software Foundation.
|
|
|
|
Mitsuba 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <mitsuba/core/properties.h>
|
|
#include <mitsuba/core/netobject.h>
|
|
#include <mitsuba/core/track.h>
|
|
|
|
/* Keep the boost::variant includes outside of properties.h,
|
|
since they noticeably add to the overall compile times */
|
|
#include <boost/variant.hpp>
|
|
|
|
MTS_NAMESPACE_BEGIN
|
|
|
|
typedef boost::variant<
|
|
bool, int64_t, Float, Point, Vector, Transform, AnimatedTransform *,
|
|
Spectrum, std::string, Properties::Data> ElementData;
|
|
|
|
struct PropertyElement {
|
|
ElementData data;
|
|
mutable bool queried;
|
|
};
|
|
|
|
#define DEFINE_PROPERTY_ACCESSOR(Type, BaseType, TypeName, ReadableName) \
|
|
void Properties::set##TypeName(const std::string &name, const Type &value, bool warnDuplicates) { \
|
|
if (hasProperty(name) && warnDuplicates) \
|
|
SLog(EWarn, "Property \"%s\" was specified multiple times!", name.c_str()); \
|
|
(*m_elements)[name].data = (BaseType) value; \
|
|
(*m_elements)[name].queried = false; \
|
|
} \
|
|
\
|
|
Type Properties::get##TypeName(const std::string &name) const { \
|
|
std::map<std::string, PropertyElement>::const_iterator it = m_elements->find(name); \
|
|
if (it == m_elements->end()) \
|
|
SLog(EError, "Property \"%s\" has not been specified!", name.c_str()); \
|
|
const BaseType *result = boost::get<BaseType>(&it->second.data); \
|
|
if (!result) \
|
|
SLog(EError, "The property \"%s\" has the wrong type (expected <" #ReadableName ">). The " \
|
|
"complete property record is :\n%s", name.c_str(), toString().c_str()); \
|
|
it->second.queried = true; \
|
|
return (Type) *result; \
|
|
} \
|
|
\
|
|
Type Properties::get##TypeName(const std::string &name, const Type &defVal) const { \
|
|
std::map<std::string, PropertyElement>::const_iterator it = m_elements->find(name); \
|
|
if (it == m_elements->end()) \
|
|
return defVal; \
|
|
const BaseType *result = boost::get<BaseType>(&it->second.data); \
|
|
if (!result) \
|
|
SLog(EError, "The property \"%s\" has the wrong type (expected <" #ReadableName ">). The " \
|
|
"complete property record is :\n%s", name.c_str(), toString().c_str()); \
|
|
it->second.queried = true; \
|
|
return (Type) *result; \
|
|
}
|
|
|
|
DEFINE_PROPERTY_ACCESSOR(bool, bool, Boolean, boolean)
|
|
DEFINE_PROPERTY_ACCESSOR(int64_t, int64_t, Long, integer)
|
|
DEFINE_PROPERTY_ACCESSOR(int, int64_t, Integer, integer)
|
|
DEFINE_PROPERTY_ACCESSOR(size_t, int64_t, Size, integer)
|
|
DEFINE_PROPERTY_ACCESSOR(Float, Float, Float, float)
|
|
DEFINE_PROPERTY_ACCESSOR(Point, Point, Point, point)
|
|
DEFINE_PROPERTY_ACCESSOR(Vector, Vector, Vector, vector)
|
|
DEFINE_PROPERTY_ACCESSOR(Transform, Transform, Transform, transform)
|
|
DEFINE_PROPERTY_ACCESSOR(Spectrum, Spectrum, Spectrum, spectrum)
|
|
DEFINE_PROPERTY_ACCESSOR(std::string, std::string, String, string)
|
|
DEFINE_PROPERTY_ACCESSOR(Properties::Data, Properties::Data, Data, data)
|
|
|
|
void Properties::setAnimatedTransform(const std::string &name, const AnimatedTransform *value, bool warnDuplicates) {
|
|
if (hasProperty(name)) {
|
|
AnimatedTransform **old = boost::get<AnimatedTransform *>(&((*m_elements)[name].data));
|
|
if (old)
|
|
(*old)->decRef();
|
|
if (warnDuplicates)
|
|
SLog(EWarn, "Property \"%s\" was specified multiple times!", name.c_str());
|
|
}
|
|
(*m_elements)[name].data = (AnimatedTransform *) value;
|
|
(*m_elements)[name].queried = false;
|
|
value->incRef();
|
|
}
|
|
|
|
ref<const AnimatedTransform> Properties::getAnimatedTransform(const std::string &name) const {
|
|
std::map<std::string, PropertyElement>::const_iterator it = m_elements->find(name);
|
|
if (it == m_elements->end())
|
|
SLog(EError, "Property \"%s\" missing", name.c_str());
|
|
const AnimatedTransform * const * result1 = boost::get<AnimatedTransform *>(&it->second.data);
|
|
const Transform *result2 = boost::get<Transform>(&it->second.data);
|
|
|
|
if (!result1 && !result2)
|
|
SLog(EError, "The property \"%s\" has the wrong type (expected <atransform> or <transform>). The "
|
|
"complete property record is :\n%s", name.c_str(), toString().c_str());
|
|
it->second.queried = true;
|
|
|
|
if (result1)
|
|
return *result1;
|
|
else
|
|
return new AnimatedTransform(*result2);
|
|
}
|
|
|
|
ref<const AnimatedTransform> Properties::getAnimatedTransform(const std::string &name, const AnimatedTransform *defVal) const {
|
|
std::map<std::string, PropertyElement>::const_iterator it = m_elements->find(name);
|
|
if (it == m_elements->end())
|
|
return defVal;
|
|
AnimatedTransform * const * result1 = boost::get<AnimatedTransform *>(&it->second.data);
|
|
const Transform *result2 = boost::get<Transform>(&it->second.data);
|
|
|
|
if (!result1 && !result2)
|
|
SLog(EError, "The property \"%s\" has the wrong type (expected <atransform> or <transform>). The "
|
|
"complete property record is :\n%s", name.c_str(), toString().c_str());
|
|
|
|
it->second.queried = true;
|
|
|
|
if (result1)
|
|
return *result1;
|
|
else
|
|
return new AnimatedTransform(*result2);
|
|
}
|
|
|
|
ref<const AnimatedTransform> Properties::getAnimatedTransform(const std::string &name, const Transform &defVal) const {
|
|
std::map<std::string, PropertyElement>::const_iterator it = m_elements->find(name);
|
|
if (it == m_elements->end())
|
|
return new AnimatedTransform(defVal);
|
|
|
|
AnimatedTransform * const * result1 = boost::get<AnimatedTransform *>(&it->second.data);
|
|
const Transform *result2 = boost::get<Transform>(&it->second.data);
|
|
|
|
if (!result1 && !result2)
|
|
SLog(EError, "The property \"%s\" has the wrong type (expected <atransform> or <transform>). The "
|
|
"complete property record is :\n%s", name.c_str(), toString().c_str());
|
|
it->second.queried = true;
|
|
|
|
if (result1)
|
|
return *result1;
|
|
else
|
|
return new AnimatedTransform(*result2);
|
|
}
|
|
|
|
namespace {
|
|
class TypeVisitor : public boost::static_visitor<Properties::EPropertyType> {
|
|
public:
|
|
Properties::EPropertyType operator()(const bool &) const { return Properties::EBoolean; }
|
|
Properties::EPropertyType operator()(const int64_t &) const { return Properties::EInteger; }
|
|
Properties::EPropertyType operator()(const Float &) const { return Properties::EFloat; }
|
|
Properties::EPropertyType operator()(const Point &) const { return Properties::EPoint; }
|
|
Properties::EPropertyType operator()(const Vector &) const { return Properties::EVector; }
|
|
Properties::EPropertyType operator()(const Transform &) const { return Properties::ETransform; }
|
|
Properties::EPropertyType operator()(const AnimatedTransform *) const { return Properties::EAnimatedTransform; }
|
|
Properties::EPropertyType operator()(const Spectrum &) const { return Properties::ESpectrum; }
|
|
Properties::EPropertyType operator()(const std::string &) const { return Properties::EString; }
|
|
Properties::EPropertyType operator()(const Properties::Data &) const { return Properties::EData; }
|
|
};
|
|
|
|
class EqualityVisitor : public boost::static_visitor<bool> {
|
|
public:
|
|
EqualityVisitor(const ElementData *ref) : ref(ref) { }
|
|
|
|
bool operator()(const bool &v) const { const bool *v2 = boost::get<bool>(ref); return v2 ? (v == *v2) : false; }
|
|
bool operator()(const int64_t &v) const { const int64_t *v2 = boost::get<int64_t>(ref); return v2 ? (v == *v2) : false; }
|
|
bool operator()(const Float &v) const { const Float *v2 = boost::get<Float>(ref); return v2 ? (v == *v2) : false; }
|
|
bool operator()(const Point &v) const { const Point *v2 = boost::get<Point>(ref); return v2 ? (v == *v2) : false; }
|
|
bool operator()(const Vector &v) const { const Vector *v2 = boost::get<Vector>(ref); return v2 ? (v == *v2) : false; }
|
|
bool operator()(const Transform &v) const { const Transform *v2 = boost::get<Transform>(ref); return v2 ? (v == *v2) : false; }
|
|
bool operator()(const AnimatedTransform *v) const { AnimatedTransform * const *v2 = boost::get<AnimatedTransform*>(ref); return v2 ? (v == *v2) : false; }
|
|
bool operator()(const Spectrum &v) const { const Spectrum *v2 = boost::get<Spectrum>(ref); return v2 ? (v == *v2) : false; }
|
|
bool operator()(const std::string &v) const { const std::string *v2 = boost::get<std::string>(ref); return v2 ? (v == *v2) : false; }
|
|
bool operator()(const Properties::Data &v) const { const Properties::Data *v2 = boost::get<Properties::Data>(ref); return v2 ? (v == *v2) : false; }
|
|
private:
|
|
const ElementData *ref;
|
|
};
|
|
|
|
class StringVisitor : public boost::static_visitor<void> {
|
|
public:
|
|
StringVisitor(std::ostringstream &oss, bool quote) : oss(oss), quote(quote) { }
|
|
|
|
void operator()(const bool &v) const { oss << (v ? "true" : "false"); }
|
|
void operator()(const int64_t &v) const { oss << v; }
|
|
void operator()(const Float &v) const { oss << v; }
|
|
void operator()(const Point &v) const { oss << v.toString(); }
|
|
void operator()(const Vector &v) const { oss << v.toString(); }
|
|
void operator()(const Transform &v) const { oss << v.toString(); }
|
|
void operator()(const AnimatedTransform *v) const { oss << ((Object *) v)->toString(); }
|
|
void operator()(const Spectrum &v) const { oss << v.toString(); }
|
|
void operator()(const std::string &v) const { oss << (quote ? "\"" : "") << v << (quote ? "\"" : ""); }
|
|
void operator()(const Properties::Data &v) const { oss << v.ptr << " (size=" << v.size << ")"; }
|
|
private:
|
|
std::ostringstream &oss;
|
|
bool quote;
|
|
};
|
|
}
|
|
|
|
Properties::Properties()
|
|
: m_id("unnamed") {
|
|
m_elements = new std::map<std::string, PropertyElement>();
|
|
}
|
|
|
|
Properties::Properties(const std::string &pluginName)
|
|
: m_pluginName(pluginName), m_id("unnamed") {
|
|
m_elements = new std::map<std::string, PropertyElement>();
|
|
}
|
|
|
|
Properties::Properties(const Properties &props)
|
|
: m_pluginName(props.m_pluginName), m_id(props.m_id) {
|
|
m_elements = new std::map<std::string, PropertyElement>(*props.m_elements);
|
|
|
|
for (std::map<std::string, PropertyElement>::iterator it = m_elements->begin();
|
|
it != m_elements->end(); ++it) {
|
|
AnimatedTransform **trafo = boost::get<AnimatedTransform *>(&(*it).second.data);
|
|
if (trafo)
|
|
(*trafo)->incRef();
|
|
}
|
|
}
|
|
|
|
Properties::~Properties() {
|
|
for (std::map<std::string, PropertyElement>::iterator it = m_elements->begin();
|
|
it != m_elements->end(); ++it) {
|
|
AnimatedTransform **trafo = boost::get<AnimatedTransform *>(&(*it).second.data);
|
|
if (trafo)
|
|
(*trafo)->decRef();
|
|
}
|
|
|
|
delete m_elements;
|
|
}
|
|
|
|
void Properties::operator=(const Properties &props) {
|
|
for (std::map<std::string, PropertyElement>::iterator it = m_elements->begin();
|
|
it != m_elements->end(); ++it) {
|
|
AnimatedTransform **trafo = boost::get<AnimatedTransform *>(&(*it).second.data);
|
|
if (trafo)
|
|
(*trafo)->decRef();
|
|
}
|
|
|
|
m_pluginName = props.m_pluginName;
|
|
m_id = props.m_id;
|
|
*m_elements = *props.m_elements;
|
|
|
|
for (std::map<std::string, PropertyElement>::iterator it = m_elements->begin();
|
|
it != m_elements->end(); ++it) {
|
|
AnimatedTransform **trafo = boost::get<AnimatedTransform *>(&(*it).second.data);
|
|
if (trafo)
|
|
(*trafo)->incRef();
|
|
}
|
|
}
|
|
|
|
bool Properties::hasProperty(const std::string &name) const {
|
|
return m_elements->find(name) != m_elements->end();
|
|
}
|
|
|
|
bool Properties::removeProperty(const std::string &name) {
|
|
std::map<std::string, PropertyElement>::iterator it = m_elements->find(name);
|
|
if (it == m_elements->end())
|
|
return false;
|
|
AnimatedTransform **trafo = boost::get<AnimatedTransform *>(&(*it).second.data);
|
|
if (trafo)
|
|
(*trafo)->decRef();
|
|
m_elements->erase(it);
|
|
return true;
|
|
}
|
|
|
|
std::vector<std::string> Properties::getUnqueried() const {
|
|
std::map<std::string, PropertyElement>::const_iterator it = m_elements->begin();
|
|
std::vector<std::string> result;
|
|
|
|
for (; it != m_elements->end(); ++it) {
|
|
if (!(*it).second.queried)
|
|
result.push_back((*it).first);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
Properties::EPropertyType Properties::getType(const std::string &name) const {
|
|
std::map<std::string, PropertyElement>::const_iterator it = m_elements->find(name);
|
|
if (it == m_elements->end())
|
|
SLog(EError, "Property \"%s\" has not been specified!", name.c_str());
|
|
|
|
return boost::apply_visitor(TypeVisitor(), it->second.data);
|
|
}
|
|
|
|
std::string Properties::getAsString(const std::string &name, const std::string &defVal) const {
|
|
if (m_elements->find(name) == m_elements->end())
|
|
return defVal;
|
|
return getAsString(name);
|
|
}
|
|
|
|
std::string Properties::getAsString(const std::string &name) const {
|
|
std::map<std::string, PropertyElement>::const_iterator it = m_elements->find(name);
|
|
if (it == m_elements->end())
|
|
SLog(EError, "Property \"%s\" has not been specified!", name.c_str());
|
|
|
|
std::ostringstream oss;
|
|
StringVisitor strVisitor(oss, false);
|
|
boost::apply_visitor(strVisitor, it->second.data);
|
|
it->second.queried = true;
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
std::string Properties::toString() const {
|
|
std::map<std::string, PropertyElement>::const_iterator it = m_elements->begin();
|
|
std::ostringstream oss;
|
|
StringVisitor strVisitor(oss, true);
|
|
|
|
oss << "Properties[" << endl
|
|
<< " pluginName = \"" << m_pluginName << "\"," << endl
|
|
<< " id = \"" << m_id << "\"," << endl
|
|
<< " elements = {" << endl;
|
|
while (it != m_elements->end()) {
|
|
oss << " \"" << (*it).first << "\" -> ";
|
|
const ElementData &data = (*it).second.data;
|
|
boost::apply_visitor(strVisitor, data);
|
|
if (++it != m_elements->end())
|
|
oss << ",";
|
|
oss << endl;
|
|
}
|
|
oss << " }" << endl
|
|
<< "]" << endl;
|
|
return oss.str();
|
|
}
|
|
|
|
void Properties::markQueried(const std::string &name) const {
|
|
std::map<std::string, PropertyElement>::const_iterator it = m_elements->find(name);
|
|
if (it == m_elements->end())
|
|
return;
|
|
it->second.queried = true;
|
|
}
|
|
|
|
bool Properties::wasQueried(const std::string &name) const {
|
|
std::map<std::string, PropertyElement>::const_iterator it = m_elements->find(name);
|
|
if (it == m_elements->end())
|
|
SLog(EError, "Could not find parameter \"%s\"!", name.c_str());
|
|
return it->second.queried;
|
|
}
|
|
|
|
void Properties::putPropertyNames(std::vector<std::string> &results) const {
|
|
for (std::map<std::string, PropertyElement>::const_iterator it = m_elements->begin();
|
|
it != m_elements->end(); ++it)
|
|
results.push_back((*it).first);
|
|
}
|
|
|
|
void Properties::copyAttribute(const Properties &properties,
|
|
const std::string &sourceName, const std::string &targetName) {
|
|
std::map<std::string, PropertyElement>::const_iterator it = properties.m_elements->find(sourceName);
|
|
if (it == properties.m_elements->end())
|
|
SLog(EError, "copyAttribute(): Could not find parameter \"%s\"!", sourceName.c_str());
|
|
m_elements->operator[](targetName) = it->second;
|
|
}
|
|
|
|
bool Properties::operator==(const Properties &p) const {
|
|
if (m_pluginName != p.m_pluginName || m_id != p.m_id || m_elements->size() != p.m_elements->size())
|
|
return false;
|
|
|
|
std::map<std::string, PropertyElement>::const_iterator it = m_elements->begin();
|
|
for (; it != m_elements->end(); ++it) {
|
|
const PropertyElement &first = it->second;
|
|
const PropertyElement &second = (*p.m_elements)[it->first];
|
|
|
|
if (!boost::apply_visitor(EqualityVisitor(&first.data), second.data))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
ConfigurableObject::ConfigurableObject(Stream *stream, InstanceManager *manager)
|
|
: SerializableObject(stream, manager) {
|
|
}
|
|
|
|
void ConfigurableObject::setParent(ConfigurableObject *parent) {
|
|
}
|
|
|
|
void ConfigurableObject::configure() {
|
|
}
|
|
|
|
void ConfigurableObject::serialize(Stream *stream, InstanceManager *manager) const {
|
|
if (!getClass()->isSerializable())
|
|
Log(EError, "Error: trying to serialize an instance of type '%s', which does "
|
|
"not have full serialization support!", getClass()->getName().c_str());
|
|
}
|
|
|
|
void ConfigurableObject::addChild(const std::string &name, ConfigurableObject *child) {
|
|
SLog(EError, "ConfigurableObject::addChild(\"%s\", %s) not implemented in \"%s\"",
|
|
name.c_str(), child->toString().c_str(), toString().c_str());
|
|
}
|
|
|
|
void NetworkedObject::serialize(Stream *stream, InstanceManager *manager) const {
|
|
ConfigurableObject::serialize(stream, manager);
|
|
}
|
|
|
|
void NetworkedObject::bindUsedResources(ParallelProcess *proc) const {
|
|
}
|
|
|
|
void NetworkedObject::wakeup(ConfigurableObject *,
|
|
std::map<std::string, SerializableObject *> &) {
|
|
}
|
|
|
|
MTS_IMPLEMENT_CLASS(ConfigurableObject, true, SerializableObject)
|
|
MTS_IMPLEMENT_CLASS(NetworkedObject, true, ConfigurableObject)
|
|
MTS_NAMESPACE_END
|