diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 4e21d33475..90069c2d8d 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -359,6 +359,7 @@ namespace MWRender stateset->setAttribute(m); stateset->addUniform(new osg::Uniform("colorMode", 0)); stateset->addUniform(new osg::Uniform("emissiveMult", 1.f)); + stateset->addUniform(new osg::Uniform("specStrength", 1.f)); node.setStateSet(stateset); } }; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 06bfb3582f..e0cd3f713a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -500,6 +500,7 @@ namespace MWRender defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); sceneRoot->getOrCreateStateSet()->setAttribute(defaultMat); sceneRoot->getOrCreateStateSet()->addUniform(new osg::Uniform("emissiveMult", 1.f)); + sceneRoot->getOrCreateStateSet()->addUniform(new osg::Uniform("specStrength", 1.f)); mFog.reset(new FogManager()); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 0b3c95ff45..5c0ead4ad0 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -61,7 +61,7 @@ add_component_dir (sceneutil ) add_component_dir (nif - controlled effect niftypes record controller extra node record_ptr data niffile property nifkey base nifstream + controlled effect niftypes record controller extra node record_ptr data niffile property nifkey base nifstream physics ) add_component_dir (nifosg diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index 704c4928e6..16e6b5e40f 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -270,6 +270,15 @@ namespace Nif nif->getUInt(); // Zero } + void NiControllerManager::read(NIFStream *nif) + { + Controller::read(nif); + mCumulative = nif->getBoolean(); + unsigned int numSequences = nif->getUInt(); + nif->skip(4 * numSequences); // Controller sequences + nif->skip(4); // Object palette + } + void NiPoint3Interpolator::read(NIFStream *nif) { defaultVal = nif->getVector3(); diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 503710fe90..210eaab217 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -184,6 +184,12 @@ struct bhkBlendController : public Controller void read(NIFStream *nif) override; }; +struct NiControllerManager : public Controller +{ + bool mCumulative; + void read(NIFStream *nif) override; +}; + struct Interpolator : public Record { }; struct NiPoint3Interpolator : public Interpolator diff --git a/components/nif/data.cpp b/components/nif/data.cpp index b6674611bc..cac924733d 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -34,6 +34,13 @@ void NiSkinInstance::post(NIFFile *nif) } } +void BSDismemberSkinInstance::read(NIFStream *nif) +{ + NiSkinInstance::read(nif); + unsigned int numPartitions = nif->getUInt(); + nif->skip(4 * numPartitions); // Body part information +} + void NiGeometryData::read(NIFStream *nif) { if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,114)) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index efbe138c53..70171ac47c 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -170,6 +170,11 @@ struct NiSkinInstance : public Record void post(NIFFile *nif) override; }; +struct BSDismemberSkinInstance : public NiSkinInstance +{ + void read(NIFStream *nif) override; +}; + struct NiSkinData : public Record { struct VertWeight diff --git a/components/nif/extra.cpp b/components/nif/extra.cpp index a45ea8c50b..04217995ac 100644 --- a/components/nif/extra.cpp +++ b/components/nif/extra.cpp @@ -94,4 +94,38 @@ void BSBound::read(NIFStream *nif) halfExtents = nif->getVector3(); } +void BSFurnitureMarker::LegacyFurniturePosition::read(NIFStream *nif) +{ + mOffset = nif->getVector3(); + mOrientation = nif->getUShort(); + mPositionRef = nif->getChar(); + nif->skip(1); // Position ref 2 +} + +void BSFurnitureMarker::FurniturePosition::read(NIFStream *nif) +{ + mOffset = nif->getVector3(); + mHeading = nif->getFloat(); + mType = nif->getUShort(); + mEntryPoint = nif->getUShort(); +} + +void BSFurnitureMarker::read(NIFStream *nif) +{ + Extra::read(nif); + unsigned int num = nif->getUInt(); + if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3) + { + mLegacyMarkers.resize(num); + for (auto& marker : mLegacyMarkers) + marker.read(nif); + } + else + { + mMarkers.resize(num); + for (auto& marker : mMarkers) + marker.read(nif); + } +} + } diff --git a/components/nif/extra.hpp b/components/nif/extra.hpp index f4ac1caff9..8eb14f9b01 100644 --- a/components/nif/extra.hpp +++ b/components/nif/extra.hpp @@ -120,5 +120,30 @@ struct BSBound : public Extra void read(NIFStream *nif) override; }; +struct BSFurnitureMarker : public Extra +{ + struct LegacyFurniturePosition + { + osg::Vec3f mOffset; + uint16_t mOrientation; + uint8_t mPositionRef; + void read(NIFStream *nif); + }; + + struct FurniturePosition + { + osg::Vec3f mOffset; + float mHeading; + uint16_t mType; + uint16_t mEntryPoint; + void read(NIFStream *nif); + }; + + std::vector mLegacyMarkers; + std::vector mMarkers; + + void read(NIFStream *nif) override; +}; + } // Namespace #endif diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 6863209988..24b9bbceed 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -136,6 +136,11 @@ static std::map makeFactory() factory["BSShaderProperty"] = {&construct , RC_BSShaderProperty }; factory["BSShaderPPLightingProperty"] = {&construct , RC_BSShaderPPLightingProperty }; factory["BSShaderNoLightingProperty"] = {&construct , RC_BSShaderNoLightingProperty }; + factory["BSFurnitureMarker"] = {&construct , RC_BSFurnitureMarker }; + factory["NiCollisionObject"] = {&construct , RC_NiCollisionObject }; + factory["bhkCollisionObject"] = {&construct , RC_bhkCollisionObject }; + factory["BSDismemberSkinInstance"] = {&construct , RC_BSDismemberSkinInstance }; + factory["NiControllerManager"] = {&construct , RC_NiControllerManager }; return factory; } diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 406a4d4549..c01ba9b663 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -8,6 +8,7 @@ #include "niftypes.hpp" #include "controller.hpp" #include "base.hpp" +#include "physics.hpp" #include @@ -143,6 +144,9 @@ struct Node : public Named bool hasBounds{false}; NiBoundingVolume bounds; + // Collision object info + NiCollisionObjectPtr collision; + void read(NIFStream *nif) override { Named::read(nif); @@ -160,7 +164,7 @@ struct Node : public Named bounds.read(nif); // Reference to the collision object in Gamebryo files. if (nif->getVersion() >= NIFStream::generateVersion(10,0,1,0)) - nif->skip(4); + collision.read(nif); parent = nullptr; @@ -171,6 +175,7 @@ struct Node : public Named { Named::post(nif); props.post(nif); + collision.post(nif); } // Parent node, or nullptr for the root node. As far as I'm aware, only diff --git a/components/nif/physics.cpp b/components/nif/physics.cpp new file mode 100644 index 0000000000..992a56c9b7 --- /dev/null +++ b/components/nif/physics.cpp @@ -0,0 +1,54 @@ +#include "physics.hpp" +#include "node.hpp" + +namespace Nif +{ + void bhkCollisionObject::read(NIFStream *nif) + { + NiCollisionObject::read(nif); + mFlags = nif->getUShort(); + mBody.read(nif); + } + + void bhkWorldObject::read(NIFStream *nif) + { + mShape.read(nif); + if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB_OLD) + nif->skip(4); // Unknown + mFlags = nif->getUInt(); + nif->skip(4); // Unused + mWorldObjectInfo.mPhaseType = nif->getChar(); + nif->skip(3); // Unused + mWorldObjectInfo.mData = nif->getUInt(); + mWorldObjectInfo.mSize = nif->getUInt(); + mWorldObjectInfo.mCapacityAndFlags = nif->getUInt(); + } + + void bhkWorldObject::post(NIFFile *nif) + { + mShape.post(nif); + } + + void bhkEntity::read(NIFStream *nif) + { + bhkWorldObject::read(nif); + mResponseType = static_cast(nif->getChar()); + nif->skip(1); // Unused + mProcessContactDelay = nif->getUShort(); + } + + void HavokMaterial::read(NIFStream *nif) + { + if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB_OLD) + nif->skip(4); // Unknown + mMaterial = nif->getUInt(); + } + + void hkSubPartData::read(NIFStream *nif) + { + mHavokFilter = nif->getUInt(); + mNumVertices = nif->getUInt(); + mHavokMaterial.read(nif); + } + +} // Namespace \ No newline at end of file diff --git a/components/nif/physics.hpp b/components/nif/physics.hpp new file mode 100644 index 0000000000..ca31512c71 --- /dev/null +++ b/components/nif/physics.hpp @@ -0,0 +1,90 @@ +#ifndef OPENMW_COMPONENTS_NIF_PHYSICS_HPP +#define OPENMW_COMPONENTS_NIF_PHYSICS_HPP + +#include "base.hpp" + +// This header contains certain record definitions +// specific to Bethesda implementation of Havok physics +namespace Nif +{ + +// Generic collision object +struct NiCollisionObject : public Record +{ + // The node that references this object + NodePtr mTarget; + + void read(NIFStream *nif) override + { + mTarget.read(nif); + } + void post(NIFFile *nif) override + { + mTarget.post(nif); + } +}; + +// Bethesda Havok-specific collision object +struct bhkCollisionObject : public NiCollisionObject +{ + unsigned short mFlags; + CollisionBodyPtr mBody; + + void read(NIFStream *nif) override; + void post(NIFFile *nif) override + { + NiCollisionObject::post(nif); + mBody.post(nif); + } +}; + +// Abstract Havok shape info record +struct bhkWorldObject : public Record +{ + bhkShapePtr mShape; + unsigned int mFlags; // Havok layer type, collision filter flags and group + struct WorldObjectInfo + { + unsigned char mPhaseType; + unsigned int mData; + unsigned int mSize; + unsigned int mCapacityAndFlags; + }; + WorldObjectInfo mWorldObjectInfo; + void read(NIFStream *nif) override; + void post(NIFFile *nif) override; +}; + +struct bhkShape : public Record {}; + +enum class hkResponseType : uint8_t +{ + Response_Invalid = 0, + Response_SimpleContact = 1, + Response_Reporting = 2, + Response_None = 3 +}; + +struct bhkEntity : public bhkWorldObject +{ + hkResponseType mResponseType; + unsigned short mProcessContactDelay; + void read(NIFStream *nif) override; +}; + +struct HavokMaterial +{ + unsigned int mMaterial; + void read(NIFStream *nif); +}; + +struct hkSubPartData +{ + HavokMaterial mHavokMaterial; + unsigned int mNumVertices; + unsigned int mHavokFilter; + void read(NIFStream *nif); +}; + +} // Namespace +#endif \ No newline at end of file diff --git a/components/nif/record.hpp b/components/nif/record.hpp index dc81eb69c7..0b9b2dc998 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -125,7 +125,12 @@ enum RecordType RC_BSLODTriShape, RC_BSShaderProperty, RC_BSShaderPPLightingProperty, - RC_BSShaderNoLightingProperty + RC_BSShaderNoLightingProperty, + RC_BSFurnitureMarker, + RC_NiCollisionObject, + RC_bhkCollisionObject, + RC_BSDismemberSkinInstance, + RC_NiControllerManager }; /// Base class for all records diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index b30d99fbe4..a25480fe43 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -148,6 +148,9 @@ struct BSShaderTextureSet; struct NiGeometryData; struct BSShaderProperty; struct NiAlphaProperty; +struct NiCollisionObject; +struct bhkWorldObject; +struct bhkShape; using NodePtr = RecordPtrT; using ExtraPtr = RecordPtrT; @@ -175,6 +178,9 @@ using BSShaderTextureSetPtr = RecordPtrT; using NiGeometryDataPtr = RecordPtrT; using BSShaderPropertyPtr = RecordPtrT; using NiAlphaPropertyPtr = RecordPtrT; +using NiCollisionObjectPtr = RecordPtrT; +using CollisionBodyPtr = RecordPtrT; +using bhkShapePtr = RecordPtrT; using NodeList = RecordListT; using PropertyList = RecordListT; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a745d50eda..e46e2d934b 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1932,6 +1932,7 @@ namespace NifOsg int lightmode = 1; float emissiveMult = 1.f; + float specStrength = 1.f; for (const Nif::Property* property : properties) { @@ -2081,6 +2082,8 @@ namespace NifOsg stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); if (emissiveMult != 1.f) stateset->addUniform(new osg::Uniform("emissiveMult", emissiveMult)); + if (specStrength != 1.f) + stateset->addUniform(new osg::Uniform("specStrength", specStrength)); } }; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 8a88f7def9..f6c041a879 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -524,6 +524,7 @@ namespace Resource result.getNode()->accept(colladaAlphaTrickVisitor); result.getNode()->getOrCreateStateSet()->addUniform(new osg::Uniform("emissiveMult", 1.f)); + result.getNode()->getOrCreateStateSet()->addUniform(new osg::Uniform("specStrength", 1.f)); result.getNode()->getOrCreateStateSet()->addUniform(new osg::Uniform("envMapColor", osg::Vec4f(1,1,1,1))); result.getNode()->getOrCreateStateSet()->addUniform(new osg::Uniform("useFalloff", false)); } diff --git a/files/shaders/nv_default_fragment.glsl b/files/shaders/nv_default_fragment.glsl index 17204534e3..ff81a2b94d 100644 --- a/files/shaders/nv_default_fragment.glsl +++ b/files/shaders/nv_default_fragment.glsl @@ -39,6 +39,7 @@ varying vec3 passNormal; #include "alpha.glsl" uniform float emissiveMult; +uniform float specStrength; void main() { @@ -80,7 +81,7 @@ void main() gl_FragData[0].xyz *= lighting; float shininess = gl_FrontMaterial.shininess; - vec3 matSpec = getSpecularColor().xyz; + vec3 matSpec = getSpecularColor().xyz * specStrength; #if @normalMap matSpec *= normalTex.a; #endif diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index d750a4dd1f..99ed44919b 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -71,6 +71,7 @@ centroid varying vec3 shadowDiffuseLighting; #else uniform float emissiveMult; #endif +uniform float specStrength; varying vec3 passViewPos; varying vec3 passNormal; @@ -204,6 +205,7 @@ void main() vec3 matSpec = getSpecularColor().xyz; #endif + matSpec *= specStrength; if (matSpec != vec3(0.0)) { #if (!@normalMap && !@parallax && !@forcePPL)