From 19cd987208a18ae098327699d3828404b0f52e13 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 14:32:39 +0100 Subject: [PATCH 1/9] Fix Ptr updates in PositionCell This was not the proper way to get the updated Ptr, it will only work for the player which isn't owned by any cell. For other objects, moving between cells makes the object owned by that cell and thus the getBase() pointer will change. --- apps/openmw/mwscript/transformationextensions.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index b2b21a532..35e61ab56 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -312,8 +312,8 @@ namespace MWScript } if(store) { - MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z); - ptr = MWWorld::Ptr(ptr.getBase(), store); + ptr = MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z); + dynamic_cast(runtime.getContext()).updatePtr(ptr); float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); @@ -363,8 +363,7 @@ namespace MWScript if (ptr == MWMechanics::getPlayer()) { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); - MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); - ptr = MWWorld::Ptr(ptr.getBase(), cell); + ptr = MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); } else { From af7b5e636e173a12c9b5799cc59d8f4b17fdb678 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 30 Sep 2015 10:30:50 +0200 Subject: [PATCH 2/9] improves InterpreterContext::updatePtr This checks the update is really on the right pointer. It fixes the boat disappearing in "fishing academy", and it allows scripts linked to objects not to loose their default reference when using the object-> notation on another object. --- apps/openmw/mwscript/interpretercontext.cpp | 4 ++-- apps/openmw/mwscript/interpretercontext.hpp | 2 +- .../mwscript/transformationextensions.cpp | 19 ++++++++++--------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index b0d4d3f2d..c70eb6cf8 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -601,9 +601,9 @@ namespace MWScript return mTargetId; } - void InterpreterContext::updatePtr(const MWWorld::Ptr& updated) + void InterpreterContext::updatePtr(const MWWorld::Ptr& base, const MWWorld::Ptr& updated) { - if (!mReference.isEmpty()) + if (!mReference.isEmpty() && base == mReference) mReference = updated; } } diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index d3841befd..3c43444cc 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -167,7 +167,7 @@ namespace MWScript MWWorld::Ptr getReference(bool required=true); ///< Reference, that the script is running from (can be empty) - void updatePtr(const MWWorld::Ptr& updated); + void updatePtr(const MWWorld::Ptr& base, const MWWorld::Ptr& updated); ///< Update the Ptr stored in mReference, if there is one stored there. Should be called after the reference has been moved to a new cell. virtual std::string getTargetId() const; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 35e61ab56..f65035226 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -186,7 +186,7 @@ namespace MWScript runtime.push(ptr.getRefData().getPosition().pos[2]); } else - throw std::runtime_error ("invalid axis: " + axis); + throw std::runtime_error ("invalid axis: " + axis); } }; @@ -232,7 +232,7 @@ namespace MWScript else throw std::runtime_error ("invalid axis: " + axis); - dynamic_cast(runtime.getContext()).updatePtr(updated); + dynamic_cast(runtime.getContext()).updatePtr(ptr,updated); } }; @@ -300,7 +300,7 @@ namespace MWScript } catch(std::exception&) { - const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); int cx,cy; MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); @@ -312,9 +312,9 @@ namespace MWScript } if(store) { + MWWorld::Ptr base = ptr; ptr = MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z); - - dynamic_cast(runtime.getContext()).updatePtr(ptr); + dynamic_cast(runtime.getContext()).updatePtr(base,ptr); float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); float ay = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]); @@ -360,6 +360,7 @@ namespace MWScript // another morrowind oddity: player will be moved to the exterior cell at this location, // non-player actors will move within the cell they are in. + MWWorld::Ptr base = ptr; if (ptr == MWMechanics::getPlayer()) { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); @@ -369,7 +370,7 @@ namespace MWScript { ptr = MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z); } - dynamic_cast(runtime.getContext()).updatePtr(ptr); + dynamic_cast(runtime.getContext()).updatePtr(base,ptr); float ax = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]); float ay = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]); @@ -626,7 +627,7 @@ namespace MWScript MWBase::Environment::get().getWorld()->rotateObject(ptr, xr, yr, zr); - dynamic_cast(runtime.getContext()).updatePtr( + dynamic_cast(runtime.getContext()).updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], ptr.getCellRef().getPosition().pos[1], ptr.getCellRef().getPosition().pos[2])); @@ -744,8 +745,8 @@ namespace MWScript interpreter.installSegment5(Compiler::Transformation::opcodePositionExplicit,new OpPosition); interpreter.installSegment5(Compiler::Transformation::opcodePositionCell,new OpPositionCell); interpreter.installSegment5(Compiler::Transformation::opcodePositionCellExplicit,new OpPositionCell); - interpreter.installSegment5(Compiler::Transformation::opcodePlaceItemCell,new OpPlaceItemCell); - interpreter.installSegment5(Compiler::Transformation::opcodePlaceItem,new OpPlaceItem); + interpreter.installSegment5(Compiler::Transformation::opcodePlaceItemCell,new OpPlaceItemCell); + interpreter.installSegment5(Compiler::Transformation::opcodePlaceItem,new OpPlaceItem); interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtPc,new OpPlaceAt); interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtMe,new OpPlaceAt); interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtMeExplicit,new OpPlaceAt); From 9897400d9702117183319b52959d354e459ef598 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 19:03:24 +0100 Subject: [PATCH 3/9] Restore the previous key focus widget after playing video --- apps/openmw/mwgui/windowmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a7c3a1957..114b8223d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1743,6 +1743,7 @@ namespace MWGui MyGUI::IntSize screenSize = MyGUI::RenderManager::getInstance().getViewSize(); sizeVideo(screenSize.width, screenSize.height); + MyGUI::Widget* oldKeyFocus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); setKeyFocusWidget(mVideoWidget); mVideoBackground->setVisible(true); @@ -1770,6 +1771,8 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->resumeSounds(); + setKeyFocusWidget(oldKeyFocus); + setCursorVisible(cursorWasVisible); // Restore normal rendering From 626281977eb2d0bc5c3549ce0409b0b5e4ed1cca Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 19:40:31 +0100 Subject: [PATCH 4/9] Read NiLODNode (Bug #3008) --- components/nif/niffile.cpp | 2 ++ components/nif/node.hpp | 36 ++++++++++++++++++++++++++++++++++++ components/nif/record.hpp | 2 ++ 3 files changed, 40 insertions(+) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 1db9c8ccf..1387a97b0 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -48,6 +48,8 @@ static std::map makeFactory() { std::map newFactory; newFactory.insert(makeEntry("NiNode", &construct , RC_NiNode )); + newFactory.insert(makeEntry("NiSwitchNode", &construct , RC_NiSwitchNode )); + newFactory.insert(makeEntry("NiLODNode", &construct , RC_NiLODNode )); newFactory.insert(makeEntry("AvoidNode", &construct , RC_AvoidNode )); newFactory.insert(makeEntry("NiBSParticleNode", &construct , RC_NiBSParticleNode )); newFactory.insert(makeEntry("NiBSAnimationNode", &construct , RC_NiBSAnimationNode )); diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 943ddcc66..326e9802f 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -250,5 +250,41 @@ struct NiRotatingParticles : Node } }; +// A node used as the base to switch between child nodes, such as for LOD levels. +struct NiSwitchNode : public NiNode +{ + void read(NIFStream *nif) + { + NiNode::read(nif); + nif->getInt(); // unknown + } +}; + +struct NiLODNode : public NiSwitchNode +{ + osg::Vec3f lodCenter; + + struct LODRange + { + float minRange; + float maxRange; + }; + std::vector lodLevels; + + void read(NIFStream *nif) + { + NiSwitchNode::read(nif); + lodCenter = nif->getVector3(); + unsigned int numLodLevels = nif->getUInt(); + for (unsigned int i=0; igetFloat(); + r.maxRange = nif->getFloat(); + lodLevels.push_back(r); + } + } +}; + } // Namespace #endif diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 1022802cc..bcbdba115 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -36,6 +36,8 @@ enum RecordType { RC_MISSING = 0, RC_NiNode, + RC_NiSwitchNode, + RC_NiLODNode, RC_NiBillboardNode, RC_AvoidNode, RC_NiTriShape, From 0965a9059d76bac29af26a091e7c7ac0012ec39c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 19:52:36 +0100 Subject: [PATCH 5/9] Handle NiLODNode using osg::LOD (Fixes #3008) --- components/nifosg/nifloader.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3e7f47b6f..73b72811a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -6,6 +6,7 @@ #include #include #include +#include // resource #include @@ -424,6 +425,20 @@ namespace NifOsg // Need to make sure that won't break transparency sorting. Check what the original engine is doing? } + osg::ref_ptr handleLodNode(const Nif::NiLODNode* niLodNode) + { + osg::ref_ptr lod (new osg::LOD); + lod->setCenterMode(osg::LOD::USER_DEFINED_CENTER); + lod->setCenter(niLodNode->lodCenter); + for (unsigned int i=0; ilodLevels.size(); ++i) + { + const Nif::NiLODNode::LODRange& range = niLodNode->lodLevels[i]; + lod->setRange(i, range.minRange, range.maxRange); + } + lod->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT); + return lod; + } + osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::vector boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { @@ -555,6 +570,15 @@ namespace NifOsg // Optimization pass optimize(nifNode, node, skipMeshes); + + if (nifNode->recType == Nif::RC_NiLODNode) + { + const Nif::NiLODNode* niLodNode = static_cast(nifNode); + osg::ref_ptr lod = handleLodNode(niLodNode); + node->addChild(lod); // unsure if LOD should be above or below this node's transform + node = lod; + } + const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) { From 8cd41f0ed4809e960e36733eee481b180be25a2a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 23:05:44 +0100 Subject: [PATCH 6/9] Increase the ray distance for dropObjectOnGround (Fixes #3010) --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f82392662..7e78bef8c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1870,7 +1870,7 @@ namespace MWWorld orig.z() += 20; osg::Vec3f dir (0, 0, -1); - float len = 100.0; + float len = 1000000.0; MWRender::RenderingManager::RayResult result = mRendering->castRay(orig, orig+dir*len, true, true); if (result.mHit) From ba211ad9ad43e69f1bb19b00bb0de5ae446750af Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 23:27:34 +0100 Subject: [PATCH 7/9] Read NiPointLight (Fixes #3011) --- components/nif/effect.cpp | 27 ++++++++++++-------------- components/nif/effect.hpp | 39 ++++++++++++++++++++++++-------------- components/nif/niffile.cpp | 1 + 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/components/nif/effect.cpp b/components/nif/effect.cpp index 41dcb09de..78feeea94 100644 --- a/components/nif/effect.cpp +++ b/components/nif/effect.cpp @@ -5,29 +5,19 @@ namespace Nif { -void NiLight::SLight::read(NIFStream *nif) +void NiLight::read(NIFStream *nif) { + NiDynamicEffect::read(nif); + dimmer = nif->getFloat(); ambient = nif->getVector3(); diffuse = nif->getVector3(); specular = nif->getVector3(); } -void NiLight::read(NIFStream *nif) -{ - Effect::read(nif); - - nif->getInt(); // 1 - nif->getInt(); // 1? - light.read(nif); -} - void NiTextureEffect::read(NIFStream *nif) { - Effect::read(nif); - - int tmp = nif->getInt(); - if(tmp) nif->getInt(); // always 1? + NiDynamicEffect::read(nif); /* 3 x Vector4 = [1,0,0,0] @@ -52,10 +42,17 @@ void NiTextureEffect::read(NIFStream *nif) void NiTextureEffect::post(NIFFile *nif) { - Effect::post(nif); + NiDynamicEffect::post(nif); texture.post(nif); } +void NiPointLight::read(NIFStream *nif) +{ + NiLight::read(nif); + constantAttenuation = nif->getFloat(); + linearAttenuation = nif->getFloat(); + quadraticAttenuation = nif->getFloat(); +} } diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index fae1cd7f5..75de0a9ab 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -29,27 +29,38 @@ namespace Nif { -typedef Node Effect; - -// Used for NiAmbientLight and NiDirectionalLight. Might also work for -// NiPointLight and NiSpotLight? -struct NiLight : Effect +struct NiDynamicEffect : public Node { - struct SLight + void read(NIFStream *nif) { - float dimmer; - osg::Vec3f ambient; - osg::Vec3f diffuse; - osg::Vec3f specular; + Node::read(nif); + unsigned int numAffectedNodes = nif->getUInt(); + for (unsigned int i=0; igetUInt(); // ref to another Node + } +}; - void read(NIFStream *nif); - }; - SLight light; +// Used as base for NiAmbientLight, NiDirectionalLight, NiPointLight and NiSpotLight. +struct NiLight : NiDynamicEffect +{ + float dimmer; + osg::Vec3f ambient; + osg::Vec3f diffuse; + osg::Vec3f specular; void read(NIFStream *nif); }; -struct NiTextureEffect : Effect +struct NiPointLight : public NiLight +{ + float constantAttenuation; + float linearAttenuation; + float quadraticAttenuation; + + void read(NIFStream *nif); +}; + +struct NiTextureEffect : NiDynamicEffect { NiSourceTexturePtr texture; diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 1387a97b0..ab0af8f99 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -82,6 +82,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiFlipController", &construct , RC_NiFlipController )); newFactory.insert(makeEntry("NiAmbientLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiDirectionalLight", &construct , RC_NiLight )); + newFactory.insert(makeEntry("NiPointLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiTextureEffect", &construct , RC_NiTextureEffect )); newFactory.insert(makeEntry("NiVertWeightsExtraData", &construct , RC_NiVertWeightsExtraData )); newFactory.insert(makeEntry("NiTextKeyExtraData", &construct , RC_NiTextKeyExtraData )); From a29d1ace2b2beeeda58cc523793f73e401ec1afd Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Nov 2015 23:45:12 +0100 Subject: [PATCH 8/9] Read NiSpotLight --- components/nif/effect.cpp | 8 ++++++++ components/nif/effect.hpp | 7 +++++++ components/nif/niffile.cpp | 1 + 3 files changed, 16 insertions(+) diff --git a/components/nif/effect.cpp b/components/nif/effect.cpp index 78feeea94..79cd10431 100644 --- a/components/nif/effect.cpp +++ b/components/nif/effect.cpp @@ -55,4 +55,12 @@ void NiPointLight::read(NIFStream *nif) quadraticAttenuation = nif->getFloat(); } +void NiSpotLight::read(NIFStream *nif) +{ + NiPointLight::read(nif); + + cutoff = nif->getFloat(); + exponent = nif->getFloat(); +} + } diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index 75de0a9ab..02647e444 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -60,6 +60,13 @@ struct NiPointLight : public NiLight void read(NIFStream *nif); }; +struct NiSpotLight : public NiPointLight +{ + float cutoff; + float exponent; + void read(NIFStream *nif); +}; + struct NiTextureEffect : NiDynamicEffect { NiSourceTexturePtr texture; diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index ab0af8f99..ccfcdfc73 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -83,6 +83,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiAmbientLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiDirectionalLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiPointLight", &construct , RC_NiLight )); + newFactory.insert(makeEntry("NiSpotLight", &construct , RC_NiLight )); newFactory.insert(makeEntry("NiTextureEffect", &construct , RC_NiTextureEffect )); newFactory.insert(makeEntry("NiVertWeightsExtraData", &construct , RC_NiVertWeightsExtraData )); newFactory.insert(makeEntry("NiTextKeyExtraData", &construct , RC_NiTextKeyExtraData )); From 7c16630874230d886aa1d94f620c8b332676d93a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Nov 2015 00:21:30 +0100 Subject: [PATCH 9/9] NifOsg::Emitter: ignore psToWorld scale Seems wrong to me, but MW appears to do it that way. Without this fix, the light_de_candle_08_64 from http://www.nexusmods.com/morrowind/mods/41654/ has flame particles in the wrong spot. --- components/nifosg/particle.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 68f3de8aa..44d062d8b 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -264,7 +264,9 @@ void Emitter::emitParticles(double dt) osg::MatrixList worldMats = getParticleSystem()->getWorldMatrices(); if (!worldMats.empty()) { - const osg::Matrix psToWorld = worldMats[0]; + osg::Matrix psToWorld = worldMats[0]; + // ignore scales in particlesystem world matrix. this seems wrong, but have to do so for MW compatibility. + psToWorld.orthoNormalize(psToWorld); worldToPs = osg::Matrix::inverse(psToWorld); }