From f142f9bf8634faa984d121e9db8711d36950e7b0 Mon Sep 17 00:00:00 2001 From: LohikaarmeHav Date: Wed, 27 Jul 2016 21:35:05 +0300 Subject: [PATCH 01/20] wtf --- CMakeLists.txt | 1 - apps/opencs/view/world/dragrecordtable.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 133d9f7e6..0790c0878 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -802,7 +802,6 @@ if (APPLE) set(\${default_embedded_path_var} \"\${path}\" PARENT_SCOPE) endif() endfunction() - cmake_policy(SET CMP0009 OLD) fixup_bundle(\"${INSTALLED_OPENMW_APP}\" \"${PLUGINS}\" \"\") fixup_bundle(\"${INSTALLED_OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"\") diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index a5f933283..8bb5659fd 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -62,7 +62,7 @@ void CSVWorld::DragRecordTable::dragMoveEvent(QDragMoveEvent *event) } void CSVWorld::DragRecordTable::dropEvent(QDropEvent *event) -{ +{(void)write(1,"H\n",2); QModelIndex index = indexAt(event->pos()); CSMWorld::ColumnBase::Display display = getIndexDisplayType(index); if (CSVWorld::DragDropUtils::canAcceptData(*event, display)) From c6ec473280d00a4f8b92ca13b1335472f5edae5f Mon Sep 17 00:00:00 2001 From: LohikaarmeHav Date: Tue, 2 Aug 2016 13:46:43 +0300 Subject: [PATCH 02/20] Camera reset now every time cell object->view is pressed. --- CMakeLists.txt | 1 + apps/opencs/model/world/cellcoordinates.hpp | 2 ++ apps/opencs/view/render/pagedworldspacewidget.cpp | 8 ++++++-- apps/opencs/view/render/pagedworldspacewidget.hpp | 2 ++ apps/opencs/view/render/scenewidget.cpp | 11 +---------- apps/opencs/view/render/scenewidget.hpp | 3 --- 6 files changed, 12 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 373301ddc..aa6d76a4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -810,6 +810,7 @@ if (APPLE) set(\${default_embedded_path_var} \"\${path}\" PARENT_SCOPE) endif() endfunction() + cmake_policy(SET CMP0009 OLD) fixup_bundle(\"${INSTALLED_OPENMW_APP}\" \"${PLUGINS}\" \"\") fixup_bundle(\"${INSTALLED_OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"\") diff --git a/apps/opencs/model/world/cellcoordinates.hpp b/apps/opencs/model/world/cellcoordinates.hpp index f8851a6d9..6ff4e4b5d 100644 --- a/apps/opencs/model/world/cellcoordinates.hpp +++ b/apps/opencs/model/world/cellcoordinates.hpp @@ -38,7 +38,9 @@ namespace CSMWorld /// \note The worldspace part of \a id is ignored static std::pair fromId (const std::string& id); + /// \return cell coordinates such that given world coordinates are in it. static std::pair coordinatesToCellIndex (float x, float y); + }; bool operator== (const CellCoordinates& left, const CellCoordinates& right); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index a01df4392..3baf4e972 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -17,6 +17,7 @@ #include "editmode.hpp" #include "mask.hpp" +#include "cameracontroller.hpp" bool CSVRender::PagedWorldspaceWidget::adjustCells() { @@ -477,12 +478,15 @@ void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) { char ignore1; // : or ; char ignore2; // # + // Current coordinate int x, y; + // Loop throught all the coordinates to add them to selection while (stream >> ignore1 >> ignore2 >> x >> y) selection.add (CSMWorld::CellCoordinates (x, y)); - - /// \todo adjust camera position + + // Setup camera + mCurrentCamControl->setup(mRootNode, Mask_Reference | Mask_Terrain, CameraController::WorldUp); } } else if (hint[0]=='r') diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 692000708..e96cb9e8e 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -83,6 +83,8 @@ namespace CSVRender virtual ~PagedWorldspaceWidget(); + /// \brief Decodes the the hint string to set of cell that are rendered. + /// Calculates avarage of cell's coordinates to be new camera location. void useViewHint (const std::string& hint); void setCellSelection(const CSMWorld::CellSelection& selection); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index b2b5b30d6..a36ff8c49 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -31,7 +31,6 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) , mRootNode(0) { - osgViewer::CompositeViewer& viewer = CompositeViewer::get(); osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); @@ -314,15 +313,7 @@ void SceneWidget::keyReleaseEvent (QKeyEvent *event) void SceneWidget::update(double dt) { - if (mCamPositionSet) - { - mCurrentCamControl->update(dt); - } - else - { - mCurrentCamControl->setup(mRootNode, Mask_Reference | Mask_Terrain, CameraController::WorldUp); - mCamPositionSet = true; - } + mCurrentCamControl->update(dt); } void SceneWidget::settingChanged (const CSMPrefs::Setting *setting) diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 4df49543a..d3ab28adc 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -121,9 +121,6 @@ namespace CSVRender std::map, std::string> mButtonMapping; - private: - bool mCamPositionSet; - public slots: void update(double dt); From 2e6f80688c89df832e3a44cba151f358a121c5d6 Mon Sep 17 00:00:00 2001 From: LohikaarmeHav Date: Tue, 2 Aug 2016 14:10:08 +0300 Subject: [PATCH 03/20] Removed debug --- apps/opencs/view/world/dragrecordtable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index 8bb5659fd..a5f933283 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -62,7 +62,7 @@ void CSVWorld::DragRecordTable::dragMoveEvent(QDragMoveEvent *event) } void CSVWorld::DragRecordTable::dropEvent(QDropEvent *event) -{(void)write(1,"H\n",2); +{ QModelIndex index = indexAt(event->pos()); CSMWorld::ColumnBase::Display display = getIndexDisplayType(index); if (CSVWorld::DragDropUtils::canAcceptData(*event, display)) From c6bc30d6a837cef928c1ecf733b4f198ac5b9863 Mon Sep 17 00:00:00 2001 From: LohikaarmeHav Date: Tue, 2 Aug 2016 14:27:19 +0300 Subject: [PATCH 04/20] Forgot to remove line and add comment. --- apps/opencs/view/render/scenewidget.cpp | 1 - apps/opencs/view/render/scenewidget.hpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index a36ff8c49..ef5b8959b 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -160,7 +160,6 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys , mFreeCamControl(new FreeCameraController()) , mOrbitCamControl(new OrbitCameraController()) , mCurrentCamControl(mFreeCamControl.get()) - , mCamPositionSet(false) { mOrbitCamControl->setPickingMask(Mask_Reference | Mask_Terrain); selectNavigationMode("free"); diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index d3ab28adc..c36c57e4e 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -122,6 +122,7 @@ namespace CSVRender std::map, std::string> mButtonMapping; public slots: + /// \note Remember set the camera before running void update(double dt); protected slots: From 7cd991107c637f95663c38efc4fd2ecb1084bd24 Mon Sep 17 00:00:00 2001 From: LohikaarmeHav Date: Tue, 2 Aug 2016 15:26:12 +0300 Subject: [PATCH 05/20] Nah Preview seem to not like removing mCamPositionSet and I have do other things. --- apps/opencs/view/render/pagedworldspacewidget.cpp | 4 ++-- apps/opencs/view/render/scenewidget.cpp | 11 ++++++++++- apps/opencs/view/render/scenewidget.hpp | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 3baf4e972..d206c43b6 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -485,8 +485,8 @@ void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) while (stream >> ignore1 >> ignore2 >> x >> y) selection.add (CSMWorld::CellCoordinates (x, y)); - // Setup camera - mCurrentCamControl->setup(mRootNode, Mask_Reference | Mask_Terrain, CameraController::WorldUp); + // Mark that camera needs setup + mCamPositionSet=false; } } else if (hint[0]=='r') diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index ef5b8959b..1ebc5c3e7 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -160,6 +160,7 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys , mFreeCamControl(new FreeCameraController()) , mOrbitCamControl(new OrbitCameraController()) , mCurrentCamControl(mFreeCamControl.get()) + , mCamPositionSet(false) { mOrbitCamControl->setPickingMask(Mask_Reference | Mask_Terrain); selectNavigationMode("free"); @@ -312,7 +313,15 @@ void SceneWidget::keyReleaseEvent (QKeyEvent *event) void SceneWidget::update(double dt) { - mCurrentCamControl->update(dt); + if(mCamPositionSet) + { + mCurrentCamControl->update(dt); + } + else + { + mCurrentCamControl->setup(mRootNode, Mask_Reference | Mask_Terrain, CameraController::WorldUp); + mCamPositionSet = true; + } } void SceneWidget::settingChanged (const CSMPrefs::Setting *setting) diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index c36c57e4e..e21599373 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -118,6 +118,7 @@ namespace CSVRender std::auto_ptr mFreeCamControl; std::auto_ptr mOrbitCamControl; CameraController* mCurrentCamControl; + bool mCamPositionSet; std::map, std::string> mButtonMapping; From b0cf276cfc83ecf0e340d1c5f50c2761927e0013 Mon Sep 17 00:00:00 2001 From: LohikaarmeHav Date: Tue, 2 Aug 2016 15:27:40 +0300 Subject: [PATCH 06/20] hups --- apps/opencs/view/render/scenewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 1ebc5c3e7..77d68eb01 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -313,7 +313,7 @@ void SceneWidget::keyReleaseEvent (QKeyEvent *event) void SceneWidget::update(double dt) { - if(mCamPositionSet) + if (mCamPositionSet) { mCurrentCamControl->update(dt); } From 48bcde8cc99afbd835d203913c9a69f32973b2cc Mon Sep 17 00:00:00 2001 From: lohikaarme Date: Tue, 2 Aug 2016 15:41:52 +0300 Subject: [PATCH 07/20] ... --- apps/opencs/view/render/scenewidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 77d68eb01..a890fa3cb 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -31,6 +31,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) , mRootNode(0) { + osgViewer::CompositeViewer& viewer = CompositeViewer::get(); osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); From b65f379b7fe0f422b44e607f40c9c87edf37751e Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 30 Jul 2016 19:24:03 +0200 Subject: [PATCH 08/20] Save scripted animation state (Fixes #1931, #2150, #3393) --- apps/essimporter/convertacdt.cpp | 51 +++++++++ apps/essimporter/convertacdt.hpp | 3 + apps/essimporter/converter.cpp | 3 + apps/essimporter/importacdt.cpp | 7 +- apps/essimporter/importacdt.hpp | 9 ++ apps/openmw/mwbase/mechanicsmanager.hpp | 7 +- apps/openmw/mwmechanics/actors.cpp | 10 +- apps/openmw/mwmechanics/actors.hpp | 3 +- apps/openmw/mwmechanics/character.cpp | 105 +++++++++++++++--- apps/openmw/mwmechanics/character.hpp | 13 ++- .../mwmechanics/mechanicsmanagerimp.cpp | 12 +- .../mwmechanics/mechanicsmanagerimp.hpp | 3 +- apps/openmw/mwmechanics/objects.cpp | 10 +- apps/openmw/mwmechanics/objects.hpp | 3 +- apps/openmw/mwrender/animation.cpp | 9 ++ apps/openmw/mwrender/animation.hpp | 2 + apps/openmw/mwscript/animationextensions.cpp | 4 +- apps/openmw/mwstate/statemanagerimp.cpp | 3 + apps/openmw/mwworld/refdata.cpp | 16 +++ apps/openmw/mwworld/refdata.hpp | 6 + components/CMakeLists.txt | 2 +- components/esm/animationstate.cpp | 37 ++++++ components/esm/animationstate.hpp | 34 ++++++ components/esm/objectstate.cpp | 4 + components/esm/objectstate.hpp | 3 + 25 files changed, 328 insertions(+), 31 deletions(-) create mode 100644 components/esm/animationstate.cpp create mode 100644 components/esm/animationstate.hpp diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp index 8f090b3fc..5c2bcc402 100644 --- a/apps/essimporter/convertacdt.cpp +++ b/apps/essimporter/convertacdt.cpp @@ -1,3 +1,9 @@ +#include +#include +#include + +#include + #include "convertacdt.hpp" namespace ESSImport @@ -49,4 +55,49 @@ namespace ESSImport npcStats.mTimeToStartDrowning = actorData.mACDT.mBreathMeter; } + void convertANIS (const ANIS& anis, ESM::AnimationState& state) + { + static const char* animGroups[] = + { + "Idle", "Idle2", "Idle3", "Idle4", "Idle5", "Idle6", "Idle7", "Idle8", "Idle9", "Idlehh", "Idle1h", "Idle2c", + "Idle2w", "IdleSwim", "IdleSpell", "IdleCrossbow", "IdleSneak", "IdleStorm", "Torch", "Hit1", "Hit2", "Hit3", + "Hit4", "Hit5", "SwimHit1", "SwimHit2", "SwimHit3", "Death1", "Death2", "Death3", "Death4", "Death5", + "DeathKnockDown", "DeathKnockOut", "KnockDown", "KnockOut", "SwimDeath", "SwimDeath2", "SwimDeath3", + "SwimDeathKnockDown", "SwimDeathKnockOut", "SwimKnockOut", "SwimKnockDown", "SwimWalkForward", + "SwimWalkBack", "SwimWalkLeft", "SwimWalkRight", "SwimRunForward", "SwimRunBack", "SwimRunLeft", + "SwimRunRight", "SwimTurnLeft", "SwimTurnRight", "WalkForward", "WalkBack", "WalkLeft", "WalkRight", + "TurnLeft", "TurnRight", "RunForward", "RunBack", "RunLeft", "RunRight", "SneakForward", "SneakBack", + "SneakLeft", "SneakRight", "Jump", "WalkForwardhh", "WalkBackhh", "WalkLefthh", "WalkRighthh", + "TurnLefthh", "TurnRighthh", "RunForwardhh", "RunBackhh", "RunLefthh", "RunRighthh", "SneakForwardhh", + "SneakBackhh", "SneakLefthh", "SneakRighthh", "Jumphh", "WalkForward1h", "WalkBack1h", "WalkLeft1h", + "WalkRight1h", "TurnLeft1h", "TurnRight1h", "RunForward1h", "RunBack1h", "RunLeft1h", "RunRight1h", + "SneakForward1h", "SneakBack1h", "SneakLeft1h", "SneakRight1h", "Jump1h", "WalkForward2c", "WalkBack2c", + "WalkLeft2c", "WalkRight2c", "TurnLeft2c", "TurnRight2c", "RunForward2c", "RunBack2c", "RunLeft2c", + "RunRight2c", "SneakForward2c", "SneakBack2c", "SneakLeft2c", "SneakRight2c", "Jump2c", "WalkForward2w", + "WalkBack2w", "WalkLeft2w", "WalkRight2w", "TurnLeft2w", "TurnRight2w", "RunForward2w", "RunBack2w", + "RunLeft2w", "RunRight2w", "SneakForward2w", "SneakBack2w", "SneakLeft2w", "SneakRight2w", "Jump2w", + "SpellCast", "SpellTurnLeft", "SpellTurnRight", "Attack1", "Attack2", "Attack3", "SwimAttack1", + "SwimAttack2", "SwimAttack3", "HandToHand", "Crossbow", "BowAndArrow", "ThrowWeapon", "WeaponOneHand", + "WeaponTwoHand", "WeaponTwoWide", "Shield", "PickProbe", "InventoryHandToHand", "InventoryWeaponOneHand", + "InventoryWeaponTwoHand", "InventoryWeaponTwoWide" + }; + + if (anis.mGroupIndex < (sizeof(animGroups) / sizeof(*animGroups))) + { + std::string group(animGroups[anis.mGroupIndex]); + Misc::StringUtils::lowerCaseInPlace(group); + + ESM::AnimationState::ScriptedAnimation scriptedAnim; + scriptedAnim.mGroup = group; + scriptedAnim.mTime = anis.mTime; + scriptedAnim.mAbsolute = true; + // Neither loop count nor queueing seems to be supported by the ess format. + scriptedAnim.mLoopCount = std::numeric_limits::max(); + state.mScriptedAnims.push_back(scriptedAnim); + } + else + // TODO: Handle 0xFF index, which seems to be used for finished animations. + std::cerr << "unknown animation group index: " << static_cast(anis.mGroupIndex) << std::endl; + } + } diff --git a/apps/essimporter/convertacdt.hpp b/apps/essimporter/convertacdt.hpp index bc9a7bd00..4059dd1af 100644 --- a/apps/essimporter/convertacdt.hpp +++ b/apps/essimporter/convertacdt.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "importacdt.hpp" @@ -18,6 +19,8 @@ namespace ESSImport void convertACSC (const ACSC& acsc, ESM::CreatureStats& cStats); void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats); + + void convertANIS (const ANIS& anis, ESM::AnimationState& state); } #endif diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index afd0ef131..a428a8c71 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -34,6 +34,9 @@ namespace objstate.mCount = 0; convertSCRI(cellref.mSCRI, objstate.mLocals); objstate.mHasLocals = !objstate.mLocals.mVariables.empty(); + + if (cellref.mHasANIS) + convertANIS(cellref.mANIS, objstate.mAnimationState); } bool isIndexedRefId(const std::string& indexedRefId) diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index fb0dccaf5..0ddd2eb64 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -123,8 +123,13 @@ namespace ESSImport if (esm.isNextSub("ND3D")) esm.skipHSub(); + + mHasANIS = false; if (esm.isNextSub("ANIS")) - esm.skipHSub(); + { + mHasANIS = true; + esm.getHT(mANIS); + } } } diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index eacb2edf1..bf48d1f78 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -55,6 +55,12 @@ namespace ESSImport unsigned char mCorpseClearCountdown; // hours? unsigned char mUnknown3[71]; }; + struct ANIS + { + unsigned char mGroupIndex; + unsigned char mUnknown[3]; + float mTime; + }; #pragma pack(pop) struct ActorData : public ESM::CellRef @@ -77,6 +83,9 @@ namespace ESSImport SCRI mSCRI; + bool mHasANIS; + ANIS mANIS; // scripted animation state + void load(ESM::ESMReader& esm); }; diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index a0e9da26a..0f414972f 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -159,12 +159,14 @@ namespace MWBase virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0; ///< Forces an object to refresh its animation state. - virtual bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; + virtual bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1, bool persist=false) = 0; ///< Run animation for a MW-reference. Calls to this function for references that are currently not /// in the scene should be ignored. /// /// \param mode 0 normal, 1 immediate start, 2 immediate loop /// \param count How many times the animation should be run + /// \param persist Whether the animation state should be stored in saved games + /// and persist after cell unload. /// \return Success or error virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; @@ -173,6 +175,9 @@ namespace MWBase virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0; + /// Save the current animation state of managed references to their RefData. + virtual void persistAnimationStates() = 0; + /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently /// paused we may want to do it manually (after equipping permanent enchantment) virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d12dde424..fc1c77caf 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1389,12 +1389,12 @@ namespace MWMechanics iter->second->getCharacterController()->forceStateUpdate(); } - bool Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) + bool Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist) { PtrActorMap::iterator iter = mActors.find(ptr); if(iter != mActors.end()) { - return iter->second->getCharacterController()->playGroup(groupName, mode, number); + return iter->second->getCharacterController()->playGroup(groupName, mode, number, persist); } else { @@ -1417,6 +1417,12 @@ namespace MWMechanics return false; } + void Actors::persistAnimationStates() + { + for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter) + iter->second->getCharacterController()->persistAnimationState(); + } + void Actors::getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out) { for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 0dc684c56..163995f6f 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -109,9 +109,10 @@ namespace MWMechanics void forceStateUpdate(const MWWorld::Ptr &ptr); - bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist=false); void skipAnimation(const MWWorld::Ptr& ptr); bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); + void persistAnimationStates(); void getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 081f288d5..07aba2f7d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -762,12 +762,17 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true); mAnimation->runAnimation(0.f); + + unpersistAnimationState(); } CharacterController::~CharacterController() { if (mAnimation) + { + persistAnimationState(); mAnimation->setTextKeyListener(NULL); + } } void split(const std::string &s, char delim, std::vector &elems) { @@ -1557,14 +1562,14 @@ void CharacterController::update(float duration) { if(mAnimQueue.size() > 1) { - if(mAnimation->isPlaying(mAnimQueue.front().first) == false) + if(mAnimation->isPlaying(mAnimQueue.front().mGroup) == false) { - mAnimation->disable(mAnimQueue.front().first); + mAnimation->disable(mAnimQueue.front().mGroup); mAnimQueue.pop_front(); - mAnimation->play(mAnimQueue.front().first, Priority_Default, + mAnimation->play(mAnimQueue.front().mGroup, Priority_Default, MWRender::Animation::BlendMask_All, false, - 1.0f, "start", "stop", 0.0f, mAnimQueue.front().second); + 1.0f, "start", "stop", 0.0f, mAnimQueue.front().mLoopCount); } } } @@ -1837,14 +1842,14 @@ void CharacterController::update(float duration) } else if(mAnimQueue.size() > 1) { - if(mAnimation->isPlaying(mAnimQueue.front().first) == false) + if(mAnimation->isPlaying(mAnimQueue.front().mGroup) == false) { - mAnimation->disable(mAnimQueue.front().first); + mAnimation->disable(mAnimQueue.front().mGroup); mAnimQueue.pop_front(); - mAnimation->play(mAnimQueue.front().first, Priority_Default, + mAnimation->play(mAnimQueue.front().mGroup, Priority_Default, MWRender::Animation::BlendMask_All, false, - 1.0f, "start", "stop", 0.0f, mAnimQueue.front().second); + 1.0f, "start", "stop", 0.0f, mAnimQueue.front().mLoopCount); } } @@ -1951,8 +1956,74 @@ void CharacterController::update(float duration) mAnimation->enableHeadAnimation(cls.isActor() && !cls.getCreatureStats(mPtr).isDead()); } +void CharacterController::persistAnimationState() +{ + ESM::AnimationState& state = mPtr.getRefData().getAnimationState(); + + state.mScriptedAnims.clear(); + for (AnimationQueue::const_iterator iter = mAnimQueue.begin(); iter != mAnimQueue.end(); ++iter) + { + if (!iter->mPersist) + continue; + + ESM::AnimationState::ScriptedAnimation anim; + anim.mGroup = iter->mGroup; + + if (iter == mAnimQueue.begin()) + { + anim.mLoopCount = mAnimation->getCurrentLoopCount(anim.mGroup); + float complete; + mAnimation->getInfo(anim.mGroup, &complete, NULL); + anim.mTime = complete; + } + else + { + anim.mLoopCount = iter->mLoopCount; + anim.mTime = 0.f; + } + + state.mScriptedAnims.push_back(anim); + } +} + +void CharacterController::unpersistAnimationState() +{ + const ESM::AnimationState& state = mPtr.getRefData().getAnimationState(); + + if (!state.mScriptedAnims.empty()) + { + clearAnimQueue(); + for (ESM::AnimationState::ScriptedAnimations::const_iterator iter = state.mScriptedAnims.begin(); iter != state.mScriptedAnims.end(); ++iter) + { + AnimationQueueEntry entry; + entry.mGroup = iter->mGroup; + entry.mLoopCount = iter->mLoopCount; + entry.mPersist = true; + + mAnimQueue.push_back(entry); + } + + const ESM::AnimationState::ScriptedAnimation& anim = state.mScriptedAnims.front(); + float complete = anim.mTime; + if (anim.mAbsolute) + { + float start = mAnimation->getTextKeyTime(anim.mGroup+": start"); + float stop = mAnimation->getTextKeyTime(anim.mGroup+": stop"); + float time = std::max(start, std::min(stop, anim.mTime)); + complete = (time - start) / (stop - start); + } -bool CharacterController::playGroup(const std::string &groupname, int mode, int count) + mAnimation->disable(mCurrentIdle); + mCurrentIdle.clear(); + mIdleState = CharState_SpecialIdle; + + mAnimation->play(anim.mGroup, + Priority_Default, MWRender::Animation::BlendMask_All, false, 1.0f, + "start", "stop", complete, anim.mLoopCount); + } +} + +bool CharacterController::playGroup(const std::string &groupname, int mode, int count, bool persist) { if(!mAnimation || !mAnimation->hasAnimation(groupname)) { @@ -1962,10 +2033,16 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int else { count = std::max(count, 1); - if(mode != 0 || mAnimQueue.empty() || !isAnimPlaying(mAnimQueue.front().first)) + + AnimationQueueEntry entry; + entry.mGroup = groupname; + entry.mLoopCount = count-1; + entry.mPersist = persist; + + if(mode != 0 || mAnimQueue.empty() || !isAnimPlaying(mAnimQueue.front().mGroup)) { clearAnimQueue(); - mAnimQueue.push_back(std::make_pair(groupname, count-1)); + mAnimQueue.push_back(entry); mAnimation->disable(mCurrentIdle); mCurrentIdle.clear(); @@ -1978,9 +2055,9 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int else if(mode == 0) { if (!mAnimQueue.empty()) - mAnimation->stopLooping(mAnimQueue.front().first); + mAnimation->stopLooping(mAnimQueue.front().mGroup); mAnimQueue.resize(1); - mAnimQueue.push_back(std::make_pair(groupname, count-1)); + mAnimQueue.push_back(entry); } } return true; @@ -2002,7 +2079,7 @@ bool CharacterController::isAnimPlaying(const std::string &groupName) void CharacterController::clearAnimQueue() { if(!mAnimQueue.empty()) - mAnimation->disable(mAnimQueue.front().first); + mAnimation->disable(mAnimQueue.front().mGroup); mAnimQueue.clear(); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index b7e5feb6f..190e171b3 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -147,7 +147,13 @@ class CharacterController : public MWRender::Animation::TextKeyListener MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; - typedef std::deque > AnimationQueue; + struct AnimationQueueEntry + { + std::string mGroup; + size_t mLoopCount; + bool mPersist; + }; + typedef std::deque AnimationQueue; AnimationQueue mAnimQueue; CharacterState mIdleState; @@ -236,7 +242,10 @@ public: void update(float duration); - bool playGroup(const std::string &groupname, int mode, int count); + void persistAnimationState(); + void unpersistAnimationState(); + + bool playGroup(const std::string &groupname, int mode, int count, bool persist=false); void skipAnim(); bool isAnimPlaying(const std::string &groupName); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 278a5749e..b10127f74 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -842,12 +842,12 @@ namespace MWMechanics mActors.forceStateUpdate(ptr); } - bool MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) + bool MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist) { if(ptr.getClass().isActor()) - return mActors.playAnimationGroup(ptr, groupName, mode, number); + return mActors.playAnimationGroup(ptr, groupName, mode, number, persist); else - return mObjects.playAnimationGroup(ptr, groupName, mode, number); + return mObjects.playAnimationGroup(ptr, groupName, mode, number, persist); } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { @@ -864,6 +864,12 @@ namespace MWMechanics return false; } + void MechanicsManager::persistAnimationStates() + { + mActors.persistAnimationStates(); + mObjects.persistAnimationStates(); + } + void MechanicsManager::updateMagicEffects(const MWWorld::Ptr &ptr) { mActors.updateMagicEffects(ptr); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index b0a9380e5..04c67fcb6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -146,9 +146,10 @@ namespace MWMechanics /// Attempt to play an animation group /// @return Success or error - virtual bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + virtual bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist=false); virtual void skipAnimation(const MWWorld::Ptr& ptr); virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName); + virtual void persistAnimationStates(); /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently /// paused we may want to do it manually (after equipping permanent enchantment) diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index 7d7c0bfae..139825c21 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -79,12 +79,12 @@ void Objects::update(float duration, bool paused) } } -bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) +bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist) { PtrControllerMap::iterator iter = mObjects.find(ptr); if(iter != mObjects.end()) { - return iter->second->playGroup(groupName, mode, number); + return iter->second->playGroup(groupName, mode, number, persist); } else { @@ -99,6 +99,12 @@ void Objects::skipAnimation(const MWWorld::Ptr& ptr) iter->second->skipAnim(); } +void Objects::persistAnimationStates() +{ + for (PtrControllerMap::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) + iter->second->persistAnimationState(); +} + void Objects::getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out) { for (PtrControllerMap::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 07e00675c..1efebafbe 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -38,8 +38,9 @@ namespace MWMechanics void update(float duration, bool paused); ///< Update object animations - bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist=false); void skipAnimation(const MWWorld::Ptr& ptr); + void persistAnimationStates(); void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& out); }; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fa7542060..0412e1e41 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -843,6 +843,15 @@ namespace MWRender return iter->second.getTime(); } + size_t Animation::getCurrentLoopCount(const std::string& groupname) const + { + AnimStateMap::const_iterator iter = mStates.find(groupname); + if(iter == mStates.end()) + return 0; + + return iter->second.mLoopCount; + } + void Animation::disable(const std::string &groupname) { AnimStateMap::iterator iter = mStates.find(groupname); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index e9d79ced1..ad9d4ab4a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -415,6 +415,8 @@ public: /// Get the current absolute position in the animation track for the animation that is currently playing from the given group. float getCurrentTime(const std::string& groupname) const; + size_t getCurrentLoopCount(const std::string& groupname) const; + /** Disables the specified animation group; * \param groupname Animation group to disable. */ diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index 07a8a300a..44c4612ec 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -56,7 +56,7 @@ namespace MWScript throw std::runtime_error ("animation mode out of range"); } - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, std::numeric_limits::max()); + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, std::numeric_limits::max(), true); } }; @@ -89,7 +89,7 @@ namespace MWScript throw std::runtime_error ("animation mode out of range"); } - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, loops); + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, loops, true); } }; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index a8639b94b..48cc37935 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -219,6 +219,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot else slot = character->updateSlot (slot, profile); + // Make sure the animation state held by references is up to date before saving the game. + MWBase::Environment::get().getMechanicsManager()->persistAnimationStates(); + // Write to a memory stream first. If there is an exception during the save process, we don't want to trash the // existing save file we are overwriting. std::stringstream stream; diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index f85abcc32..ebc38ac9b 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -31,6 +31,8 @@ namespace MWWorld mDeletedByContentFile = refData.mDeletedByContentFile; mFlags = refData.mFlags; + mAnimationState = refData.mAnimationState; + mCustomData = refData.mCustomData ? refData.mCustomData->clone() : 0; } @@ -65,6 +67,7 @@ namespace MWWorld mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), + mAnimationState(objectState.mAnimationState), mCustomData (0), mChanged(true), mFlags(objectState.mFlags) // Loading from a savegame -> assume changed { @@ -96,6 +99,8 @@ namespace MWWorld objectState.mCount = mCount; objectState.mPosition = mPosition; objectState.mFlags = mFlags; + + objectState.mAnimationState = mAnimationState; } RefData& RefData::operator= (const RefData& refData) @@ -269,4 +274,15 @@ namespace MWWorld else return false; } + + const ESM::AnimationState& RefData::getAnimationState() const + { + return mAnimationState; + } + + ESM::AnimationState& RefData::getAnimationState() + { + return mAnimationState; + } + } diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 9e662e430..75eec6742 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -2,6 +2,7 @@ #define GAME_MWWORLD_REFDATA_H #include +#include #include "../mwscript/locals.hpp" @@ -42,6 +43,8 @@ namespace MWWorld ESM::Position mPosition; + ESM::AnimationState mAnimationState; + CustomData *mCustomData; void copy (const RefData& refData); @@ -132,6 +135,9 @@ namespace MWWorld bool hasChanged() const; ///< Has this RefData changed since it was originally loaded? + + const ESM::AnimationState& getAnimationState() const; + ESM::AnimationState& getAnimationState(); }; } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f50f30fa6..e5292eb6b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -77,7 +77,7 @@ add_component_dir (esm loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile - aisequence magiceffects util custommarkerstate stolenitems transport + aisequence magiceffects util custommarkerstate stolenitems transport animationstate ) add_component_dir (esmterrain diff --git a/components/esm/animationstate.cpp b/components/esm/animationstate.cpp new file mode 100644 index 000000000..52dde258f --- /dev/null +++ b/components/esm/animationstate.cpp @@ -0,0 +1,37 @@ +#include "animationstate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace ESM +{ + void AnimationState::load(ESMReader& esm) + { + mScriptedAnims.clear(); + + while (esm.isNextSub("ANIS")) + { + ScriptedAnimation anim; + + anim.mGroup = esm.getHString(); + esm.getHNOT(anim.mTime, "TIME"); + esm.getHNOT(anim.mAbsolute, "ABST"); + esm.getHNT(anim.mLoopCount, "COUN"); + + mScriptedAnims.push_back(anim); + } + } + + void AnimationState::save(ESMWriter& esm) const + { + for (ScriptedAnimations::const_iterator iter = mScriptedAnims.begin(); iter != mScriptedAnims.end(); ++iter) + { + esm.writeHNString("ANIS", iter->mGroup); + if (iter->mTime > 0) + esm.writeHNT("TIME", iter->mTime); + if (iter->mAbsolute) + esm.writeHNT("ABST", iter->mAbsolute); + esm.writeHNT("COUN", iter->mLoopCount); + } + } +} diff --git a/components/esm/animationstate.hpp b/components/esm/animationstate.hpp new file mode 100644 index 000000000..73b6a41d0 --- /dev/null +++ b/components/esm/animationstate.hpp @@ -0,0 +1,34 @@ +#ifndef OPENMW_ESM_ANIMATIONSTATE_H +#define OPENMW_ESM_ANIMATIONSTATE_H + +#include +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + struct AnimationState + { + struct ScriptedAnimation + { + ScriptedAnimation() + : mTime(0.f), mAbsolute(false), mLoopCount(0) {} + + std::string mGroup; + float mTime; + bool mAbsolute; + size_t mLoopCount; + }; + + typedef std::vector ScriptedAnimations; + ScriptedAnimations mScriptedAnims; + + void load(ESMReader& esm); + void save(ESMWriter& esm) const; + }; +} + +#endif diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index b80c72ffe..18c030256 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -34,6 +34,8 @@ void ESM::ObjectState::load (ESMReader &esm) int unused; esm.getHNOT(unused, "LTIM"); + mAnimationState.load(esm); + // FIXME: assuming "false" as default would make more sense, but also break compatibility with older save files mHasCustomState = true; esm.getHNOT (mHasCustomState, "HCUS"); @@ -61,6 +63,8 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const if (mFlags != 0) esm.writeHNT ("FLAG", mFlags); + mAnimationState.save(esm); + if (!mHasCustomState) esm.writeHNT ("HCUS", false); } diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index 5b78074af..b8eb138eb 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -6,6 +6,7 @@ #include "cellref.hpp" #include "locals.hpp" +#include "animationstate.hpp" namespace ESM { @@ -31,6 +32,8 @@ namespace ESM unsigned int mVersion; + ESM::AnimationState mAnimationState; + ObjectState() : mHasCustomState(true), mVersion(0) {} From 0592d1cdcfa5088e151d7c6f99b25a60932874a5 Mon Sep 17 00:00:00 2001 From: lohikaarme Date: Wed, 3 Aug 2016 14:22:25 +0300 Subject: [PATCH 09/20] Commnent? --- apps/opencs/view/render/pagedworldspacewidget.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index e96cb9e8e..8b6f2ee01 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -84,7 +84,7 @@ namespace CSVRender virtual ~PagedWorldspaceWidget(); /// \brief Decodes the the hint string to set of cell that are rendered. - /// Calculates avarage of cell's coordinates to be new camera location. + /// \details Calculates avarage of cell's coordinates to be new camera location. void useViewHint (const std::string& hint); void setCellSelection(const CSMWorld::CellSelection& selection); From e8ef5c233f2f6a6097bbec7eafb606ec1883b248 Mon Sep 17 00:00:00 2001 From: lohikaarme Date: Wed, 3 Aug 2016 14:24:21 +0300 Subject: [PATCH 10/20] Miss info --- apps/opencs/view/render/pagedworldspacewidget.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 8b6f2ee01..1c4caeb7f 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -83,8 +83,7 @@ namespace CSVRender virtual ~PagedWorldspaceWidget(); - /// \brief Decodes the the hint string to set of cell that are rendered. - /// \details Calculates avarage of cell's coordinates to be new camera location. + /// Decodes the the hint string to set of cell that are rendered. void useViewHint (const std::string& hint); void setCellSelection(const CSMWorld::CellSelection& selection); From 19c74a4d6e5dc092709e1e421b91869b1d99e4b8 Mon Sep 17 00:00:00 2001 From: LohikaarmeHAV Date: Wed, 3 Aug 2016 20:39:46 +0300 Subject: [PATCH 11/20] Part two --- apps/opencs/model/world/cellcoordinates.hpp | 3 +- .../view/render/pagedworldspacewidget.hpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 2 +- apps/opencs/view/render/scenewidget.hpp | 35 ++++++++----------- 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/apps/opencs/model/world/cellcoordinates.hpp b/apps/opencs/model/world/cellcoordinates.hpp index 6ff4e4b5d..696868d00 100644 --- a/apps/opencs/model/world/cellcoordinates.hpp +++ b/apps/opencs/model/world/cellcoordinates.hpp @@ -37,10 +37,9 @@ namespace CSMWorld /// /// \note The worldspace part of \a id is ignored static std::pair fromId (const std::string& id); - + /// \return cell coordinates such that given world coordinates are in it. static std::pair coordinatesToCellIndex (float x, float y); - }; bool operator== (const CellCoordinates& left, const CellCoordinates& right); diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index c25877e02..0663d3424 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -84,7 +84,7 @@ namespace CSVRender /// hint system. virtual ~PagedWorldspaceWidget(); - + /// Decodes the the hint string to set of cell that are rendered. void useViewHint (const std::string& hint); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 5d7a296cd..db0637a24 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -32,7 +32,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) , mRootNode(0) { - + osgViewer::CompositeViewer& viewer = CompositeViewer::get(); osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 001494ab3..c5d9cdfce 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -7,14 +7,15 @@ #include #include +#include +#include + #include #include "lightingday.hpp" #include "lightingnight.hpp" #include "lightingbright.hpp" -#include -#include namespace Resource { @@ -53,6 +54,7 @@ namespace CSVRender RenderWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); virtual ~RenderWidget(); + /// Initiates a request to redraw the view void flagAsModified(); void setVisibilityMask(int mask); @@ -62,13 +64,16 @@ namespace CSVRender protected: osg::ref_ptr mView; - - osg::Group* mRootNode; + osg::ref_ptr mRootNode; QTimer mTimer; + + protected slots: + + void toggleRenderStats(); }; - // Extension of RenderWidget to support lighting mode selection & toolbar + /// Extension of RenderWidget to support lighting mode selection & toolbar class SceneWidget : public RenderWidget { Q_OBJECT @@ -90,18 +95,8 @@ namespace CSVRender void setAmbient(const osg::Vec4f& ambient); - virtual void mousePressEvent (QMouseEvent *event); - virtual void mouseReleaseEvent (QMouseEvent *event); virtual void mouseMoveEvent (QMouseEvent *event); virtual void wheelEvent (QWheelEvent *event); - virtual void keyPressEvent (QKeyEvent *event); - virtual void keyReleaseEvent (QKeyEvent *event); - virtual void focusOutEvent (QFocusEvent *event); - - /// \return Is \a key a button mapping setting? (ignored otherwise) - virtual bool storeMappingSetting (const CSMPrefs::Setting *setting); - - std::string mapButton (QMouseEvent *event); boost::shared_ptr mResourceSystem; @@ -114,17 +109,15 @@ namespace CSVRender LightingBright mLightingBright; int mPrevMouseX, mPrevMouseY; - std::string mMouseMode; - std::auto_ptr mFreeCamControl; - std::auto_ptr mOrbitCamControl; - CameraController* mCurrentCamControl; + /// Tells update that camera isn't set bool mCamPositionSet; - std::map, std::string> mButtonMapping; + FreeCameraController* mFreeCamControl; + OrbitCameraController* mOrbitCamControl; + CameraController* mCurrentCamControl; public slots: - /// \note Remember set the camera before running void update(double dt); protected slots: From 60535b77e81b7885d8fcdb562bceb7d2dbd445fd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Aug 2016 09:10:54 +0200 Subject: [PATCH 12/20] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 60e969cdc..816afd084 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -75,6 +75,7 @@ Programmers Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) + lohikaarme Lukasz Gromanowski (lgro) Manuel Edelmann (vorenon) Marc Bouvier (CramitDeFrog) From 5674e0da24de98cc4d781d6e74bfd17f6603dd72 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Thu, 4 Aug 2016 22:58:55 -0400 Subject: [PATCH 13/20] Render water in editor. --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/view/render/cell.cpp | 2 + apps/opencs/view/render/cell.hpp | 2 + apps/opencs/view/render/cellmarker.cpp | 1 + apps/opencs/view/render/cellwater.cpp | 191 +++++++++++++++++++++++++ apps/opencs/view/render/cellwater.hpp | 69 +++++++++ 6 files changed, 266 insertions(+) create mode 100644 apps/opencs/view/render/cellwater.cpp create mode 100644 apps/opencs/view/render/cellwater.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6e19c03b2..8a830f2cb 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -87,6 +87,7 @@ opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget previewwidget editmode instancemode instanceselectionmode instancemovemode orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller + cellwater ) opencs_units_noqt (view/render diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index dc22fd511..395fbf95f 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -16,6 +16,7 @@ #include "../../model/world/refcollection.hpp" #include "../../model/world/cellcoordinates.hpp" +#include "cellwater.hpp" #include "mask.hpp" #include "pathgrid.hpp" #include "terrainstorage.hpp" @@ -111,6 +112,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st } mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates)); + mCellWater.reset(new CellWater(mData, mCellNode, mId, mCoordinates)); } } diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index a5b581d24..8f68e9f53 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -35,6 +35,7 @@ namespace CSMWorld namespace CSVRender { + class CellWater; class Pathgrid; class TagBase; @@ -49,6 +50,7 @@ namespace CSVRender std::auto_ptr mCellArrows[4]; std::auto_ptr mCellMarker; std::auto_ptr mCellBorder; + std::auto_ptr mCellWater; std::auto_ptr mPathgrid; bool mDeleted; int mSubMode; diff --git a/apps/opencs/view/render/cellmarker.cpp b/apps/opencs/view/render/cellmarker.cpp index e0d270f85..09690190d 100644 --- a/apps/opencs/view/render/cellmarker.cpp +++ b/apps/opencs/view/render/cellmarker.cpp @@ -75,6 +75,7 @@ CSVRender::CellMarker::CellMarker( mMarkerNode->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN); mMarkerNode->setAutoScaleToScreen(true); mMarkerNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + mMarkerNode->getOrCreateStateSet()->setRenderBinDetails(2000, "RenderBin"); mMarkerNode->setUserData(new CellMarkerTag(this)); mMarkerNode->setNodeMask(Mask_CellMarker); diff --git a/apps/opencs/view/render/cellwater.cpp b/apps/opencs/view/render/cellwater.cpp new file mode 100644 index 000000000..956864d7b --- /dev/null +++ b/apps/opencs/view/render/cellwater.cpp @@ -0,0 +1,191 @@ +#include "cellwater.hpp" + +#include +#include +#include +#include +#include + +#include +#include + +#include "../../model/world/cell.hpp" +#include "../../model/world/cellcoordinates.hpp" +#include "../../model/world/data.hpp" + +#include "mask.hpp" + +namespace CSVRender +{ + const int CellWater::CellSize = ESM::Land::REAL_SIZE; + + CellWater::CellWater(CSMWorld::Data& data, osg::Group* cellNode, const std::string& id, + const CSMWorld::CellCoordinates& cellCoords) + : mData(data) + , mId(id) + , mParentNode(cellNode) + , mWaterTransform(0) + , mWaterNode(0) + , mWaterGeometry(0) + , mExterior(false) + , mHasWater(false) + , mWaterHeight(0) + { + mWaterTransform = new osg::PositionAttitudeTransform(); + mWaterTransform->setPosition(osg::Vec3f(cellCoords.getX() * CellSize, cellCoords.getY() * CellSize, 0)); + mWaterTransform->setNodeMask(Mask_Water); + mParentNode->addChild(mWaterTransform); + + mWaterNode = new osg::Geode(); + mWaterTransform->addChild(mWaterNode); + + int cellIndex = mData.getCells().searchId(mId); + if (cellIndex > -1) + { + updateCellData(mData.getCells().getRecord(cellIndex).get()); + } + + // Keep water existance/height up to date + QAbstractItemModel* cells = mData.getTableModel(CSMWorld::UniversalId::Type_Cells); + connect(cells, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), + this, SLOT(cellDataChanged(const QModelIndex&, const QModelIndex&))); + } + + CellWater::~CellWater() + { + mParentNode->removeChild(mWaterTransform); + } + + void CellWater::updateCellData(const CSMWorld::Cell& cell) + { + int cellIndex = mData.getCells().searchId(mId); + if (cellIndex > -1) + { + const CSMWorld::Record& cellRecord = mData.getCells().getRecord(cellIndex); + + mDeleted = cellRecord.isDeleted(); + if (!mDeleted) + { + mExterior = cellRecord.get().isExterior(); + + mHasWater = cellRecord.get().hasWater(); + mWaterHeight = cellRecord.get().mWater; + } + } + else + { + mDeleted = true; + } + + update(); + } + + void CellWater::cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) + { + const CSMWorld::Collection& cells = mData.getCells(); + + int rowStart = -1; + int rowEnd = -1; + + if (topLeft.parent().isValid()) + { + rowStart = topLeft.parent().row(); + rowEnd = bottomRight.parent().row(); + } + else + { + rowStart = topLeft.row(); + rowEnd = bottomRight.row(); + } + + for (int row = rowStart; row <= rowEnd; ++row) + { + const CSMWorld::Cell& cell = cells.getRecord(row).get(); + + if (Misc::StringUtils::lowerCase(cell.mId) == mId) + updateCellData(cell); + } + } + + void CellWater::update() + { + const int InteriorSize = CellSize * 10; + + const size_t NumPoints = 4; + const size_t NumIndices = 6; + + const osg::Vec3f ExteriorPoints[] = + { + osg::Vec3f(0, 0, mWaterHeight), + osg::Vec3f(0, CellSize, mWaterHeight), + osg::Vec3f(CellSize, CellSize, mWaterHeight), + osg::Vec3f(CellSize, 0, mWaterHeight) + }; + + const osg::Vec3f InteriorPoints[] = + { + osg::Vec3f(-InteriorSize, -InteriorSize, mWaterHeight), + osg::Vec3f(-InteriorSize, InteriorSize, mWaterHeight), + osg::Vec3f( InteriorSize, InteriorSize, mWaterHeight), + osg::Vec3f( InteriorSize, -InteriorSize, mWaterHeight) + }; + + const unsigned short TriangleStrip[] = + { + 0, 1, 2, 3, 0, 1 + }; + + const osg::Vec4f Color = osg::Vec4f(0.6f, 0.7f, 1.f, 0.5f); + + if (mWaterGeometry) + { + mWaterNode->removeDrawable(mWaterGeometry); + mWaterGeometry = 0; + } + + if (mDeleted || !mHasWater) + return; + + mWaterGeometry = new osg::Geometry(); + + osg::ref_ptr vertices = new osg::Vec3Array(); + osg::ref_ptr colors = new osg::Vec4Array(); + osg::ref_ptr indices = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, + NumIndices); + + for (size_t i = 0; i < NumPoints; ++i) + { + if (mExterior) + vertices->push_back(ExteriorPoints[i]); + else + vertices->push_back(InteriorPoints[i]); + } + + colors->push_back(Color); + + for (size_t i = 0; i < NumIndices; ++i) + { + indices->setElement(i, TriangleStrip[i]); + } + + mWaterGeometry->setVertexArray(vertices); + mWaterGeometry->setColorArray(colors, osg::Array::BIND_OVERALL); + mWaterGeometry->addPrimitiveSet(indices); + + // Transparency + mWaterGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + mWaterGeometry->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON ); + mWaterGeometry->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + mWaterGeometry->getOrCreateStateSet()->setRenderBinDetails(1000, "RenderBin"); + + // Reduce some z-fighting + osg::ref_ptr polygonOffset = new osg::PolygonOffset(); + polygonOffset->setFactor(0.2f); + polygonOffset->setUnits(0.2f); + + mWaterGeometry->getOrCreateStateSet()->setAttributeAndModes(polygonOffset, + osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); + + mWaterNode->addDrawable(mWaterGeometry); + } +} diff --git a/apps/opencs/view/render/cellwater.hpp b/apps/opencs/view/render/cellwater.hpp new file mode 100644 index 000000000..6d533e291 --- /dev/null +++ b/apps/opencs/view/render/cellwater.hpp @@ -0,0 +1,69 @@ +#ifndef CSV_RENDER_CELLWATER_H +#define CSV_RENDER_CELLWATER_H + +#include + +#include + +#include + +namespace osg +{ + class Geode; + class Geometry; + class Group; + class PositionAttitudeTransform; +} + +namespace CSMWorld +{ + class Cell; + class CellCoordinates; + class Data; +} + +namespace CSVRender +{ + /// For exterior cells, this adds a patch of water to fit the size of the cell. For interior cells with water, this + /// adds a large patch of water much larger than the typical size of a cell. + class CellWater : public QObject + { + Q_OBJECT + + public: + + CellWater(CSMWorld::Data& data, osg::Group* cellNode, const std::string& id, + const CSMWorld::CellCoordinates& cellCoords); + + ~CellWater(); + + void updateCellData(const CSMWorld::Cell& cell); + + private slots: + + void cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); + + private: + + void update(); + + static const int CellSize; + + CSMWorld::Data& mData; + std::string mId; + + osg::Group* mParentNode; + + osg::ref_ptr mWaterTransform; + osg::ref_ptr mWaterNode; + osg::ref_ptr mWaterGeometry; + + bool mDeleted; + bool mExterior; + + bool mHasWater; + float mWaterHeight; + }; +} + +#endif From 3904a24e6cb6e4d9f61271d6648916b0f58562a5 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 5 Aug 2016 00:30:28 -0400 Subject: [PATCH 14/20] Add missing include. --- apps/opencs/view/render/cellwater.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/cellwater.hpp b/apps/opencs/view/render/cellwater.hpp index 6d533e291..a7154e9cb 100644 --- a/apps/opencs/view/render/cellwater.hpp +++ b/apps/opencs/view/render/cellwater.hpp @@ -6,6 +6,7 @@ #include #include +#include namespace osg { From 5753f52b473bc5ee246f8e9fc67845983f9711cc Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 5 Aug 2016 13:25:05 -0400 Subject: [PATCH 15/20] Move water mesh + simple state generation to components library. --- apps/openmw/mwrender/water.cpp | 75 ++-------------------------- components/CMakeLists.txt | 2 +- components/sceneutil/waterutil.cpp | 79 ++++++++++++++++++++++++++++++ components/sceneutil/waterutil.hpp | 19 +++++++ 4 files changed, 104 insertions(+), 71 deletions(-) create mode 100644 components/sceneutil/waterutil.cpp create mode 100644 components/sceneutil/waterutil.hpp diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index ab828a3ad..532e5cedc 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -24,6 +24,8 @@ #include #include +#include + #include #include @@ -40,58 +42,6 @@ #include "renderbin.hpp" #include "util.hpp" -namespace -{ - - osg::ref_ptr createWaterGeometry(float size, int segments, float textureRepeats) - { - osg::ref_ptr verts (new osg::Vec3Array); - osg::ref_ptr texcoords (new osg::Vec2Array); - - // some drivers don't like huge triangles, so we do some subdivisons - // a paged solution would be even better - const float step = size/segments; - const float texCoordStep = textureRepeats / segments; - for (int x=0; xpush_back(osg::Vec3f(x1, y2, 0.f)); - verts->push_back(osg::Vec3f(x1, y1, 0.f)); - verts->push_back(osg::Vec3f(x2, y1, 0.f)); - verts->push_back(osg::Vec3f(x2, y2, 0.f)); - - float u1 = x*texCoordStep; - float v1 = y*texCoordStep; - float u2 = u1 + texCoordStep; - float v2 = v1 + texCoordStep; - - texcoords->push_back(osg::Vec2f(u1, v2)); - texcoords->push_back(osg::Vec2f(u1, v1)); - texcoords->push_back(osg::Vec2f(u2, v1)); - texcoords->push_back(osg::Vec2f(u2, v2)); - } - } - - osg::ref_ptr waterGeom (new osg::Geometry); - waterGeom->setVertexArray(verts); - waterGeom->setTexCoordArray(0, texcoords); - - osg::ref_ptr normal (new osg::Vec3Array); - normal->push_back(osg::Vec3f(0,0,1)); - waterGeom->setNormalArray(normal, osg::Array::BIND_OVERALL); - - waterGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,verts->size())); - return waterGeom; - } - -} - namespace MWRender { @@ -465,7 +415,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem { mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback)); - mWaterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); + mWaterGeom = SceneUtil::createWaterGeometry(CELL_SIZE*150, 40, 900); mWaterGeom->setDrawCallback(new DepthClampCallback); mWaterGeom->setNodeMask(Mask_Water); @@ -527,26 +477,11 @@ void Water::updateWaterMaterial() void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) { - osg::ref_ptr stateset (new osg::StateSet); - - osg::ref_ptr material (new osg::Material); - material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, alpha)); - material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - material->setColorMode(osg::Material::OFF); - stateset->setAttributeAndModes(material, osg::StateAttribute::ON); - - stateset->setMode(GL_BLEND, osg::StateAttribute::ON); - stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); - - osg::ref_ptr depth (new osg::Depth); - depth->setWriteMask(false); - stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); - - stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); + osg::ref_ptr stateset = SceneUtil::createSimpleWaterStateSet(alpha, MWRender::RenderBin_Water); node->setStateSet(stateset); + // Add animated textures std::vector > textures; int frameCount = mFallback->getFallbackInt("Water_SurfaceFrameCount"); std::string texture = mFallback->getFallbackString("Water_SurfaceTexture"); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f50f30fa6..663616873 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -50,7 +50,7 @@ add_component_dir (shader add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry lightcontroller - lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil + lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil ) add_component_dir (nif diff --git a/components/sceneutil/waterutil.cpp b/components/sceneutil/waterutil.cpp new file mode 100644 index 000000000..562b0ee73 --- /dev/null +++ b/components/sceneutil/waterutil.cpp @@ -0,0 +1,79 @@ +#include "waterutil.hpp" + +#include +#include +#include +#include + +namespace SceneUtil +{ + osg::ref_ptr createWaterGeometry(float size, int segments, float textureRepeats) + { + osg::ref_ptr verts (new osg::Vec3Array); + osg::ref_ptr texcoords (new osg::Vec2Array); + + // some drivers don't like huge triangles, so we do some subdivisons + // a paged solution would be even better + const float step = size/segments; + const float texCoordStep = textureRepeats / segments; + for (int x=0; xpush_back(osg::Vec3f(x1, y2, 0.f)); + verts->push_back(osg::Vec3f(x1, y1, 0.f)); + verts->push_back(osg::Vec3f(x2, y1, 0.f)); + verts->push_back(osg::Vec3f(x2, y2, 0.f)); + + float u1 = x*texCoordStep; + float v1 = y*texCoordStep; + float u2 = u1 + texCoordStep; + float v2 = v1 + texCoordStep; + + texcoords->push_back(osg::Vec2f(u1, v2)); + texcoords->push_back(osg::Vec2f(u1, v1)); + texcoords->push_back(osg::Vec2f(u2, v1)); + texcoords->push_back(osg::Vec2f(u2, v2)); + } + } + + osg::ref_ptr waterGeom (new osg::Geometry); + waterGeom->setVertexArray(verts); + waterGeom->setTexCoordArray(0, texcoords); + + osg::ref_ptr normal (new osg::Vec3Array); + normal->push_back(osg::Vec3f(0,0,1)); + waterGeom->setNormalArray(normal, osg::Array::BIND_OVERALL); + + waterGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,verts->size())); + return waterGeom; + } + + osg::ref_ptr createSimpleWaterStateSet(float alpha, int renderBin) + { + osg::ref_ptr stateset (new osg::StateSet); + + osg::ref_ptr material (new osg::Material); + material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, alpha)); + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + material->setColorMode(osg::Material::OFF); + stateset->setAttributeAndModes(material, osg::StateAttribute::ON); + + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + + stateset->setRenderBinDetails(renderBin, "RenderBin"); + + return stateset; + } +} diff --git a/components/sceneutil/waterutil.hpp b/components/sceneutil/waterutil.hpp new file mode 100644 index 000000000..7b8c38010 --- /dev/null +++ b/components/sceneutil/waterutil.hpp @@ -0,0 +1,19 @@ +#ifndef OPENMW_COMPONENTS_WATERUTIL_H +#define OPENMW_COMPONENTS_WATERUTIL_H + +#include + +namespace osg +{ + class Geometry; + class StateSet; +} + +namespace SceneUtil +{ + osg::ref_ptr createWaterGeometry(float size, int segments, float textureRepeats); + + osg::ref_ptr createSimpleWaterStateSet(float alpha, int renderBin); +} + +#endif From 9454f4f2e734cf8ee589a9fe483cfa3fae1c3519 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 5 Aug 2016 13:49:44 -0400 Subject: [PATCH 16/20] Use shared water geometry + state generation, Fix water position and render bin, Fix passed cell parameter being ignored --- apps/opencs/view/render/cellmarker.cpp | 2 +- apps/opencs/view/render/cellwater.cpp | 123 +++++++++---------------- apps/opencs/view/render/cellwater.hpp | 8 +- 3 files changed, 51 insertions(+), 82 deletions(-) diff --git a/apps/opencs/view/render/cellmarker.cpp b/apps/opencs/view/render/cellmarker.cpp index 09690190d..abc337ce2 100644 --- a/apps/opencs/view/render/cellmarker.cpp +++ b/apps/opencs/view/render/cellmarker.cpp @@ -75,7 +75,7 @@ CSVRender::CellMarker::CellMarker( mMarkerNode->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN); mMarkerNode->setAutoScaleToScreen(true); mMarkerNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); - mMarkerNode->getOrCreateStateSet()->setRenderBinDetails(2000, "RenderBin"); + mMarkerNode->getOrCreateStateSet()->setRenderBinDetails(osg::StateSet::TRANSPARENT_BIN + 1, "RenderBin"); mMarkerNode->setUserData(new CellMarkerTag(this)); mMarkerNode->setNodeMask(Mask_CellMarker); diff --git a/apps/opencs/view/render/cellwater.cpp b/apps/opencs/view/render/cellwater.cpp index 956864d7b..5e93d589b 100644 --- a/apps/opencs/view/render/cellwater.cpp +++ b/apps/opencs/view/render/cellwater.cpp @@ -3,11 +3,11 @@ #include #include #include -#include #include #include #include +#include #include "../../model/world/cell.hpp" #include "../../model/world/cellcoordinates.hpp" @@ -27,12 +27,14 @@ namespace CSVRender , mWaterTransform(0) , mWaterNode(0) , mWaterGeometry(0) + , mDeleted(false) , mExterior(false) , mHasWater(false) - , mWaterHeight(0) { mWaterTransform = new osg::PositionAttitudeTransform(); - mWaterTransform->setPosition(osg::Vec3f(cellCoords.getX() * CellSize, cellCoords.getY() * CellSize, 0)); + mWaterTransform->setPosition(osg::Vec3f(cellCoords.getX() * CellSize + CellSize / 2.f, + cellCoords.getY() * CellSize + CellSize / 2.f, 0)); + mWaterTransform->setNodeMask(Mask_Water); mParentNode->addChild(mWaterTransform); @@ -42,7 +44,7 @@ namespace CSVRender int cellIndex = mData.getCells().searchId(mId); if (cellIndex > -1) { - updateCellData(mData.getCells().getRecord(cellIndex).get()); + updateCellData(mData.getCells().getRecord(cellIndex)); } // Keep water existance/height up to date @@ -56,28 +58,35 @@ namespace CSVRender mParentNode->removeChild(mWaterTransform); } - void CellWater::updateCellData(const CSMWorld::Cell& cell) + void CellWater::updateCellData(const CSMWorld::Record& cellRecord) { - int cellIndex = mData.getCells().searchId(mId); - if (cellIndex > -1) + mDeleted = cellRecord.isDeleted(); + if (!mDeleted) { - const CSMWorld::Record& cellRecord = mData.getCells().getRecord(cellIndex); + const CSMWorld::Cell& cell = cellRecord.get(); - mDeleted = cellRecord.isDeleted(); - if (!mDeleted) + if (mExterior != cell.isExterior() || mHasWater != cell.hasWater()) { mExterior = cellRecord.get().isExterior(); - mHasWater = cellRecord.get().hasWater(); - mWaterHeight = cellRecord.get().mWater; + + recreate(); + } + + float waterHeight = -1; + if (!mExterior) + { + waterHeight = cellRecord.get().mWater; } + + osg::Vec3d pos = mWaterTransform->getPosition(); + pos.z() = waterHeight; + mWaterTransform->setPosition(pos); } else { - mDeleted = true; + recreate(); } - - update(); } void CellWater::cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) @@ -100,42 +109,22 @@ namespace CSVRender for (int row = rowStart; row <= rowEnd; ++row) { - const CSMWorld::Cell& cell = cells.getRecord(row).get(); + const CSMWorld::Record& cellRecord = cells.getRecord(row); - if (Misc::StringUtils::lowerCase(cell.mId) == mId) - updateCellData(cell); + if (Misc::StringUtils::lowerCase(cellRecord.get().mId) == mId) + updateCellData(cellRecord); } } - void CellWater::update() + void CellWater::recreate() { - const int InteriorSize = CellSize * 10; + const int InteriorScalar = 20; + const int SegmentsPerCell = 1; + const int TextureRepeatsPerCell = 6; - const size_t NumPoints = 4; - const size_t NumIndices = 6; + const float Alpha = 0.5f; - const osg::Vec3f ExteriorPoints[] = - { - osg::Vec3f(0, 0, mWaterHeight), - osg::Vec3f(0, CellSize, mWaterHeight), - osg::Vec3f(CellSize, CellSize, mWaterHeight), - osg::Vec3f(CellSize, 0, mWaterHeight) - }; - - const osg::Vec3f InteriorPoints[] = - { - osg::Vec3f(-InteriorSize, -InteriorSize, mWaterHeight), - osg::Vec3f(-InteriorSize, InteriorSize, mWaterHeight), - osg::Vec3f( InteriorSize, InteriorSize, mWaterHeight), - osg::Vec3f( InteriorSize, -InteriorSize, mWaterHeight) - }; - - const unsigned short TriangleStrip[] = - { - 0, 1, 2, 3, 0, 1 - }; - - const osg::Vec4f Color = osg::Vec4f(0.6f, 0.7f, 1.f, 0.5f); + const int RenderBin = osg::StateSet::TRANSPARENT_BIN - 1; if (mWaterGeometry) { @@ -146,45 +135,25 @@ namespace CSVRender if (mDeleted || !mHasWater) return; - mWaterGeometry = new osg::Geometry(); - - osg::ref_ptr vertices = new osg::Vec3Array(); - osg::ref_ptr colors = new osg::Vec4Array(); - osg::ref_ptr indices = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, - NumIndices); + float size; + int segments; + float textureRepeats; - for (size_t i = 0; i < NumPoints; ++i) + if (mExterior) { - if (mExterior) - vertices->push_back(ExteriorPoints[i]); - else - vertices->push_back(InteriorPoints[i]); + size = CellSize; + segments = SegmentsPerCell; + textureRepeats = TextureRepeatsPerCell; } - - colors->push_back(Color); - - for (size_t i = 0; i < NumIndices; ++i) + else { - indices->setElement(i, TriangleStrip[i]); + size = CellSize * InteriorScalar; + segments = SegmentsPerCell * InteriorScalar; + textureRepeats = TextureRepeatsPerCell * InteriorScalar; } - mWaterGeometry->setVertexArray(vertices); - mWaterGeometry->setColorArray(colors, osg::Array::BIND_OVERALL); - mWaterGeometry->addPrimitiveSet(indices); - - // Transparency - mWaterGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - mWaterGeometry->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON ); - mWaterGeometry->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - mWaterGeometry->getOrCreateStateSet()->setRenderBinDetails(1000, "RenderBin"); - - // Reduce some z-fighting - osg::ref_ptr polygonOffset = new osg::PolygonOffset(); - polygonOffset->setFactor(0.2f); - polygonOffset->setUnits(0.2f); - - mWaterGeometry->getOrCreateStateSet()->setAttributeAndModes(polygonOffset, - osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); + mWaterGeometry = SceneUtil::createWaterGeometry(size, segments, textureRepeats); + mWaterGeometry->setStateSet(SceneUtil::createSimpleWaterStateSet(Alpha, RenderBin)); mWaterNode->addDrawable(mWaterGeometry); } diff --git a/apps/opencs/view/render/cellwater.hpp b/apps/opencs/view/render/cellwater.hpp index a7154e9cb..09830d95a 100644 --- a/apps/opencs/view/render/cellwater.hpp +++ b/apps/opencs/view/render/cellwater.hpp @@ -8,6 +8,8 @@ #include #include +#include "../../model/world/record.hpp" + namespace osg { class Geode; @@ -38,7 +40,7 @@ namespace CSVRender ~CellWater(); - void updateCellData(const CSMWorld::Cell& cell); + void updateCellData(const CSMWorld::Record& cellRecord); private slots: @@ -46,7 +48,7 @@ namespace CSVRender private: - void update(); + void recreate(); static const int CellSize; @@ -61,9 +63,7 @@ namespace CSVRender bool mDeleted; bool mExterior; - bool mHasWater; - float mWaterHeight; }; } From 1f32f1eef513a541b2bff954a33b052511bfb647 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 5 Aug 2016 14:55:40 -0400 Subject: [PATCH 17/20] Add water texture. --- apps/opencs/view/render/cellwater.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/apps/opencs/view/render/cellwater.cpp b/apps/opencs/view/render/cellwater.cpp index 5e93d589b..b8975da49 100644 --- a/apps/opencs/view/render/cellwater.cpp +++ b/apps/opencs/view/render/cellwater.cpp @@ -6,7 +6,10 @@ #include #include +#include #include +#include +#include #include #include "../../model/world/cell.hpp" @@ -155,6 +158,20 @@ namespace CSVRender mWaterGeometry = SceneUtil::createWaterGeometry(size, segments, textureRepeats); mWaterGeometry->setStateSet(SceneUtil::createSimpleWaterStateSet(Alpha, RenderBin)); + // Add water texture + std::string textureName = mData.getFallbackMap()->getFallbackString("Water_SurfaceTexture"); + textureName = "textures/water/" + textureName + "00.dds"; + + Resource::ImageManager* imageManager = mData.getResourceSystem()->getImageManager(); + + osg::ref_ptr waterTexture = new osg::Texture2D(); + waterTexture->setImage(imageManager->getImage(textureName)); + waterTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + waterTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); + + mWaterGeometry->getStateSet()->setTextureAttributeAndModes(0, waterTexture, osg::StateAttribute::ON); + + mWaterNode->addDrawable(mWaterGeometry); } } From 16d0580ce891f7acbc830b7657754d4fff6c2066 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 5 Aug 2016 15:39:08 -0400 Subject: [PATCH 18/20] Fix struct/class mismatch. --- apps/opencs/view/render/cellwater.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/cellwater.hpp b/apps/opencs/view/render/cellwater.hpp index 09830d95a..d2ed9b458 100644 --- a/apps/opencs/view/render/cellwater.hpp +++ b/apps/opencs/view/render/cellwater.hpp @@ -20,7 +20,7 @@ namespace osg namespace CSMWorld { - class Cell; + struct Cell; class CellCoordinates; class Data; } From 83bab29e4b5abb1cc349ff5bc3a88958923c6e17 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 6 Aug 2016 19:00:27 +0100 Subject: [PATCH 19/20] Mainly making compilable under OpenBSD. Renaming one resource file as the space led to issue for qt/moc. --- apps/openmw/crashcatcher.cpp | 4 ++-- apps/wizard/CMakeLists.txt | 2 +- components/files/fixedpath.hpp | 2 +- components/files/linuxpath.cpp | 4 ++-- components/files/linuxpath.hpp | 4 ++-- files/opencs/{flying eye.png => flying-eye.png} | Bin files/opencs/resources.qrc | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) rename files/opencs/{flying eye.png => flying-eye.png} (100%) diff --git a/apps/openmw/crashcatcher.cpp b/apps/openmw/crashcatcher.cpp index 4f0356259..a38d301ea 100644 --- a/apps/openmw/crashcatcher.cpp +++ b/apps/openmw/crashcatcher.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -21,10 +20,11 @@ #ifdef __linux__ #include +#include #ifndef PR_SET_PTRACER #define PR_SET_PTRACER 0x59616d61 #endif -#elif defined (__APPLE__) || defined (__FreeBSD__) +#elif defined (__APPLE__) || defined (__FreeBSD__) || defined(__OpenBSD__) #include #endif diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index dcd944490..dd2e1a748 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -136,7 +136,7 @@ if (BUILD_WITH_CODE_COVERAGE) endif() # Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream -if (UNIX AND NOT APPLE) +if (CMAKE_SYSTEM_NAME MATCHES "Linux") target_link_libraries(openmw-wizard dl Xt) endif() diff --git a/components/files/fixedpath.hpp b/components/files/fixedpath.hpp index 5e0ea6c86..2e72b8154 100644 --- a/components/files/fixedpath.hpp +++ b/components/files/fixedpath.hpp @@ -4,7 +4,7 @@ #include #include -#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) #ifndef ANDROID #include namespace Files { typedef LinuxPath TargetPathType; } diff --git a/components/files/linuxpath.cpp b/components/files/linuxpath.cpp index 212db562c..89b4bf45a 100644 --- a/components/files/linuxpath.cpp +++ b/components/files/linuxpath.cpp @@ -1,6 +1,6 @@ #include "linuxpath.hpp" -#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) #include #include @@ -159,4 +159,4 @@ boost::filesystem::path LinuxPath::getInstallPath() const } /* namespace Files */ -#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */ +#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) */ diff --git a/components/files/linuxpath.hpp b/components/files/linuxpath.hpp index ba9756fc0..7950157bb 100644 --- a/components/files/linuxpath.hpp +++ b/components/files/linuxpath.hpp @@ -1,7 +1,7 @@ #ifndef COMPONENTS_FILES_LINUXPATH_H #define COMPONENTS_FILES_LINUXPATH_H -#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) #include @@ -56,6 +56,6 @@ struct LinuxPath } /* namespace Files */ -#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */ +#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) */ #endif /* COMPONENTS_FILES_LINUXPATH_H */ diff --git a/files/opencs/flying eye.png b/files/opencs/flying-eye.png similarity index 100% rename from files/opencs/flying eye.png rename to files/opencs/flying-eye.png diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc index e9fb12cbe..7e798527c 100644 --- a/files/opencs/resources.qrc +++ b/files/opencs/resources.qrc @@ -77,7 +77,7 @@ Sun-48.png Lightbulb-48.png eyeballdude.png - flying eye.png + flying-eye.png orbit2.png scene-play.png scene-view-references.png From ea06506319ced4a4c7994f6f503db8822c4306d9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Aug 2016 20:34:23 +0200 Subject: [PATCH 20/20] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 816afd084..82372ae36 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -37,6 +37,7 @@ Programmers Cory F. Cohen (cfcohen) Cris Mihalache (Mirceam) darkf + devnexen Dieho Dmitry Shkurskiy (endorph) Douglas Diniz (Dgdiniz)