Merge branch 'master' of gitlab.com:openmw/openmw into rtdfix

macos_ci_fix
Zackhasacat 1 year ago
commit e7c9c57017

@ -109,6 +109,7 @@
Feature #7546: Start the game on Fredas Feature #7546: Start the game on Fredas
Feature #7568: Uninterruptable scripted music Feature #7568: Uninterruptable scripted music
Feature #7618: Show the player character's health in the save details Feature #7618: Show the player character's health in the save details
Feature #7634: Support NiParticleBomb
Task #5896: Do not use deprecated MyGUI properties Task #5896: Do not use deprecated MyGUI properties
Task #7113: Move from std::atoi to std::from_char Task #7113: Move from std::atoi to std::from_char
Task #7117: Replace boost::scoped_array with std::vector Task #7117: Replace boost::scoped_array with std::vector

@ -7,6 +7,7 @@
#include "../mwbase/scriptmanager.hpp" #include "../mwbase/scriptmanager.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwscript/globalscripts.hpp" #include "../mwscript/globalscripts.hpp"
#include "../mwworld/esmstore.hpp"
#include "object.hpp" #include "object.hpp"
@ -43,6 +44,10 @@ namespace sol
struct is_automagical<MWLua::MWScriptVariables> : std::false_type struct is_automagical<MWLua::MWScriptVariables> : std::false_type
{ {
}; };
template <>
struct is_automagical<ESM::Global> : std::false_type
{
};
} }
namespace MWLua namespace MWLua
@ -76,6 +81,7 @@ namespace MWLua
// api["getGlobalScripts"] = [](std::string_view recordId) -> list of scripts // api["getGlobalScripts"] = [](std::string_view recordId) -> list of scripts
// api["getLocalScripts"] = [](const GObject& obj) -> list of scripts // api["getLocalScripts"] = [](const GObject& obj) -> list of scripts
sol::state_view& lua = context.mLua->sol();
sol::usertype<MWScriptRef> mwscript = context.mLua->sol().new_usertype<MWScriptRef>("MWScript"); sol::usertype<MWScriptRef> mwscript = context.mLua->sol().new_usertype<MWScriptRef>("MWScript");
sol::usertype<MWScriptVariables> mwscriptVars sol::usertype<MWScriptVariables> mwscriptVars
= context.mLua->sol().new_usertype<MWScriptVariables>("MWScriptVariables"); = context.mLua->sol().new_usertype<MWScriptVariables>("MWScriptVariables");
@ -108,6 +114,51 @@ namespace MWLua
"No variable \"" + std::string(var) + "\" in mwscript " + s.mRef.mId.toDebugString()); "No variable \"" + std::string(var) + "\" in mwscript " + s.mRef.mId.toDebugString());
}; };
using GlobalStore = MWWorld::Store<ESM::Global>;
sol::usertype<GlobalStore> globalStoreT = lua.new_usertype<GlobalStore>("ESM3_GlobalStore");
const GlobalStore* globalStore = &MWBase::Environment::get().getWorld()->getStore().get<ESM::Global>();
globalStoreT[sol::meta_function::to_string] = [](const GlobalStore& store) {
return "ESM3_GlobalStore{" + std::to_string(store.getSize()) + " globals}";
};
globalStoreT[sol::meta_function::length] = [](const GlobalStore& store) { return store.getSize(); };
globalStoreT[sol::meta_function::index]
= sol::overload([](const GlobalStore& store, std::string_view globalId) -> sol::optional<float> {
auto g = store.search(ESM::RefId::deserializeText(globalId));
if (g == nullptr)
return sol::nullopt;
char varType = MWBase::Environment::get().getWorld()->getGlobalVariableType(globalId);
if (varType == 's' || varType == 'l')
{
return static_cast<float>(MWBase::Environment::get().getWorld()->getGlobalInt(globalId));
}
else
{
return MWBase::Environment::get().getWorld()->getGlobalFloat(globalId);
}
});
globalStoreT[sol::meta_function::new_index]
= sol::overload([](const GlobalStore& store, std::string_view globalId, float val) {
auto g = store.search(ESM::RefId::deserializeText(globalId));
if (g == nullptr)
return;
char varType = MWBase::Environment::get().getWorld()->getGlobalVariableType(globalId);
if (varType == 's' || varType == 'l')
{
MWBase::Environment::get().getWorld()->setGlobalInt(globalId, static_cast<int>(val));
}
else
{
MWBase::Environment::get().getWorld()->setGlobalFloat(globalId, val);
}
});
globalStoreT[sol::meta_function::pairs] = lua["ipairsForArray"].template get<sol::function>();
globalStoreT[sol::meta_function::ipairs] = lua["ipairsForArray"].template get<sol::function>();
api["getGlobalVariables"] = [globalStore](sol::optional<GObject> player) {
if (player.has_value() && player->ptr() != MWBase::Environment::get().getWorld()->getPlayerPtr())
throw std::runtime_error("First argument must either be a player or be missing");
return globalStore;
};
return LuaUtil::makeReadOnly(api); return LuaUtil::makeReadOnly(api);
} }

@ -92,15 +92,21 @@ namespace LuaUi
w->widget()->detachFromWidget(); w->widget()->detachFromWidget();
} }
void WidgetExtension::updateVisible()
{
// workaround for MyGUI bug
// parent visibility doesn't affect added children
MyGUI::Widget* widget = this->widget();
MyGUI::Widget* parent = widget->getParent();
bool inheritedVisible = widget->getVisible() && (parent == nullptr || parent->getInheritedVisible());
widget->setVisible(inheritedVisible);
}
void WidgetExtension::attach(WidgetExtension* ext) void WidgetExtension::attach(WidgetExtension* ext)
{ {
ext->mParent = this; ext->mParent = this;
ext->mTemplateChild = false; ext->mTemplateChild = false;
ext->widget()->attachToWidget(mSlot->widget()); ext->widget()->attachToWidget(mSlot->widget());
// workaround for MyGUI bug
// parent visibility doesn't affect added children
ext->widget()->setVisible(!ext->widget()->getVisible());
ext->widget()->setVisible(!ext->widget()->getVisible());
} }
void WidgetExtension::attachTemplate(WidgetExtension* ext) void WidgetExtension::attachTemplate(WidgetExtension* ext)
@ -108,10 +114,6 @@ namespace LuaUi
ext->mParent = this; ext->mParent = this;
ext->mTemplateChild = true; ext->mTemplateChild = true;
ext->widget()->attachToWidget(widget()); ext->widget()->attachToWidget(widget());
// workaround for MyGUI bug
// parent visibility doesn't affect added children
ext->widget()->setVisible(!ext->widget()->getVisible());
ext->widget()->setVisible(!ext->widget()->getVisible());
} }
WidgetExtension* WidgetExtension::findDeep(std::string_view flagName) WidgetExtension* WidgetExtension::findDeep(std::string_view flagName)
@ -256,6 +258,8 @@ namespace LuaUi
void WidgetExtension::updateCoord() void WidgetExtension::updateCoord()
{ {
updateVisible();
MyGUI::IntCoord oldCoord = mWidget->getCoord(); MyGUI::IntCoord oldCoord = mWidget->getCoord();
MyGUI::IntCoord newCoord = calculateCoord(); MyGUI::IntCoord newCoord = calculateCoord();

@ -173,6 +173,8 @@ namespace LuaUi
void focusLoss(MyGUI::Widget*, MyGUI::Widget*); void focusLoss(MyGUI::Widget*, MyGUI::Widget*);
std::optional<std::function<void(WidgetExtension*, MyGUI::IntCoord)>> mOnCoordChange; std::optional<std::function<void(WidgetExtension*, MyGUI::IntCoord)>> mOnCoordChange;
void updateVisible();
}; };
class LuaWidget : public MyGUI::Widget, public WidgetExtension class LuaWidget : public MyGUI::Widget, public WidgetExtension

@ -308,6 +308,7 @@ namespace Nif
// Modifiers, 4.0.0.2 // Modifiers, 4.0.0.2
{ "NiGravity", &construct<NiGravity, RC_NiGravity> }, { "NiGravity", &construct<NiGravity, RC_NiGravity> },
{ "NiParticleBomb", &construct<NiParticleBomb, RC_NiParticleBomb> },
{ "NiParticleColorModifier", &construct<NiParticleColorModifier, RC_NiParticleColorModifier> }, { "NiParticleColorModifier", &construct<NiParticleColorModifier, RC_NiParticleColorModifier> },
{ "NiParticleGrowFade", &construct<NiParticleGrowFade, RC_NiParticleGrowFade> }, { "NiParticleGrowFade", &construct<NiParticleGrowFade, RC_NiParticleGrowFade> },
{ "NiParticleRotation", &construct<NiParticleRotation, RC_NiParticleRotation> }, { "NiParticleRotation", &construct<NiParticleRotation, RC_NiParticleRotation> },

@ -51,6 +51,20 @@ namespace Nif
nif->read(mDirection); nif->read(mDirection);
} }
void NiParticleBomb::read(NIFStream* nif)
{
NiParticleModifier::read(nif);
nif->read(mRange);
nif->read(mDuration);
nif->read(mStrength);
nif->read(mStartTime);
mDecayType = static_cast<DecayType>(nif->get<uint32_t>());
mSymmetryType = static_cast<SymmetryType>(nif->get<uint32_t>());
nif->read(mPosition);
nif->read(mDirection);
}
void NiParticleCollider::read(NIFStream* nif) void NiParticleCollider::read(NIFStream* nif)
{ {
NiParticleModifier::read(nif); NiParticleModifier::read(nif);
@ -294,10 +308,10 @@ namespace Nif
mBombObject.read(nif); mBombObject.read(nif);
nif->read(mBombAxis); nif->read(mBombAxis);
nif->read(mDecay); nif->read(mRange);
nif->read(mDeltaV); nif->read(mStrength);
nif->read(mDecayType); mDecayType = static_cast<DecayType>(nif->get<uint32_t>());
nif->read(mSymmetryType); mSymmetryType = static_cast<SymmetryType>(nif->get<uint32_t>());
} }
void NiPSysBombModifier::post(Reader& nif) void NiPSysBombModifier::post(Reader& nif)

@ -40,6 +40,20 @@ namespace Nif
Point = 1, // Fixed origin Point = 1, // Fixed origin
}; };
enum class DecayType : uint32_t
{
None = 0, // f(Distance) = 1.0
Linear = 1, // f(Distance) = (Range - Distance) / Range
Exponential = 2, // f(Distance) = exp(-Distance / Range)
};
enum class SymmetryType : uint32_t
{
Spherical = 0,
Cylindrical = 1, // Perpendicular to direction axis
Planar = 2, // Parallel to direction axis
};
struct NiGravity : NiParticleModifier struct NiGravity : NiParticleModifier
{ {
float mDecay{ 0.f }; float mDecay{ 0.f };
@ -51,6 +65,20 @@ namespace Nif
void read(NIFStream* nif) override; void read(NIFStream* nif) override;
}; };
struct NiParticleBomb : NiParticleModifier
{
float mRange;
float mDuration;
float mStrength;
float mStartTime;
DecayType mDecayType;
SymmetryType mSymmetryType;
osg::Vec3f mPosition;
osg::Vec3f mDirection;
void read(NIFStream* nif);
};
struct NiParticleCollider : NiParticleModifier struct NiParticleCollider : NiParticleModifier
{ {
float mBounceFactor; float mBounceFactor;
@ -210,10 +238,10 @@ namespace Nif
{ {
NiAVObjectPtr mBombObject; NiAVObjectPtr mBombObject;
osg::Vec3f mBombAxis; osg::Vec3f mBombAxis;
float mDecay; float mRange;
float mDeltaV; float mStrength;
uint32_t mDecayType; DecayType mDecayType;
uint32_t mSymmetryType; SymmetryType mSymmetryType;
void read(NIFStream* nif) override; void read(NIFStream* nif) override;
void post(Reader& nif) override; void post(Reader& nif) override;

@ -206,6 +206,7 @@ namespace Nif
RC_NiMultiTargetTransformController, RC_NiMultiTargetTransformController,
RC_NiNode, RC_NiNode,
RC_NiPalette, RC_NiPalette,
RC_NiParticleBomb,
RC_NiParticleColorModifier, RC_NiParticleColorModifier,
RC_NiParticleGrowFade, RC_NiParticleGrowFade,
RC_NiParticleRotation, RC_NiParticleRotation,

@ -1092,6 +1092,18 @@ namespace NifOsg
const Nif::NiGravity* gr = static_cast<const Nif::NiGravity*>(modifier.getPtr()); const Nif::NiGravity* gr = static_cast<const Nif::NiGravity*>(modifier.getPtr());
program->addOperator(new GravityAffector(gr)); program->addOperator(new GravityAffector(gr));
} }
else if (modifier->recType == Nif::RC_NiParticleBomb)
{
auto bomb = static_cast<const Nif::NiParticleBomb*>(modifier.getPtr());
osg::ref_ptr<osgParticle::ModularProgram> bombProgram(new osgParticle::ModularProgram);
attachTo->addChild(bombProgram);
bombProgram->setParticleSystem(partsys);
bombProgram->setReferenceFrame(rf);
bombProgram->setStartTime(bomb->mStartTime);
bombProgram->setLifeTime(bomb->mDuration);
bombProgram->setEndless(false);
bombProgram->addOperator(new ParticleBomb(bomb));
}
else if (modifier->recType == Nif::RC_NiParticleColorModifier) else if (modifier->recType == Nif::RC_NiParticleColorModifier)
{ {
const Nif::NiParticleColorModifier* cl const Nif::NiParticleColorModifier* cl

@ -346,6 +346,84 @@ namespace NifOsg
} }
} }
ParticleBomb::ParticleBomb(const Nif::NiParticleBomb* bomb)
: mRange(bomb->mRange)
, mStrength(bomb->mStrength)
, mDecayType(bomb->mDecayType)
, mSymmetryType(bomb->mSymmetryType)
, mPosition(bomb->mPosition)
, mDirection(bomb->mDirection)
{
}
ParticleBomb::ParticleBomb(const ParticleBomb& copy, const osg::CopyOp& copyop)
: osgParticle::Operator(copy, copyop)
{
mRange = copy.mRange;
mStrength = copy.mStrength;
mDecayType = copy.mDecayType;
mSymmetryType = copy.mSymmetryType;
mCachedWorldPosition = copy.mCachedWorldPosition;
mCachedWorldDirection = copy.mCachedWorldDirection;
}
void ParticleBomb::beginOperate(osgParticle::Program* program)
{
bool absolute = (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF);
mCachedWorldPosition = absolute ? program->transformLocalToWorld(mPosition) : mPosition;
// We don't need the direction for Spherical bomb
if (mSymmetryType != Nif::SymmetryType::Spherical)
{
mCachedWorldDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection;
mCachedWorldDirection.normalize();
}
}
void ParticleBomb::operate(osgParticle::Particle* particle, double dt)
{
float decay = 1.f;
osg::Vec3f explosionDir;
osg::Vec3f particleDir = particle->getPosition() - mCachedWorldPosition;
float distance = particleDir.length();
particleDir.normalize();
switch (mDecayType)
{
case Nif::DecayType::None:
break;
case Nif::DecayType::Linear:
decay = 1.f - distance / mRange;
break;
case Nif::DecayType::Exponential:
decay = std::exp(-distance / mRange);
break;
}
if (decay <= 0.f)
return;
switch (mSymmetryType)
{
case Nif::SymmetryType::Spherical:
explosionDir = particleDir;
break;
case Nif::SymmetryType::Cylindrical:
explosionDir = particleDir - mCachedWorldDirection * (mCachedWorldDirection * particleDir);
explosionDir.normalize();
break;
case Nif::SymmetryType::Planar:
explosionDir = mCachedWorldDirection;
if (explosionDir * particleDir < 0)
explosionDir = -explosionDir;
break;
}
particle->addVelocity(explosionDir * mStrength * decay * dt);
}
Emitter::Emitter() Emitter::Emitter()
: osgParticle::Emitter() : osgParticle::Emitter()
, mFlags(0) , mFlags(0)

@ -199,6 +199,31 @@ namespace NifOsg
osg::Vec3f mCachedWorldDirection; osg::Vec3f mCachedWorldDirection;
}; };
class ParticleBomb : public osgParticle::Operator
{
public:
ParticleBomb(const Nif::NiParticleBomb* bomb);
ParticleBomb() = default;
ParticleBomb(const ParticleBomb& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
ParticleBomb& operator=(const ParticleBomb&) = delete;
META_Object(NifOsg, ParticleBomb)
void operate(osgParticle::Particle* particle, double dt) override;
void beginOperate(osgParticle::Program*) override;
private:
float mRange{ 0.f };
float mStrength{ 0.f };
Nif::DecayType mDecayType{ Nif::DecayType::None };
Nif::SymmetryType mSymmetryType{ Nif::SymmetryType::Spherical };
osg::Vec3f mPosition;
osg::Vec3f mDirection;
osg::Vec3f mCachedWorldPosition;
osg::Vec3f mCachedWorldDirection;
};
// NodeVisitor to find a Group node with the given record index, stored in the node's user data container. // NodeVisitor to find a Group node with the given record index, stored in the node's user data container.
// Alternatively, returns the node's parent Group if that node is not a Group (i.e. a leaf node). // Alternatively, returns the node's parent Group if that node is not a Group (i.e. a leaf node).
class FindGroupByRecIndex : public osg::NodeVisitor class FindGroupByRecIndex : public osg::NodeVisitor

@ -1,5 +1,7 @@
#include "riggeometry.hpp" #include "riggeometry.hpp"
#include <unordered_map>
#include <osg/MatrixTransform> #include <osg/MatrixTransform>
#include <osgUtil/CullVisitor> #include <osgUtil/CullVisitor>
@ -10,39 +12,10 @@
#include "skeleton.hpp" #include "skeleton.hpp"
#include "util.hpp" #include "util.hpp"
namespace
{
inline void accumulateMatrix(
const osg::Matrixf& invBindMatrix, const osg::Matrixf& matrix, const float weight, osg::Matrixf& result)
{
osg::Matrixf m = invBindMatrix * matrix;
float* ptr = m.ptr();
float* ptrresult = result.ptr();
ptrresult[0] += ptr[0] * weight;
ptrresult[1] += ptr[1] * weight;
ptrresult[2] += ptr[2] * weight;
ptrresult[4] += ptr[4] * weight;
ptrresult[5] += ptr[5] * weight;
ptrresult[6] += ptr[6] * weight;
ptrresult[8] += ptr[8] * weight;
ptrresult[9] += ptr[9] * weight;
ptrresult[10] += ptr[10] * weight;
ptrresult[12] += ptr[12] * weight;
ptrresult[13] += ptr[13] * weight;
ptrresult[14] += ptr[14] * weight;
}
}
namespace SceneUtil namespace SceneUtil
{ {
RigGeometry::RigGeometry() RigGeometry::RigGeometry()
: mSkeleton(nullptr)
, mLastFrameNumber(0)
, mBoundsFirstFrame(true)
{ {
setNumChildrenRequiringUpdateTraversal(1); setNumChildrenRequiringUpdateTraversal(1);
// update done in accept(NodeVisitor&) // update done in accept(NodeVisitor&)
@ -50,12 +23,7 @@ namespace SceneUtil
RigGeometry::RigGeometry(const RigGeometry& copy, const osg::CopyOp& copyop) RigGeometry::RigGeometry(const RigGeometry& copy, const osg::CopyOp& copyop)
: Drawable(copy, copyop) : Drawable(copy, copyop)
, mSkeleton(nullptr) , mData(copy.mData)
, mInfluenceMap(copy.mInfluenceMap)
, mBone2VertexVector(copy.mBone2VertexVector)
, mBoneSphereVector(copy.mBoneSphereVector)
, mLastFrameNumber(0)
, mBoundsFirstFrame(true)
{ {
setSourceGeometry(copy.mSourceGeometry); setSourceGeometry(copy.mSourceGeometry);
setNumChildrenRequiringUpdateTraversal(1); setNumChildrenRequiringUpdateTraversal(1);
@ -151,42 +119,18 @@ namespace SceneUtil
return false; return false;
} }
if (!mInfluenceMap) if (!mData)
{ {
Log(Debug::Error) << "Error: No InfluenceMap set on RigGeometry"; Log(Debug::Error) << "Error: No influence data set on RigGeometry";
return false; return false;
} }
mBoneNodesVector.clear(); mNodes.clear();
for (auto& bonePair : mBoneSphereVector->mData) for (const BoneInfo& info : mData->mBones)
{ {
const std::string& boneName = bonePair.first; mNodes.push_back(mSkeleton->getBone(info.mName));
Bone* bone = mSkeleton->getBone(boneName); if (!mNodes.back())
if (!bone) Log(Debug::Error) << "Error: RigGeometry did not find bone " << info.mName;
{
mBoneNodesVector.push_back(nullptr);
Log(Debug::Error) << "Error: RigGeometry did not find bone " << boneName;
continue;
}
mBoneNodesVector.push_back(bone);
}
for (auto& pair : mBone2VertexVector->mData)
{
for (auto& weight : pair.first)
{
const std::string& boneName = weight.first.first;
Bone* bone = mSkeleton->getBone(boneName);
if (!bone)
{
mBoneNodesVector.push_back(nullptr);
Log(Debug::Error) << "Error: RigGeometry did not find bone " << boneName;
continue;
}
mBoneNodesVector.push_back(bone);
}
} }
return true; return true;
@ -226,25 +170,28 @@ namespace SceneUtil
osg::Vec3Array* normalDst = static_cast<osg::Vec3Array*>(geom.getNormalArray()); osg::Vec3Array* normalDst = static_cast<osg::Vec3Array*>(geom.getNormalArray());
osg::Vec4Array* tangentDst = static_cast<osg::Vec4Array*>(geom.getTexCoordArray(7)); osg::Vec4Array* tangentDst = static_cast<osg::Vec4Array*>(geom.getTexCoordArray(7));
int index = mBoneSphereVector->mData.size(); for (const auto& [influences, vertices] : mData->mInfluences)
for (auto& pair : mBone2VertexVector->mData)
{ {
osg::Matrixf resultMat(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); osg::Matrixf resultMat(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
for (auto& weight : pair.first) for (const auto& [index, weight] : influences)
{ {
Bone* bone = mBoneNodesVector[index]; const Bone* bone = mNodes[index];
if (bone == nullptr) if (bone == nullptr)
continue; continue;
accumulateMatrix(weight.first.second, bone->mMatrixInSkeletonSpace, weight.second, resultMat); osg::Matrixf boneMat = mData->mBones[index].mInvBindMatrix * bone->mMatrixInSkeletonSpace;
index++; float* boneMatPtr = boneMat.ptr();
float* resultMatPtr = resultMat.ptr();
for (int i = 0; i < 16; ++i, ++resultMatPtr, ++boneMatPtr)
if (i % 4 != 3)
*resultMatPtr += *boneMatPtr * weight;
} }
if (mGeomToSkelMatrix) if (mGeomToSkelMatrix)
resultMat *= (*mGeomToSkelMatrix); resultMat *= (*mGeomToSkelMatrix);
for (auto& vertex : pair.second) for (unsigned short vertex : vertices)
{ {
(*positionDst)[vertex] = resultMat.preMult((*positionSrc)[vertex]); (*positionDst)[vertex] = resultMat.preMult((*positionSrc)[vertex]);
if (normalDst) if (normalDst)
@ -291,15 +238,14 @@ namespace SceneUtil
osg::BoundingBox box; osg::BoundingBox box;
int index = 0; size_t index = 0;
for (auto& boundPair : mBoneSphereVector->mData) for (const BoneInfo& info : mData->mBones)
{ {
Bone* bone = mBoneNodesVector[index]; const Bone* bone = mNodes[index++];
if (bone == nullptr) if (bone == nullptr)
continue; continue;
index++; osg::BoundingSpheref bs = info.mBoundSphere;
osg::BoundingSpheref bs = boundPair.second;
if (mGeomToSkelMatrix) if (mGeomToSkelMatrix)
transformBoundingSphere(bone->mMatrixInSkeletonSpace * (*mGeomToSkelMatrix), bs); transformBoundingSphere(bone->mMatrixInSkeletonSpace * (*mGeomToSkelMatrix), bs);
else else
@ -357,35 +303,26 @@ namespace SceneUtil
void RigGeometry::setInfluenceMap(osg::ref_ptr<InfluenceMap> influenceMap) void RigGeometry::setInfluenceMap(osg::ref_ptr<InfluenceMap> influenceMap)
{ {
mInfluenceMap = influenceMap; mData = new InfluenceData;
mData->mBones.reserve(influenceMap->mData.size());
typedef std::map<unsigned short, std::vector<BoneWeight>> Vertex2BoneMap;
Vertex2BoneMap vertex2BoneMap;
mBoneSphereVector = new BoneSphereVector;
mBoneSphereVector->mData.reserve(mInfluenceMap->mData.size());
mBone2VertexVector = new Bone2VertexVector;
for (auto& influencePair : mInfluenceMap->mData)
{
const std::string& boneName = influencePair.first;
const BoneInfluence& bi = influencePair.second;
mBoneSphereVector->mData.emplace_back(boneName, bi.mBoundSphere);
for (auto& weightPair : bi.mWeights) std::unordered_map<unsigned short, std::vector<BoneWeight>> vertexToInfluences;
{ size_t index = 0;
std::vector<BoneWeight>& vec = vertex2BoneMap[weightPair.first]; for (const auto& [boneName, bi] : influenceMap->mData)
{
mData->mBones.push_back({ boneName, bi.mBoundSphere, bi.mInvBindMatrix });
vec.emplace_back(std::make_pair(boneName, bi.mInvBindMatrix), weightPair.second); for (const auto& [vertex, weight] : bi.mWeights)
} vertexToInfluences[vertex].emplace_back(index, weight);
index++;
} }
Bone2VertexMap bone2VertexMap; std::map<std::vector<BoneWeight>, VertexList> influencesToVertices;
for (auto& vertexPair : vertex2BoneMap) for (const auto& [vertex, weights] : vertexToInfluences)
{ influencesToVertices[weights].emplace_back(vertex);
bone2VertexMap[vertexPair.second].emplace_back(vertexPair.first);
}
mBone2VertexVector->mData.reserve(bone2VertexMap.size()); mData->mInfluences.reserve(influencesToVertices.size());
mBone2VertexVector->mData.assign(bone2VertexMap.begin(), bone2VertexMap.end()); mData->mInfluences.assign(influencesToVertices.begin(), influencesToVertices.end());
} }
void RigGeometry::accept(osg::NodeVisitor& nv) void RigGeometry::accept(osg::NodeVisitor& nv)

@ -36,6 +36,7 @@ namespace SceneUtil
// static parts of the model. // static parts of the model.
void compileGLObjects(osg::RenderInfo& renderInfo) const override {} void compileGLObjects(osg::RenderInfo& renderInfo) const override {}
// TODO: Make InfluenceMap more similar to InfluenceData
struct BoneInfluence struct BoneInfluence
{ {
osg::Matrixf mInvBindMatrix; osg::Matrixf mInvBindMatrix;
@ -84,35 +85,29 @@ namespace SceneUtil
osg::ref_ptr<osg::Geometry> mSourceGeometry; osg::ref_ptr<osg::Geometry> mSourceGeometry;
osg::ref_ptr<const osg::Vec4Array> mSourceTangents; osg::ref_ptr<const osg::Vec4Array> mSourceTangents;
Skeleton* mSkeleton; Skeleton* mSkeleton{ nullptr };
osg::ref_ptr<osg::RefMatrix> mGeomToSkelMatrix; osg::ref_ptr<osg::RefMatrix> mGeomToSkelMatrix;
osg::ref_ptr<InfluenceMap> mInfluenceMap; struct BoneInfo
typedef std::pair<std::string, osg::Matrixf> BoneBindMatrixPair;
typedef std::pair<BoneBindMatrixPair, float> BoneWeight;
typedef std::vector<unsigned short> VertexList;
typedef std::map<std::vector<BoneWeight>, VertexList> Bone2VertexMap;
struct Bone2VertexVector : public osg::Referenced
{ {
std::vector<std::pair<std::vector<BoneWeight>, VertexList>> mData; std::string mName;
osg::BoundingSpheref mBoundSphere;
osg::Matrixf mInvBindMatrix;
}; };
osg::ref_ptr<Bone2VertexVector> mBone2VertexVector;
struct BoneSphereVector : public osg::Referenced using BoneWeight = std::pair<size_t, float>;
using VertexList = std::vector<unsigned short>;
struct InfluenceData : public osg::Referenced
{ {
std::vector<std::pair<std::string, osg::BoundingSpheref>> mData; std::vector<BoneInfo> mBones;
std::vector<std::pair<std::vector<BoneWeight>, VertexList>> mInfluences;
}; };
osg::ref_ptr<BoneSphereVector> mBoneSphereVector; osg::ref_ptr<InfluenceData> mData;
std::vector<Bone*> mBoneNodesVector; std::vector<Bone*> mNodes;
unsigned int mLastFrameNumber; unsigned int mLastFrameNumber{ 0 };
bool mBoundsFirstFrame; bool mBoundsFirstFrame{ true };
bool initFromParentSkeleton(osg::NodeVisitor* nv); bool initFromParentSkeleton(osg::NodeVisitor* nv);

@ -167,7 +167,7 @@ namespace SceneUtil
"SceneUtil::DisableLight", "SceneUtil::MWShadowTechnique", "SceneUtil::TextKeyMapHolder", "SceneUtil::DisableLight", "SceneUtil::MWShadowTechnique", "SceneUtil::TextKeyMapHolder",
"Shader::AddedState", "Shader::RemovedAlphaFunc", "NifOsg::FlipController", "Shader::AddedState", "Shader::RemovedAlphaFunc", "NifOsg::FlipController",
"NifOsg::KeyframeController", "NifOsg::Emitter", "NifOsg::ParticleColorAffector", "NifOsg::KeyframeController", "NifOsg::Emitter", "NifOsg::ParticleColorAffector",
"NifOsg::ParticleSystem", "NifOsg::GravityAffector", "NifOsg::GrowFadeAffector", "NifOsg::ParticleSystem", "NifOsg::GravityAffector", "NifOsg::ParticleBomb", "NifOsg::GrowFadeAffector",
"NifOsg::InverseWorldMatrix", "NifOsg::StaticBoundingBoxCallback", "NifOsg::GeomMorpherController", "NifOsg::InverseWorldMatrix", "NifOsg::StaticBoundingBoxCallback", "NifOsg::GeomMorpherController",
"NifOsg::UpdateMorphGeometry", "NifOsg::UVController", "NifOsg::VisController", "osgMyGUI::Drawable", "NifOsg::UpdateMorphGeometry", "NifOsg::UVController", "NifOsg::VisController", "osgMyGUI::Drawable",
"osg::DrawCallback", "osg::UniformBufferObject", "osgOQ::ClearQueriesCallback", "osg::DrawCallback", "osg::UniformBufferObject", "osgOQ::ClearQueriesCallback",

@ -29,6 +29,12 @@
-- @param openmw.core#GameObject player (optional) Will be used in multiplayer mode to get the script if there is a separate instance for each player. Currently has no effect. -- @param openmw.core#GameObject player (optional) Will be used in multiplayer mode to get the script if there is a separate instance for each player. Currently has no effect.
-- @return #MWScript, #nil -- @return #MWScript, #nil
---
-- Returns mutable global variables. In multiplayer, these may be specific to the provided player.
-- @function [parent=#MWScriptFunctions] getGlobalVariables
-- @param openmw.core#GameObject player (optional) Will be used in multiplayer mode to get the globals if there is a separate instance for each player. Currently has no effect.
-- @return #list<#number>
--- ---
-- Returns global mwscript with given recordId. Returns `nil` if the script doesn't exist or is not started. -- Returns global mwscript with given recordId. Returns `nil` if the script doesn't exist or is not started.
-- Currently there can be only one instance of each mwscript, but in multiplayer it will be possible to have a separate instance per player. -- Currently there can be only one instance of each mwscript, but in multiplayer it will be possible to have a separate instance per player.

Loading…
Cancel
Save