From c54ee16748390b3bb0775b0508be6135ecf357b9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 21:44:01 +0100 Subject: [PATCH] Add AlphaController and MaterialColorController --- components/nifosg/controller.cpp | 39 +++++++++ components/nifosg/controller.hpp | 24 ++++++ components/nifosg/nifloader.cpp | 137 ++++++++++++++++++------------- components/nifosg/nifloader.hpp | 4 + 4 files changed, 148 insertions(+), 56 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 086e679d6..8ac7f004c 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -2,8 +2,11 @@ #include #include +#include #include +#include + #include namespace NifOsg @@ -271,5 +274,41 @@ void VisControllerValue::setValue(float time) mNode->setNodeMask(vis ? ~0 : 0); } +AlphaControllerValue::AlphaControllerValue(osg::StateSet *target, const Nif::NiFloatData *data) + : mTarget(target) + , mData(data->mKeyList) +{ +} + +void AlphaControllerValue::setValue(float time) +{ + float value = interpKey(mData.mKeys, time); + osg::Material* mat = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::MATERIAL)); + if (!mat) + return; + + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.a() = value; + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); +} + +MaterialColorControllerValue::MaterialColorControllerValue(osg::StateSet *target, const Nif::NiPosData *data) + : mTarget(target), mData(data->mKeyList) +{ + +} + +void MaterialColorControllerValue::setValue(float time) +{ + osg::Vec3f value = interpKey(mData.mKeys, time); + osg::Material* mat = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::MATERIAL)); + if (!mat) + return; + + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); +} + } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index d916f894f..af09bda64 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -193,6 +193,30 @@ namespace NifOsg virtual void setValue(float time); }; + class AlphaControllerValue : public ControllerValue, public ValueInterpolator + { + private: + osg::StateSet* mTarget; + Nif::FloatKeyMap mData; + + public: + AlphaControllerValue(osg::StateSet* target, const Nif::NiFloatData *data); + + virtual void setValue(float time); + }; + + class MaterialColorControllerValue : public ControllerValue, public ValueInterpolator + { + private: + osg::StateSet* mTarget; + Nif::Vector3KeyMap mData; + + public: + MaterialColorControllerValue(osg::StateSet* target, const Nif::NiPosData *data); + + virtual void setValue(float time); + }; + } #endif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index abeb17b6f..ebc4911c8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -113,61 +113,6 @@ namespace collectMaterialProperties(nifNode->parent, out); } - void updateMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors) - { - int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty - osg::Material* mat = new osg::Material; - mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); - for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) - { - const Nif::Property* property = *it; - switch (property->recType) - { - case Nif::RC_NiSpecularProperty: - { - specFlags = property->flags; - break; - } - case Nif::RC_NiMaterialProperty: - { - const Nif::NiMaterialProperty* matprop = static_cast(property); - - mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.diffuse, matprop->data.alpha)); - mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.ambient, 1.f)); - mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.emissive, 1.f)); - - mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.specular, 1.f)); - mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); - - break; - } - case Nif::RC_NiVertexColorProperty: - { - const Nif::NiVertexColorProperty* vertprop = static_cast(property); - if (!hasVertexColors) - break; - switch (vertprop->flags) - { - case 0: - mat->setColorMode(osg::Material::OFF); - break; - case 1: - mat->setColorMode(osg::Material::EMISSION); - break; - case 2: - mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); - break; - } - } - } - } - - if (specFlags == 0) - mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f)); - - stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); - } - // NodeCallback used to update the bone matrices in skeleton space as needed for skinning. class UpdateBone : public osg::NodeCallback { @@ -438,6 +383,27 @@ namespace NifOsg } } + void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::StateSet *stateset) + { + for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (ctrl->recType == Nif::RC_NiAlphaController) + { + const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); + boost::shared_ptr dest(new AlphaControllerValue(stateset, alphactrl->data.getPtr())); + createController(alphactrl, dest, 0); + } + else if (ctrl->recType == Nif::RC_NiMaterialColorController) + { + const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); + boost::shared_ptr dest(new MaterialColorControllerValue(stateset, matctrl->data.getPtr())); + createController(matctrl, dest, 0); + } + else + std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; + } + } + void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -518,7 +484,7 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector materialProps; collectMaterialProperties(triShape, materialProps); - updateMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty()); + applyMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty()); } void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures) @@ -761,4 +727,63 @@ namespace NifOsg break; } } + + void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors) + { + int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty + osg::Material* mat = new osg::Material; + mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); + // TODO: check if the OpenGL default material values are actually the default NIF material values, for when there's no NiMaterialProperty + for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) + { + const Nif::Property* property = *it; + switch (property->recType) + { + case Nif::RC_NiSpecularProperty: + { + specFlags = property->flags; + break; + } + case Nif::RC_NiMaterialProperty: + { + const Nif::NiMaterialProperty* matprop = static_cast(property); + + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.diffuse, matprop->data.alpha)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.ambient, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.emissive, 1.f)); + + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(matprop->data.specular, 1.f)); + mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); + + if (!matprop->controller.empty()) + handleMaterialControllers(matprop, stateset); + + break; + } + case Nif::RC_NiVertexColorProperty: + { + const Nif::NiVertexColorProperty* vertprop = static_cast(property); + if (!hasVertexColors) + break; + switch (vertprop->flags) + { + case 0: + mat->setColorMode(osg::Material::OFF); + break; + case 1: + mat->setColorMode(osg::Material::EMISSION); + break; + case 2: + mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + break; + } + } + } + } + + if (specFlags == 0) + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f)); + + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + } } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index a089f7651..3b2443eb9 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -56,6 +56,8 @@ namespace NifOsg void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode); + void handleMaterialControllers(const Nif::Property* materialProperty, osg::StateSet* stateset); + void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, osg::Node* node, std::map& boundTextures); @@ -71,6 +73,8 @@ namespace NifOsg // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures); + void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors); + void createController(const Nif::Controller* ctrl, boost::shared_ptr value, int animflags); Nif::NIFFilePtr mNif;