From 35f5be680bb877bd4c8ad9ae48c1126fb25a6d69 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 16:52:39 +0100 Subject: [PATCH 01/27] Support for NiVisController on trishape nodes --- components/nifosg/nifloader.cpp | 56 ++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2b73f779f..a8865e7d2 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -609,15 +609,20 @@ namespace NifOsg } else if (ctrl->recType == Nif::RC_NiVisController) { - const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); - - osg::ref_ptr callback(new VisController(visctrl->data.getPtr())); - setupController(visctrl, callback, animflags); - transformNode->addUpdateCallback(callback); + handleVisController(static_cast(ctrl.getPtr()), transformNode, animflags); } + else + std::cerr << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename << std::endl; } } + void handleVisController(const Nif::NiVisController* visctrl, osg::Node* node, int animflags) + { + osg::ref_ptr callback(new VisController(visctrl->data.getPtr())); + setupController(visctrl, callback, animflags); + node->addUpdateCallback(callback); + } + void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) @@ -942,28 +947,31 @@ namespace NifOsg void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { + osg::ref_ptr geode (new osg::Geode); + osg::ref_ptr geometry; - if(!triShape->controller.empty()) + for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) { - Nif::ControllerPtr ctrl = triShape->controller; - do { - if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) - { - geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if(ctrl->recType == Nif::RC_NiGeomMorpherController) + { + geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); - osg::ref_ptr morphctrl = new GeomMorpherController( - static_cast(ctrl.getPtr())->data.getPtr()); - setupController(ctrl.getPtr(), morphctrl, animflags); - geometry->setUpdateCallback(morphctrl); - break; - } - } while(!(ctrl=ctrl->next).empty()); + osg::ref_ptr morphctrl = new GeomMorpherController( + static_cast(ctrl.getPtr())->data.getPtr()); + setupController(ctrl.getPtr(), morphctrl, animflags); + geometry->setUpdateCallback(morphctrl); + } + else if (ctrl->recType == Nif::RC_NiVisController) + { + handleVisController(static_cast(ctrl.getPtr()), geode, animflags); + } } if (!geometry.get()) geometry = new osg::Geometry; - osg::ref_ptr geode (new osg::Geode); triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); geode->addDrawable(geometry); @@ -1043,6 +1051,16 @@ namespace NifOsg { osg::ref_ptr geode (new osg::Geode); + for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if (ctrl->recType == Nif::RC_NiVisController) + { + handleVisController(static_cast(ctrl.getPtr()), geode, animflags); + } + } + osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); From 64abdbabe3f2b169ebcc9932dc910512592dcae7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 17:00:33 +0100 Subject: [PATCH 02/27] Small refactor of controllers handling, print warning messages for unhandled controllers --- components/nifosg/nifloader.cpp | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a8865e7d2..49bc7b0fb 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -536,7 +536,7 @@ namespace NifOsg handleSkinnedTriShape(triShape, node, composite, boundTextures, animflags); if (!nifNode->controller.empty()) - handleMeshControllers(nifNode, composite, boundTextures, animflags); + handleMeshControllers(nifNode, node, composite, boundTextures, animflags); } if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) @@ -570,7 +570,7 @@ namespace NifOsg return node; } - void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector &boundTextures, int animflags) + void handleMeshControllers(const Nif::Node *nifNode, osg::Node* node, SceneUtil::CompositeStateSetUpdater* composite, const std::vector &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -587,6 +587,14 @@ namespace NifOsg setupController(uvctrl, ctrl, animflags); composite->addController(ctrl); } + else if (ctrl->recType == Nif::RC_NiVisController) + { + handleVisController(static_cast(ctrl.getPtr()), node, animflags); + } + else if(ctrl->recType == Nif::RC_NiGeomMorpherController) + {} // handled in handleTriShape + else + std::cerr << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename << std::endl; } } @@ -815,6 +823,8 @@ namespace NifOsg continue; if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) partctrl = static_cast(ctrl.getPtr()); + else + std::cerr << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename << std::endl; } if (!partctrl) { @@ -962,10 +972,7 @@ namespace NifOsg static_cast(ctrl.getPtr())->data.getPtr()); setupController(ctrl.getPtr(), morphctrl, animflags); geometry->setUpdateCallback(morphctrl); - } - else if (ctrl->recType == Nif::RC_NiVisController) - { - handleVisController(static_cast(ctrl.getPtr()), geode, animflags); + break; } } @@ -1051,16 +1058,6 @@ namespace NifOsg { osg::ref_ptr geode (new osg::Geode); - for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) - { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if (ctrl->recType == Nif::RC_NiVisController) - { - handleVisController(static_cast(ctrl.getPtr()), geode, animflags); - } - } - osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); From 1b52749ae1930e5322e19066a2513d8b9dccfece Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 17:30:11 +0100 Subject: [PATCH 03/27] Adjust third person camera height based on character height --- apps/openmw/mwrender/camera.cpp | 13 ++++++++++--- apps/openmw/mwrender/camera.hpp | 3 +++ apps/openmw/mwrender/renderingmanager.cpp | 3 +++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index fb6573d65..ea8c60bf3 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -42,7 +42,8 @@ namespace MWRender { Camera::Camera (osg::Camera* camera) - : mCamera(camera), + : mHeightScale(1.f), + mCamera(camera), mAnimation(NULL), mFirstPersonView(true), mPreviewMode(false), @@ -93,7 +94,7 @@ namespace MWRender osg::Vec3d position = worldMat.getTrans(); if (!isFirstPerson()) - position.z() += mHeight; + position.z() += mHeight * mHeightScale; return position; } @@ -372,11 +373,17 @@ namespace MWRender mTrackingNode = mAnimation->getNode("Camera"); if (!mTrackingNode) mTrackingNode = mAnimation->getNode("Head"); + mHeightScale = 1.f; } else { mAnimation->setViewMode(NpcAnimation::VM_Normal); - mTrackingNode = mTrackingPtr.getRefData().getBaseNode(); + osg::PositionAttitudeTransform* transform = mTrackingPtr.getRefData().getBaseNode(); + mTrackingNode = transform; + if (transform) + mHeightScale = mTrackingPtr.getRefData().getBaseNode()->getScale().z(); + else + mHeightScale = 1.f; } rotateCamera(getPitch(), getYaw(), false); } diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index a655e1c1f..899fc9447 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -29,6 +29,7 @@ namespace MWRender MWWorld::Ptr mTrackingPtr; osg::ref_ptr mTrackingNode; + float mHeightScale; osg::ref_ptr mCamera; @@ -97,6 +98,8 @@ namespace MWRender bool isFirstPerson() const { return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); } + void updateScale(); + void processViewChange(); void update(float duration, bool paused=false); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 45c04ceec..27ea7ebed 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -439,6 +439,9 @@ namespace MWRender void RenderingManager::scaleObject(const MWWorld::Ptr &ptr, const osg::Vec3f &scale) { ptr.getRefData().getBaseNode()->setScale(scale); + + if (ptr == mCamera->getTrackingPtr()) // update height of camera + mCamera->processViewChange(); } void RenderingManager::removeObject(const MWWorld::Ptr &ptr) From 1200ff91866ae430d9e5d3e4d1ccff3d133e1ba6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 18:31:41 +0100 Subject: [PATCH 04/27] RigGeometry: fix incorrect bounding box in the first frame The default computeBound() was overriding the manually set bounding box. --- components/sceneutil/riggeometry.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 8eb08f546..ac29ee3e8 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -2,9 +2,9 @@ #include #include - #include +#include #include #include "skeleton.hpp" @@ -58,6 +58,14 @@ public: } }; +// We can't compute the bounds without a NodeVisitor, since we need the current geomToSkelMatrix. +// So we return nothing. Bounds are updated every frame in the UpdateCallback. +class DummyComputeBoundCallback : public osg::Drawable::ComputeBoundingBoxCallback +{ +public: + virtual osg::BoundingBox computeBound(const osg::Drawable&) const { return osg::BoundingBox(); } +}; + RigGeometry::RigGeometry() : mSkeleton(NULL) , mLastFrameNumber(0) @@ -66,6 +74,7 @@ RigGeometry::RigGeometry() setCullCallback(new UpdateRigGeometry); setUpdateCallback(new UpdateRigBounds); setSupportsDisplayList(false); + setComputeBoundingBoxCallback(new DummyComputeBoundCallback); } RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) @@ -278,6 +287,12 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) } _boundingBox = box; + _boundingBoxComputed = true; +#if OSG_MIN_VERSION_REQUIRED(3,3,3) + // in OSG 3.3.3 and up Drawable inherits from Node, so has a bounding sphere as well. + _boundingSphere = osg::BoundingSphere(_boundingBox); + _boundingSphereComputed = true; +#endif for (unsigned int i=0; idirtyBound(); } From bd8332d2b01ab600b6405c7d6a0b73cf7746e8a1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 18:57:17 +0100 Subject: [PATCH 05/27] Remove default copyop argument for nodecallback copy constructors Works around a compiler warning with OSG 3.4: warning: base class 'class osg::Callback' should be explicitly initialized in the copy constructor [-Wextra] With no default argument for osg::CopyOp&, the compiler no longer sees the function as a real copy constructor and stops warning about the missing virtual initializations. We don't care about this warning because there is nothing interesting to initialize in the osg::NodeCallback base anyway. A proper fix for the warning would require to inserting OSG_VERSION conditional compiling all over the place, that is as long as we are still supporting OSG 3.2. --- components/nifosg/controller.hpp | 2 +- components/nifosg/particle.hpp | 2 +- components/sceneutil/lightmanager.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 58870317e..d0c6d1de3 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -146,7 +146,7 @@ namespace NifOsg { public: UVController(); - UVController(const UVController&,const osg::CopyOp& = osg::CopyOp::SHALLOW_COPY); + UVController(const UVController&,const osg::CopyOp&); UVController(const Nif::NiUVData *data, std::set textureUnits); META_Object(NifOsg,UVController) diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index c7d5d585d..043489865 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -60,7 +60,7 @@ namespace NifOsg InverseWorldMatrix() { } - InverseWorldMatrix(const InverseWorldMatrix& copy, const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY) + InverseWorldMatrix(const InverseWorldMatrix& copy, const osg::CopyOp& op) : osg::Object(), osg::NodeCallback() { } diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index e62dc00e5..bcdcdf7dc 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -121,7 +121,7 @@ namespace SceneUtil : mLightManager(NULL) , mLastFrameNumber(0) {} - LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) + LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop) : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) , mLightManager(copy.mLightManager) , mLastFrameNumber(0) From 801dc8eee381e30c64a52d8c27513d3c284b940a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 20:17:21 +0100 Subject: [PATCH 06/27] ObstacleCheck: fix weird distance calculation --- apps/openmw/mwmechanics/obstacle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 53f12a982..b5c0dedd4 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -126,8 +126,8 @@ namespace MWMechanics if(mDistSameSpot == -1) mDistSameSpot = DIST_SAME_SPOT * (cls.getSpeed(actor) / 150); - bool samePosition = (std::abs(pos.pos[0] - mPrevX) < mDistSameSpot) && - (std::abs(pos.pos[1] - mPrevY) < mDistSameSpot); + bool samePosition = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2() < mDistSameSpot * mDistSameSpot; + // update position mPrevX = pos.pos[0]; mPrevY = pos.pos[1]; From caa523a9592c80abdacc102bc6a5c9d94b15af25 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 20:21:25 +0100 Subject: [PATCH 07/27] ObstacleCheck: fix the framerate not being taken into account --- apps/openmw/mwmechanics/obstacle.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index b5c0dedd4..078c31ac0 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -11,7 +11,7 @@ namespace MWMechanics { // NOTE: determined empirically but probably need further tweaking - static const float DIST_SAME_SPOT = 1.8f; + static const float DIST_SAME_SPOT = 0.72f; static const float DURATION_SAME_SPOT = 1.0f; static const float DURATION_TO_EVADE = 0.4f; @@ -114,19 +114,22 @@ namespace MWMechanics * t = how long before considered stuck * u = how long to move sideways * - * DIST_SAME_SPOT is calibrated for movement speed of around 150. - * A rat has walking speed of around 30, so we need to adjust for - * that. */ bool ObstacleCheck::check(const MWWorld::Ptr& actor, float duration) { const MWWorld::Class& cls = actor.getClass(); ESM::Position pos = actor.getRefData().getPosition(); + // actors can move at most 60 fps (the physics framerate). + // the max() can be removed if we implement physics interpolation. + float movementDuration = std::max(1/60.f, duration); + if(mDistSameSpot == -1) - mDistSameSpot = DIST_SAME_SPOT * (cls.getSpeed(actor) / 150); + mDistSameSpot = DIST_SAME_SPOT * cls.getSpeed(actor); + + float distSameSpot = mDistSameSpot * movementDuration; - bool samePosition = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2() < mDistSameSpot * mDistSameSpot; + bool samePosition = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2() < distSameSpot * distSameSpot; // update position mPrevX = pos.pos[0]; From d233bc483d195afbbacbad7b6b2c940bace024b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 20:26:18 +0100 Subject: [PATCH 08/27] ObstacleCheck: fix evasion issue The check if (samePosition... would not work as intended because actors do not move in every frame when the framerate is higher than the physics framerate. In that case the actor would change its evasion direction almost every frame. --- apps/openmw/mwmechanics/obstacle.cpp | 13 +++++-------- apps/openmw/mwmechanics/obstacle.hpp | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 078c31ac0..8c9ab3380 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -163,13 +163,13 @@ namespace MWMechanics { mStuckDuration = 0; mWalkState = State_Evade; + chooseEvasionDirection(); } } } /* FALL THROUGH */ case State_Evade: { - chooseEvasionDirection(samePosition); mEvadeDuration += duration; if(mEvadeDuration < DURATION_TO_EVADE) return true; @@ -191,16 +191,13 @@ namespace MWMechanics actorMovement.mPosition[1] = evadeDirections[mEvadeDirectionIndex][1]; } - void ObstacleCheck::chooseEvasionDirection(bool samePosition) + void ObstacleCheck::chooseEvasionDirection() { // change direction if attempt didn't work - if (samePosition && (0 < mEvadeDuration)) + ++mEvadeDirectionIndex; + if (mEvadeDirectionIndex == NUM_EVADE_DIRECTIONS) { - ++mEvadeDirectionIndex; - if (mEvadeDirectionIndex == NUM_EVADE_DIRECTIONS) - { - mEvadeDirectionIndex = 0; - } + mEvadeDirectionIndex = 0; } } diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index ecff00a5c..6b442f5a5 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -65,7 +65,7 @@ namespace MWMechanics float mDistSameSpot; // take account of actor's speed int mEvadeDirectionIndex; - void chooseEvasionDirection(bool samePosition); + void chooseEvasionDirection(); }; } From 3c338b9da994b0c0d2d222e3ef08ab1cf44daa6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Nov 2015 20:31:40 +0100 Subject: [PATCH 09/27] ObstacleCheck: tweak the stuck detection parameters The netch_betty wander animation starts up so slowly that the creature thought it was stuck, even though it's not. --- apps/openmw/mwmechanics/obstacle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 8c9ab3380..7def96bef 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -11,8 +11,8 @@ namespace MWMechanics { // NOTE: determined empirically but probably need further tweaking - static const float DIST_SAME_SPOT = 0.72f; - static const float DURATION_SAME_SPOT = 1.0f; + static const float DIST_SAME_SPOT = 0.5f; + static const float DURATION_SAME_SPOT = 1.5f; static const float DURATION_TO_EVADE = 0.4f; const float ObstacleCheck::evadeDirections[NUM_EVADE_DIRECTIONS][2] = From 637cd3a628e365899752a7a95e865e21fd854fa3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 01:01:41 +0100 Subject: [PATCH 10/27] Adjust the FirstPersonNeckController to follow the camera with a reduced factor (Fixes #1784) --- apps/openmw/mwmechanics/character.cpp | 2 ++ apps/openmw/mwrender/animation.hpp | 1 + apps/openmw/mwrender/npcanimation.cpp | 18 ++++++++++++++++-- apps/openmw/mwrender/npcanimation.hpp | 7 +++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c9b248984..129206f51 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1479,6 +1479,8 @@ bool CharacterController::updateWeaponState() } } + mAnimation->setAccurateAiming(mUpperBodyState > UpperCharState_WeapEquiped); + return forcestateupdate; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1e46cc71a..5aaa4071b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -439,6 +439,7 @@ public: virtual void setHeadYaw(float yawRadians); virtual float getHeadPitch() const; virtual float getHeadYaw() const; + virtual void setAccurateAiming(bool enabled) {} private: Animation(const Animation&); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 0b3838a33..815671266 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -281,7 +281,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mShowWeapons(false), mShowCarriedLeft(true), mNpcType(Type_Normal), - mSoundsDisabled(disableSounds) + mSoundsDisabled(disableSounds), + mAccurateAiming(false), + mAimingFactor(0.f) { mNpc = mPtr.get()->mBase; @@ -726,7 +728,14 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed) if (mFirstPersonNeckController) { - mFirstPersonNeckController->setRotate(osg::Quat(mPtr.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0))); + if (mAccurateAiming) + mAimingFactor = 1.f; + else + mAimingFactor = std::max(0.f, mAimingFactor - timepassed * 0.5f); + + float rotateFactor = 0.75f + 0.25f * mAimingFactor; + + mFirstPersonNeckController->setRotate(osg::Quat(mPtr.getRefData().getPosition().rot[0] * rotateFactor, osg::Vec3f(-1,0,0))); mFirstPersonNeckController->setOffset(mFirstPersonOffset); } @@ -1072,4 +1081,9 @@ void NpcAnimation::updatePtr(const MWWorld::Ptr &updated) mHeadAnimationTime->updatePtr(updated); } +void NpcAnimation::setAccurateAiming(bool enabled) +{ + mAccurateAiming = enabled; +} + } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index b4272226d..2289703c8 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -67,6 +67,9 @@ private: bool mSoundsDisabled; + bool mAccurateAiming; + float mAimingFactor; + void updateNpcBase(); PartHolderPtr insertBoundedPart(const std::string &model, const std::string &bonename, @@ -104,6 +107,10 @@ public: virtual void enableHeadAnimation(bool enable); + /// 1: the first person meshes follow the camera's rotation completely + /// 0: the first person meshes follow the camera with a reduced factor, so you can look down at your own hands + virtual void setAccurateAiming(bool enabled); + virtual void setWeaponGroup(const std::string& group); virtual osg::Vec3f runAnimation(float timepassed); From 91583fc027024e1cb80eed63d8a0a24f6eaa8ff0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 17:00:33 +0100 Subject: [PATCH 11/27] Fix MWRender::Mask_ParticleSystem --- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ components/resource/scenemanager.cpp | 17 +++++++++++++---- components/resource/scenemanager.hpp | 5 +++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 27ea7ebed..e0a0c75c6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -137,6 +137,8 @@ namespace MWRender , mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog")) , mNightEyeFactor(0.f) { + resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); + osg::ref_ptr lightRoot = new SceneUtil::LightManager; mLightRoot = lightRoot; lightRoot->setStartLight(1); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 08fa7bc9b..f2840574b 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -25,8 +25,10 @@ namespace class InitWorldSpaceParticlesVisitor : public osg::NodeVisitor { public: - InitWorldSpaceParticlesVisitor() + /// @param mask The node mask to set on ParticleSystem nodes. + InitWorldSpaceParticlesVisitor(unsigned int mask) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mMask(mask) { } @@ -47,7 +49,7 @@ namespace if (geode->getNumParents() && geode->getParent(0)->getNumParents()) transformInitialParticles(partsys, geode->getParent(0)->getParent(0)); } - geode->setNodeMask((1<<10)); //MWRender::Mask_ParticleSystem + geode->setNodeMask(mMask); } } } @@ -74,8 +76,9 @@ namespace box.expandBy(sphere); partsys->setInitialBound(box); } + private: + unsigned int mMask; }; - } namespace Resource @@ -84,6 +87,7 @@ namespace Resource SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager) : mVFS(vfs) , mTextureManager(textureManager) + , mParticleSystemMask(~0u) { } @@ -183,7 +187,7 @@ namespace Resource void SceneManager::notifyAttached(osg::Node *node) const { - InitWorldSpaceParticlesVisitor visitor; + InitWorldSpaceParticlesVisitor visitor (mParticleSystemMask); node->accept(visitor); } @@ -197,4 +201,9 @@ namespace Resource return mTextureManager; } + void SceneManager::setParticleSystemMask(unsigned int mask) + { + mParticleSystemMask = mask; + } + } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 168247a15..5ecb875ac 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -73,12 +73,17 @@ namespace Resource Resource::TextureManager* getTextureManager(); + /// @param mask The node mask to apply to loaded particle system nodes. + void setParticleSystemMask(unsigned int mask); + private: const VFS::Manager* mVFS; Resource::TextureManager* mTextureManager; osg::ref_ptr mIncrementalCompileOperation; + unsigned int mParticleSystemMask; + // observer_ptr? typedef std::map > Index; Index mIndex; From 35459f20d54602d6c465863cb7975e183c4607fa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 17:19:51 +0100 Subject: [PATCH 12/27] Refactor lighting mask --- apps/openmw/mwrender/animation.cpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 3 ++- apps/openmw/mwrender/vismask.hpp | 17 +++++++-------- apps/openmw/mwrender/water.cpp | 4 ++-- components/sceneutil/lightmanager.cpp | 25 ++++++++++++++++------- components/sceneutil/lightmanager.hpp | 13 +++++++++--- 6 files changed, 42 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 06065c566..c3ddbf297 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1066,6 +1066,7 @@ namespace MWRender osg::ref_ptr lightSource = new SceneUtil::LightSource; osg::Light* light = new osg::Light; lightSource->setLight(light); + lightSource->setNodeMask(Mask_Lighting); const MWWorld::Fallback* fallback = MWBase::Environment::get().getWorld()->getFallback(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e0a0c75c6..c55d11795 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -140,6 +140,7 @@ namespace MWRender resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); osg::ref_ptr lightRoot = new SceneUtil::LightManager; + lightRoot->setLightingMask(Mask_Lighting); mLightRoot = lightRoot; lightRoot->setStartLight(1); @@ -165,7 +166,7 @@ namespace MWRender mViewer->setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; - source->setNodeMask(SceneUtil::Mask_Lit); + source->setNodeMask(Mask_Lighting); mSunLight = new osg::Light; source->setLight(mSunLight); mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index a26bde1d1..dd6e85e2c 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -15,16 +15,16 @@ namespace MWRender Mask_Actor = (1<<3), Mask_Player = (1<<4), Mask_Sky = (1<<5), - Mask_Water = (1<<6), - Mask_Terrain = (1<<7), - Mask_FirstPerson = (1<<8), + Mask_Water = (1<<6), // choose Water or SimpleWater depending on detail required + Mask_SimpleWater = (1<<7), + Mask_Terrain = (1<<8), + Mask_FirstPerson = (1<<9), // child of Sky - Mask_Sun = (1<<9), - Mask_WeatherParticles = (1<<10), + Mask_Sun = (1<<10), + Mask_WeatherParticles = (1<<11), // child of Water - Mask_SimpleWater = (1<<11), // top level masks Mask_Scene = (1<<12), @@ -34,9 +34,10 @@ namespace MWRender Mask_ParticleSystem = (1<<14), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<15) + Mask_RenderToTexture = (1<<15), - // reserved: (1<<16) for SceneUtil::Mask_Lit + // Set on a camera's cull mask to enable the LightManager + Mask_Lighting = (1<<16) }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 80023ecda..e93060f7c 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -302,7 +302,7 @@ public: setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); setReferenceFrame(osg::Camera::RELATIVE_RF); - setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|(1<<16)); + setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); setNodeMask(Mask_RenderToTexture); setViewport(0, 0, rttSize, rttSize); @@ -378,7 +378,7 @@ public: setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); setReferenceFrame(osg::Camera::RELATIVE_RF); - setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); + setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|Mask_Lighting); setNodeMask(Mask_RenderToTexture); unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 1e1d04cf5..dc6da73a6 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -131,6 +131,7 @@ namespace SceneUtil LightManager::LightManager() : mStartLight(0) + , mLightingMask(~0u) { setUpdateCallback(new LightManagerUpdateCallback); } @@ -138,10 +139,21 @@ namespace SceneUtil LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op) : osg::Group(copy, copyop) , mStartLight(copy.mStartLight) + , mLightingMask(copy.mLightingMask) { } + void LightManager::setLightingMask(unsigned int mask) + { + mLightingMask = mask; + } + + unsigned int LightManager::getLightingMask() const + { + return mLightingMask; + } + void LightManager::update() { mLights.clear(); @@ -237,7 +249,6 @@ namespace SceneUtil LightSource::LightSource() : mRadius(0.f) { - setNodeMask(Mask_Lit); setUpdateCallback(new CollectLightCallback); mId = sLightId++; } @@ -260,12 +271,6 @@ namespace SceneUtil { osgUtil::CullVisitor* cv = static_cast(nv); - if (!(cv->getCurrentCamera()->getCullMask()&Mask_Lit)) - { - traverse(node, nv); - return; - } - if (!mLightManager) { mLightManager = findLightManager(nv->getNodePath()); @@ -276,6 +281,12 @@ namespace SceneUtil } } + if (!(cv->getCurrentCamera()->getCullMask() & mLightManager->getLightingMask())) + { + traverse(node, nv); + return; + } + // Possible optimizations: // - cull list of lights by the camera frustum // - organize lights in a quad tree diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index bcdcdf7dc..27ee1cdaa 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -9,9 +9,6 @@ namespace SceneUtil { - // This mask should be included in the Cull and Update visitor's traversal mask if lighting is desired. - const int Mask_Lit = (1<<16); - /// LightSource managed by a LightManager. class LightSource : public osg::Node { @@ -68,6 +65,14 @@ namespace SceneUtil LightManager(const LightManager& copy, const osg::CopyOp& copyop); + /// @param mask This mask is compared with the current Camera's cull mask to determine if lighting is desired. + /// By default, it's ~0u i.e. always on. + /// If you have some views that do not require lighting, then set the Camera's cull mask to not include + /// the lightingMask for a much faster cull and rendering. + void setLightingMask (unsigned int mask); + + unsigned int getLightingMask() const; + // Called automatically by the UpdateCallback void update(); @@ -111,6 +116,8 @@ namespace SceneUtil LightStateSetMap mStateSetCache; int mStartLight; + + unsigned int mLightingMask; }; /// @note Not thread safe for CullThreadPerCamera threading mode. From f1ac408f352fed6c5520b6bae1b6c120ff4873bb Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 18:21:56 +0100 Subject: [PATCH 13/27] Place Drawables directly in the scene graph when built with OSG 3.4 OSG 3.4 adds the ability to place Drawables directly in the scene graph, without a Geode decorating them. Leveraging this should give a small performance boost, because the redundant Geodes increase culling overhead. There is still an oustanding issue with the RemoveDrawableVisitor no longer working correctly, because Drawables can have multiple parents. --- apps/openmw/mwrender/animation.cpp | 22 ++++++++++++ apps/openmw/mwrender/objects.cpp | 9 +++++ apps/openmw/mwrender/sky.cpp | 47 ++++++++++++------------ components/nifosg/nifloader.cpp | 53 +++++++++++++++++++++------- components/resource/scenemanager.cpp | 48 +++++++++++++++++-------- components/sceneutil/visitor.cpp | 12 ++++--- components/sceneutil/visitor.hpp | 1 + 7 files changed, 137 insertions(+), 55 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c3ddbf297..c2cbb4627 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -196,10 +197,18 @@ namespace traverse(node); } +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) + virtual void apply(osg::Drawable& drw) + { + mToRemove.push_back(&drw); + } +#endif + void remove() { for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) { + // FIXME: a Drawable might have more than one parent osg::Node* node = *it; if (node->getNumParents()) node->getParent(0)->removeChild(node); @@ -219,6 +228,18 @@ namespace } virtual void apply(osg::Geode &node) + { + applyImpl(node); + } + +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) + virtual void apply(osg::Drawable& drw) + { + applyImpl(drw); + } +#endif + + void applyImpl(osg::Node& node) { const std::string toFind = "tri bip"; if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0) @@ -232,6 +253,7 @@ namespace { for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) { + // FIXME: a Drawable might have more than one parent osg::Node* node = *it; if (node->getNumParents()) node->getParent(0)->removeChild(node); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index bdefdcafa..9f4fe2de2 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -54,11 +55,19 @@ namespace for (std::vector::iterator it = partsysVector.begin(); it != partsysVector.end(); ++it) geode.removeDrawable(*it); } +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) + virtual void apply(osg::Drawable& drw) + { + if (osgParticle::ParticleSystem* partsys = dynamic_cast(&drw)) + mToRemove.push_back(partsys); + } +#endif void remove() { for (std::vector >::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) { + // FIXME: a Drawable might have more than one parent osg::Node* node = *it; if (node->getNumParents()) node->getParent(0)->removeChild(node); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 5c38d79d4..7d38308b1 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -351,33 +351,36 @@ public: for (unsigned int i=0; iasGeometry(); - if (!geom) - continue; - - osg::ref_ptr colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements()); - for (unsigned int i=0; isize(); ++i) + osg::ref_ptr colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements()); + for (unsigned int i=0; isize(); ++i) + { + float alpha = 1.f; + if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row + else if (mMeshType == 1) { - float alpha = 1.f; - if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row - else if (mMeshType == 1) - { - if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row - else if (i>= 33 && i <= 48) alpha = 0.25098; // second row - else alpha = 1.f; - } - else if (mMeshType == 2) - { - osg::Vec4Array* origColors = static_cast(geom->getColorArray()); - alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f; - } - - (*colors)[i] = osg::Vec4f(0.f, 0.f, 0.f, alpha); + if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row + else if (i>= 33 && i <= 48) alpha = 0.25098; // second row + else alpha = 1.f; + } + else if (mMeshType == 2) + { + osg::Vec4Array* origColors = static_cast(geom->getColorArray()); + alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f; } - geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX); + (*colors)[i] = osg::Vec4f(0.f, 0.f, 0.f, alpha); } + + geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX); } private: diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 49bc7b0fb..b926d7eea 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -5,6 +5,7 @@ #include #include #include +#include // resource #include @@ -885,9 +886,6 @@ namespace NifOsg // localToWorldMatrix for transforming to particle space handleParticlePrograms(partctrl->affectors, partctrl->colliders, parentNode, partsys.get(), rf); - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(partsys); - std::vector drawableProps; collectDrawableProperties(nifNode, drawableProps); applyDrawableProperties(parentNode, drawableProps, composite, true, animflags); @@ -907,13 +905,21 @@ namespace NifOsg updater->addParticleSystem(partsys); parentNode->addChild(updater); +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(partsys); + osg::Node* toAttach = geode.get(); +#else + osg::Node* toAttach = partsys.get(); +#endif + if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) - parentNode->addChild(geode); + parentNode->addChild(toAttach); else { osg::MatrixTransform* trans = new osg::MatrixTransform; trans->setUpdateCallback(new InverseWorldMatrix); - trans->addChild(geode); + trans->addChild(toAttach); parentNode->addChild(trans); } } @@ -957,8 +963,6 @@ namespace NifOsg void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { - osg::ref_ptr geode (new osg::Geode); - osg::ref_ptr geometry; for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -981,21 +985,36 @@ namespace NifOsg triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) + osg::ref_ptr geode (new osg::Geode); geode->addDrawable(geometry); +#endif if (geometry->getDataVariance() == osg::Object::DYNAMIC) { // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch // This is so we can set the DataVariance as STATIC, giving a huge performance boost geometry->setDataVariance(osg::Object::STATIC); - osg::ref_ptr geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); osg::ref_ptr frameswitch = new FrameSwitch; + +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) + osg::ref_ptr geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); frameswitch->addChild(geode); frameswitch->addChild(geode2); +#else + osg::ref_ptr geom2 = static_cast(osg::clone(geometry.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); + frameswitch->addChild(geometry); + frameswitch->addChild(geom2); +#endif + parentNode->addChild(frameswitch); } else +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) parentNode->addChild(geode); +#else + parentNode->addChild(geometry); +#endif } osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) @@ -1056,8 +1075,6 @@ namespace NifOsg void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { - osg::ref_ptr geode (new osg::Geode); - osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); @@ -1090,17 +1107,27 @@ namespace NifOsg } rig->setInfluenceMap(map); - geode->addDrawable(rig); - // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch // This is so we can set the DataVariance as STATIC, giving a huge performance boost rig->setDataVariance(osg::Object::STATIC); + + osg::ref_ptr frameswitch = new FrameSwitch; + +#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(rig); + osg::Geode* geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES| osg::CopyOp::DEEP_COPY_DRAWABLES)); - osg::ref_ptr frameswitch = new FrameSwitch; frameswitch->addChild(geode); frameswitch->addChild(geode2); +#else + SceneUtil::RigGeometry* rig2 = static_cast(osg::clone(rig.get(), osg::CopyOp::DEEP_COPY_NODES| + osg::CopyOp::DEEP_COPY_DRAWABLES)); + frameswitch->addChild(rig); + frameswitch->addChild(rig2); +#endif parentNode->addChild(frameswitch); } diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index f2840574b..20bee13d1 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -32,30 +33,47 @@ namespace { } - void apply(osg::Node& node) + bool isWorldSpaceParticleSystem(osgParticle::ParticleSystem* partsys) { - if (osg::Geode* geode = node.asGeode()) + // HACK: ParticleSystem has no getReferenceFrame() + return (partsys->getUserDataContainer() + && partsys->getUserDataContainer()->getNumDescriptions() > 0 + && partsys->getUserDataContainer()->getDescriptions()[0] == "worldspace"); + } + + void apply(osg::Geode& geode) + { + for (unsigned int i=0;igetNumDrawables();++i) + if (osgParticle::ParticleSystem* partsys = dynamic_cast(geode.getDrawable(i))) { - if (osgParticle::ParticleSystem* partsys = dynamic_cast(geode->getDrawable(i))) + if (isWorldSpaceParticleSystem(partsys)) { - // HACK: ParticleSystem has no getReferenceFrame() - if (partsys->getUserDataContainer() - && partsys->getUserDataContainer()->getNumDescriptions() > 0 - && partsys->getUserDataContainer()->getDescriptions()[0] == "worldspace") - { - // HACK: Ignore the InverseWorldMatrix transform the geode is attached to - if (geode->getNumParents() && geode->getParent(0)->getNumParents()) - transformInitialParticles(partsys, geode->getParent(0)->getParent(0)); - } - geode->setNodeMask(mMask); + // HACK: Ignore the InverseWorldMatrix transform the geode is attached to + if (geode.getNumParents() && geode.getParent(0)->getNumParents()) + transformInitialParticles(partsys, geode.getParent(0)->getParent(0)); } + geode.setNodeMask(mMask); } } + } - traverse(node); +#if OSG_MIN_VERSION_REQUIRED(3,3,3) + // in OSG 3.3 and up Drawables can be directly in the scene graph without a Geode decorating them. + void apply(osg::Drawable& drw) + { + if (osgParticle::ParticleSystem* partsys = dynamic_cast(&drw)) + { + if (isWorldSpaceParticleSystem(partsys)) + { + // HACK: Ignore the InverseWorldMatrix transform the particle system is attached to + if (partsys->getNumParents() && partsys->getParent(0)->getNumParents()) + transformInitialParticles(partsys, partsys->getParent(0)->getParent(0)); + } + partsys->setNodeMask(mMask); + } } +#endif void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node) { diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 3738be08d..0a5ad2d00 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -22,11 +22,13 @@ namespace SceneUtil void DisableFreezeOnCullVisitor::apply(osg::Geode &geode) { for (unsigned int i=0; i(drw)) - partsys->setFreezeOnCull(false); - } + apply(*geode.getDrawable(i)); + } + + void DisableFreezeOnCullVisitor::apply(osg::Drawable& drw) + { + if (osgParticle::ParticleSystem* partsys = dynamic_cast(&drw)) + partsys->setFreezeOnCull(false); } } diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index 656084940..dcfefe9cd 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -35,6 +35,7 @@ namespace SceneUtil } virtual void apply(osg::Geode &geode); + virtual void apply(osg::Drawable& drw); }; } From 0409e5a043d1d2db1c07aded5f73e5a8b2a9b25b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 18:28:58 +0100 Subject: [PATCH 14/27] Use OSG_VERSION_GREATER_EQUAL / LESS_THAN rather than MIN_VERSION_REQUIRED (cosmetic change) --- apps/openmw/mwrender/sky.cpp | 2 +- components/nifosg/nifloader.cpp | 10 +++++----- components/resource/scenemanager.cpp | 2 +- components/resource/texturemanager.cpp | 2 +- components/sceneutil/controller.cpp | 4 ++-- components/sceneutil/riggeometry.cpp | 2 +- components/sdlutil/sdlgraphicswindow.cpp | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 7d38308b1..66253f70d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1271,7 +1271,7 @@ public: if (stateset->getAttribute(osg::StateAttribute::MATERIAL)) { SceneUtil::CompositeStateSetUpdater* composite = NULL; -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::Callback* callback = node.getUpdateCallback(); #else osg::NodeCallback* callback = node.getUpdateCallback(); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b926d7eea..ccf840dfe 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -905,7 +905,7 @@ namespace NifOsg updater->addParticleSystem(partsys); parentNode->addChild(updater); -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) osg::ref_ptr geode (new osg::Geode); geode->addDrawable(partsys); osg::Node* toAttach = geode.get(); @@ -985,7 +985,7 @@ namespace NifOsg triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) osg::ref_ptr geode (new osg::Geode); geode->addDrawable(geometry); #endif @@ -997,7 +997,7 @@ namespace NifOsg geometry->setDataVariance(osg::Object::STATIC); osg::ref_ptr frameswitch = new FrameSwitch; -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) osg::ref_ptr geode2 = static_cast(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES)); frameswitch->addChild(geode); frameswitch->addChild(geode2); @@ -1010,7 +1010,7 @@ namespace NifOsg parentNode->addChild(frameswitch); } else -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) parentNode->addChild(geode); #else parentNode->addChild(geometry); @@ -1113,7 +1113,7 @@ namespace NifOsg osg::ref_ptr frameswitch = new FrameSwitch; -#if not(OSG_MIN_VERSION_REQUIRED(3,3,3)) +#if OSG_VERSION_LESS_THAN(3,3,3) osg::ref_ptr geode (new osg::Geode); geode->addDrawable(rig); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 20bee13d1..eb4a4992d 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -58,7 +58,7 @@ namespace } } -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) // in OSG 3.3 and up Drawables can be directly in the scene graph without a Geode decorating them. void apply(osg::Drawable& drw) { diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index c2f76a527..8b80efcdc 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -119,7 +119,7 @@ namespace Resource case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): { -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); if (exts && !exts->isTextureCompressionS3TCSupported // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index a2c1cdcd3..7762b48d0 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -65,7 +65,7 @@ namespace SceneUtil void ControllerVisitor::apply(osg::Node &node) { -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::Callback* callback = node.getUpdateCallback(); #else osg::NodeCallback* callback = node.getUpdateCallback(); @@ -96,7 +96,7 @@ namespace SceneUtil { osg::Drawable* drw = geode.getDrawable(i); -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) osg::Callback* callback = drw->getUpdateCallback(); #else osg::Drawable::UpdateCallback* callback = drw->getUpdateCallback(); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index ac29ee3e8..bd3d613a3 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -288,7 +288,7 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) _boundingBox = box; _boundingBoxComputed = true; -#if OSG_MIN_VERSION_REQUIRED(3,3,3) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) // in OSG 3.3.3 and up Drawable inherits from Node, so has a bounding sphere as well. _boundingSphere = osg::BoundingSphere(_boundingBox); _boundingSphereComputed = true; diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index 84aafa100..da4b666ec 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -109,7 +109,7 @@ void GraphicsWindowSDL2::init() mValid = true; -#if OSG_MIN_VERSION_REQUIRED(3,3,4) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,4) getEventQueue()->syncWindowRectangleWithGraphicsContext(); #else getEventQueue()->syncWindowRectangleWithGraphcisContext(); @@ -130,7 +130,7 @@ bool GraphicsWindowSDL2::realizeImplementation() SDL_ShowWindow(mWindow); -#if OSG_MIN_VERSION_REQUIRED(3,3,4) +#if OSG_VERSION_GREATER_OR_EQUAL(3,3,4) getEventQueue()->syncWindowRectangleWithGraphicsContext(); #else getEventQueue()->syncWindowRectangleWithGraphcisContext(); From 7776c49fc15a921d2e81bf24c46be88de80f8157 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 18:42:59 +0100 Subject: [PATCH 15/27] GraphicsWindowSDL2: adjust the log levels --- components/sdlutil/sdlgraphicswindow.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index da4b666ec..49afe32a8 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -2,7 +2,6 @@ #include -#include #include namespace SDLUtil @@ -79,15 +78,13 @@ void GraphicsWindowSDL2::init() if(!_traits.valid()) return; - // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get()); - WindowData *inheritedWindowData = dynamic_cast(_traits->inheritedWindowData.get()); mWindow = inheritedWindowData ? inheritedWindowData->mWindow : NULL; mOwnsWindow = (mWindow == 0); if(mOwnsWindow) { - OSG_NOTICE<<"Error: No SDL window provided."< Date: Tue, 10 Nov 2015 21:45:53 +0100 Subject: [PATCH 16/27] Fix self-referencing camera --- apps/openmw/mwrender/globalmap.cpp | 10 ++++------ apps/openmw/mwrender/localmap.cpp | 12 +++++------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 3445e4189..1e0a9112f 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -62,9 +62,8 @@ namespace class CameraUpdateGlobalCallback : public osg::NodeCallback { public: - CameraUpdateGlobalCallback(osg::Camera* cam, MWRender::GlobalMap* parent) + CameraUpdateGlobalCallback(MWRender::GlobalMap* parent) : mRendered(false) - , mCamera(cam) , mParent(parent) { } @@ -73,7 +72,7 @@ namespace { if (mRendered) { - mCamera->setNodeMask(0); + node->setNodeMask(0); return; } @@ -82,13 +81,12 @@ namespace if (!mRendered) { mRendered = true; - mParent->markForRemoval(mCamera); + mParent->markForRemoval(static_cast(node)); } } private: bool mRendered; - osg::ref_ptr mCamera; MWRender::GlobalMap* mParent; }; @@ -263,7 +261,7 @@ namespace MWRender else camera->setClearMask(GL_NONE); - camera->setUpdateCallback(new CameraUpdateGlobalCallback(camera, this)); + camera->setUpdateCallback(new CameraUpdateGlobalCallback(this)); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); camera->attach(osg::Camera::COLOR_BUFFER, mOverlayTexture); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index e479119ee..14ec770e8 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -30,22 +30,21 @@ namespace class CameraLocalUpdateCallback : public osg::NodeCallback { public: - CameraLocalUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) + CameraLocalUpdateCallback(MWRender::LocalMap* parent) : mRendered(false) - , mCamera(cam) , mParent(parent) { } - virtual void operator()(osg::Node*, osg::NodeVisitor*) + virtual void operator()(osg::Node* node, osg::NodeVisitor*) { if (mRendered) - mCamera->setNodeMask(0); + node->setNodeMask(0); if (!mRendered) { mRendered = true; - mParent->markForRemoval(mCamera); + mParent->markForRemoval(static_cast(node)); } // Note, we intentionally do not traverse children here. The map camera's scene data is the same as the master camera's, @@ -55,7 +54,6 @@ namespace private: bool mRendered; - osg::ref_ptr mCamera; MWRender::LocalMap* mParent; }; @@ -205,7 +203,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setStateSet(stateset); camera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); camera->setViewport(0, 0, mMapResolution, mMapResolution); - camera->setUpdateCallback(new CameraLocalUpdateCallback(camera, this)); + camera->setUpdateCallback(new CameraLocalUpdateCallback(this)); return camera; } From b840c68f0c5ad860a074be71e851d6298d8cc717 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Nov 2015 21:46:40 +0100 Subject: [PATCH 17/27] Do not create a depth buffer for the global map 2d rendering --- apps/openmw/mwrender/globalmap.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 1e0a9112f..f91f7674f 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -266,6 +266,9 @@ namespace MWRender camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); camera->attach(osg::Camera::COLOR_BUFFER, mOverlayTexture); + // no need for a depth buffer + camera->setImplicitBufferAttachmentMask(osg::DisplaySettings::IMPLICIT_COLOR_BUFFER_ATTACHMENT); + if (cpuCopy) { // Attach an image to copy the render back to the CPU when finished @@ -286,10 +289,12 @@ namespace MWRender { osg::ref_ptr geom = createTexturedQuad(srcLeft, srcTop, srcRight, srcBottom); osg::ref_ptr depth = new osg::Depth; - depth->setFunction(osg::Depth::ALWAYS); - geom->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); - geom->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - geom->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + depth->setWriteMask(0); + osg::StateSet* stateset = geom->getOrCreateStateSet(); + stateset->setAttribute(depth); + stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); osg::ref_ptr geode = new osg::Geode; geode->addDrawable(geom); camera->addChild(geode); From 2e9805fa0ee57fa5d724c04f8c2230cc0ba5a927 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 00:50:57 +0100 Subject: [PATCH 18/27] Leak fix --- apps/openmw/mwrender/characterpreview.cpp | 9 ++++----- apps/openmw/mwrender/characterpreview.hpp | 3 ++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index eb950ea79..f7296b1bd 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -157,11 +157,10 @@ namespace MWRender void CharacterPreview::rebuild() { - delete mAnimation; - mAnimation = NULL; + mAnimation.reset(NULL); - mAnimation = new NpcAnimation(mCharacter, mNode, mResourceSystem, true, true, - (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); + mAnimation.reset(new NpcAnimation(mCharacter, mNode, mResourceSystem, true, true, + (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal))); onSetup(); @@ -194,7 +193,7 @@ namespace MWRender void InventoryPreview::update() { - if (!mAnimation) + if (!mAnimation.get()) return; mAnimation->showWeapons(true); diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 0f85cc3bf..32c1850c6 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -2,6 +2,7 @@ #define MWRENDER_CHARACTERPREVIEW_H #include +#include #include @@ -61,7 +62,7 @@ namespace MWRender MWWorld::Ptr mCharacter; - MWRender::NpcAnimation* mAnimation; + std::auto_ptr mAnimation; osg::ref_ptr mNode; std::string mCurrentAnimGroup; From fc93dc619578eff74c647ee35a3875b4c79332ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 01:32:31 +0100 Subject: [PATCH 19/27] Remove a stray method declaration --- components/nifosg/particle.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 043489865..bfb127218 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -139,9 +139,6 @@ namespace NifOsg META_Object(NifOsg, ParticleColorAffector) - // TODO: very similar to vec3 version, refactor to a template - osg::Vec4f interpolate(const float time, const Nif::Vector4KeyMap::MapType& keys); - virtual void operate(osgParticle::Particle* particle, double dt); private: From c62c1693e9dd3741b44d84faabf119ef20c08d3d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 01:47:11 +0100 Subject: [PATCH 20/27] Disable copy constructor and operator= in PartHolder --- apps/openmw/mwrender/animation.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 5aaa4071b..b1c34576b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -61,6 +61,9 @@ public: private: osg::ref_ptr mNode; + + void operator= (const PartHolder&); + PartHolder(const PartHolder&); }; typedef boost::shared_ptr PartHolderPtr; From afa590bddb5a991cd35aeabd17f43e3ae2fb0e1f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 16:04:17 +0100 Subject: [PATCH 21/27] Leak fix --- apps/openmw/mwrender/rotatecontroller.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/rotatecontroller.hpp b/apps/openmw/mwrender/rotatecontroller.hpp index 8c3758cb0..456a6dd20 100644 --- a/apps/openmw/mwrender/rotatecontroller.hpp +++ b/apps/openmw/mwrender/rotatecontroller.hpp @@ -27,7 +27,7 @@ protected: bool mEnabled; osg::Quat mRotate; - osg::ref_ptr mRelativeTo; + osg::Node* mRelativeTo; }; From 1edcb219a70f757221810e8c5861dc58972bd691 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 16:27:17 +0100 Subject: [PATCH 22/27] Leak fix --- components/nifosg/nifloader.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index ccf840dfe..3e7f47b6f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1407,7 +1407,7 @@ namespace NifOsg osg::StateSet* stateset = node->getOrCreateStateSet(); int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty - osg::Material* mat = new osg::Material; + osg::ref_ptr mat (new osg::Material); mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); // NIF material defaults don't match OpenGL defaults @@ -1462,12 +1462,11 @@ namespace NifOsg case Nif::RC_NiAlphaProperty: { const Nif::NiAlphaProperty* alphaprop = static_cast(property); - osg::BlendFunc* blendfunc = new osg::BlendFunc; if (alphaprop->flags&1) { - blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), - getBlendMode((alphaprop->flags>>5)&0xf)); - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); + stateset->setAttributeAndModes(new osg::BlendFunc(getBlendMode((alphaprop->flags>>1)&0xf), + getBlendMode((alphaprop->flags>>5)&0xf)), + osg::StateAttribute::ON); bool noSort = (alphaprop->flags>>13)&1; if (!noSort) @@ -1482,11 +1481,10 @@ namespace NifOsg stateset->setRenderBinToInherit(); } - osg::AlphaFunc* alphafunc = new osg::AlphaFunc; if((alphaprop->flags>>9)&1) { - alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); - stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); + stateset->setAttributeAndModes(new osg::AlphaFunc(getTestMode((alphaprop->flags>>10)&0x7), + alphaprop->data.threshold/255.f), osg::StateAttribute::ON); } else { From 0a52ee17c31851a3c9ad4ea576d0782a1f8feb2c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:04:06 +0100 Subject: [PATCH 23/27] Fix Drawable removal issues --- apps/openmw/mwrender/animation.cpp | 88 +++++++++++++++--------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c2cbb4627..b5f0a2036 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -175,58 +175,71 @@ namespace return 0.0f; } - - // Removes all drawables from a graph. - class RemoveDrawableVisitor : public osg::NodeVisitor + /// @brief Base class for visitors that remove nodes from a scene graph. + /// Subclasses need to fill the mToRemove vector. + /// To use, node->accept(removeVisitor); removeVisitor.remove(); + class RemoveVisitor : public osg::NodeVisitor { public: - RemoveDrawableVisitor() + RemoveVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { } - virtual void apply(osg::Geode &node) + void remove() { - // Not safe to remove in apply(), since the visitor is still iterating the child list - osg::Group* parent = node.getParent(0); - // prune nodes that would be empty after the removal - if (parent->getNumChildren() == 1 && parent->getDataVariance() == osg::Object::STATIC) - mToRemove.push_back(parent); - else - mToRemove.push_back(&node); - traverse(node); + for (RemoveVec::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + it->second->removeChild(it->first); + } + + protected: + // + typedef std::vector > RemoveVec; + std::vector > mToRemove; + }; + + // Removes all drawables from a graph. + class RemoveDrawableVisitor : public RemoveVisitor + { + public: + virtual void apply(osg::Geode &geode) + { + applyImpl(geode); } #if OSG_VERSION_GREATER_OR_EQUAL(3,3,3) virtual void apply(osg::Drawable& drw) { - mToRemove.push_back(&drw); + applyImpl(drw); } #endif - void remove() + void applyImpl(osg::Node& node) { - for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + osg::NodePath::iterator parent = getNodePath().end()-2; + // We know that the parent is a Group because only Groups can have children. + osg::Group* parentGroup = static_cast(*parent); + + // Try to prune nodes that would be empty after the removal + if (parent != getNodePath().begin()) { - // FIXME: a Drawable might have more than one parent - osg::Node* node = *it; - if (node->getNumParents()) - node->getParent(0)->removeChild(node); + // This could be extended to remove the parent's parent, and so on if they are empty as well. + // But for NIF files, there won't be a benefit since only TriShapes can be set to STATIC dataVariance. + osg::Group* parentParent = static_cast(*(parent - 1)); + if (parentGroup->getNumChildren() == 1 && parentGroup->getDataVariance() == osg::Object::STATIC) + { + mToRemove.push_back(std::make_pair(parentGroup, parentParent)); + return; + } } - } - private: - std::vector mToRemove; + mToRemove.push_back(std::make_pair(&node, parentGroup)); + } }; - class RemoveTriBipVisitor : public osg::NodeVisitor + class RemoveTriBipVisitor : public RemoveVisitor { public: - RemoveTriBipVisitor() - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - { - } - virtual void apply(osg::Geode &node) { applyImpl(node); @@ -244,24 +257,11 @@ namespace const std::string toFind = "tri bip"; if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0) { + osg::Group* parent = static_cast(*(getNodePath().end()-2)); // Not safe to remove in apply(), since the visitor is still iterating the child list - mToRemove.push_back(&node); + mToRemove.push_back(std::make_pair(&node, parent)); } } - - void remove() - { - for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) - { - // FIXME: a Drawable might have more than one parent - osg::Node* node = *it; - if (node->getNumParents()) - node->getParent(0)->removeChild(node); - } - } - - private: - std::vector mToRemove; }; } From 9c503cbd8c0b9f4235e3f7ca0be18c43931684d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:07:31 +0100 Subject: [PATCH 24/27] Add build* to the gitignore Allows one to have multiple build folders, e.g. a separate build for a different OSG versions, or for different OpenMW versions, or when you often switch between branches. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 88f591aae..e1abcaa63 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ CMakeCache.txt cmake_install.cmake Makefile makefile -build +build* prebuilt ## doxygen From 02148a43f5da34d3d4be31adf9c148e9de8951d0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:22:31 +0100 Subject: [PATCH 25/27] Node mask fix --- apps/openmw/mwrender/animation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b5f0a2036..55a47d4b6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1317,6 +1317,7 @@ namespace MWRender { mGlowLight = new SceneUtil::LightSource; mGlowLight->setLight(new osg::Light); + mGlowLight->setNodeMask(Mask_Lighting); osg::Light* light = mGlowLight->getLight(); light->setDiffuse(osg::Vec4f(0,0,0,0)); light->setSpecular(osg::Vec4f(0,0,0,0)); From 79c44d0bfe33deb2ccacda73ac631cdb31931133 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:23:47 +0100 Subject: [PATCH 26/27] Style fix --- apps/openmw/mwrender/camera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index ea8c60bf3..1d43cde43 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -381,7 +381,7 @@ namespace MWRender osg::PositionAttitudeTransform* transform = mTrackingPtr.getRefData().getBaseNode(); mTrackingNode = transform; if (transform) - mHeightScale = mTrackingPtr.getRefData().getBaseNode()->getScale().z(); + mHeightScale = transform->getScale().z(); else mHeightScale = 1.f; } From a68fd791c849d0820d3286921cc6ffa46b54258f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Nov 2015 17:24:27 +0100 Subject: [PATCH 27/27] Remove a stray method declaration --- apps/openmw/mwrender/camera.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index 899fc9447..fab63cd3f 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -98,8 +98,6 @@ namespace MWRender bool isFirstPerson() const { return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); } - void updateScale(); - void processViewChange(); void update(float duration, bool paused=false);