Merge pull request #34 from OpenMW/master

Add OpenMW commits from 1st week of August
coverity_scan^2
David Cernat 9 years ago committed by GitHub
commit babba95413

@ -37,6 +37,7 @@ Programmers
Cory F. Cohen (cfcohen) Cory F. Cohen (cfcohen)
Cris Mihalache (Mirceam) Cris Mihalache (Mirceam)
darkf darkf
devnexen
Dieho Dieho
Dmitry Shkurskiy (endorph) Dmitry Shkurskiy (endorph)
Douglas Diniz (Dgdiniz) Douglas Diniz (Dgdiniz)
@ -75,6 +76,7 @@ Programmers
Lars Söderberg (Lazaroth) Lars Söderberg (Lazaroth)
lazydev lazydev
Leon Saunders (emoose) Leon Saunders (emoose)
lohikaarme
Lukasz Gromanowski (lgro) Lukasz Gromanowski (lgro)
Manuel Edelmann (vorenon) Manuel Edelmann (vorenon)
Marc Bouvier (CramitDeFrog) Marc Bouvier (CramitDeFrog)

@ -1,3 +1,9 @@
#include <string>
#include <iostream>
#include <limits>
#include <components/misc/stringops.hpp>
#include "convertacdt.hpp" #include "convertacdt.hpp"
namespace ESSImport namespace ESSImport
@ -49,4 +55,49 @@ namespace ESSImport
npcStats.mTimeToStartDrowning = actorData.mACDT.mBreathMeter; 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<size_t>::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<unsigned int>(anis.mGroupIndex) << std::endl;
}
} }

@ -4,6 +4,7 @@
#include <components/esm/creaturestats.hpp> #include <components/esm/creaturestats.hpp>
#include <components/esm/npcstats.hpp> #include <components/esm/npcstats.hpp>
#include <components/esm/loadskil.hpp> #include <components/esm/loadskil.hpp>
#include <components/esm/animationstate.hpp>
#include "importacdt.hpp" #include "importacdt.hpp"
@ -18,6 +19,8 @@ namespace ESSImport
void convertACSC (const ACSC& acsc, ESM::CreatureStats& cStats); void convertACSC (const ACSC& acsc, ESM::CreatureStats& cStats);
void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats); void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats);
void convertANIS (const ANIS& anis, ESM::AnimationState& state);
} }
#endif #endif

@ -34,6 +34,9 @@ namespace
objstate.mCount = 0; objstate.mCount = 0;
convertSCRI(cellref.mSCRI, objstate.mLocals); convertSCRI(cellref.mSCRI, objstate.mLocals);
objstate.mHasLocals = !objstate.mLocals.mVariables.empty(); objstate.mHasLocals = !objstate.mLocals.mVariables.empty();
if (cellref.mHasANIS)
convertANIS(cellref.mANIS, objstate.mAnimationState);
} }
bool isIndexedRefId(const std::string& indexedRefId) bool isIndexedRefId(const std::string& indexedRefId)

@ -123,8 +123,13 @@ namespace ESSImport
if (esm.isNextSub("ND3D")) if (esm.isNextSub("ND3D"))
esm.skipHSub(); esm.skipHSub();
mHasANIS = false;
if (esm.isNextSub("ANIS")) if (esm.isNextSub("ANIS"))
esm.skipHSub(); {
mHasANIS = true;
esm.getHT(mANIS);
}
} }
} }

@ -55,6 +55,12 @@ namespace ESSImport
unsigned char mCorpseClearCountdown; // hours? unsigned char mCorpseClearCountdown; // hours?
unsigned char mUnknown3[71]; unsigned char mUnknown3[71];
}; };
struct ANIS
{
unsigned char mGroupIndex;
unsigned char mUnknown[3];
float mTime;
};
#pragma pack(pop) #pragma pack(pop)
struct ActorData : public ESM::CellRef struct ActorData : public ESM::CellRef
@ -77,6 +83,9 @@ namespace ESSImport
SCRI mSCRI; SCRI mSCRI;
bool mHasANIS;
ANIS mANIS; // scripted animation state
void load(ESM::ESMReader& esm); void load(ESM::ESMReader& esm);
}; };

@ -87,6 +87,7 @@ opencs_units (view/render
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
previewwidget editmode instancemode instanceselectionmode instancemovemode previewwidget editmode instancemode instanceselectionmode instancemovemode
orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller
cellwater
) )
opencs_units_noqt (view/render opencs_units_noqt (view/render

@ -37,7 +37,8 @@ namespace CSMWorld
/// ///
/// \note The worldspace part of \a id is ignored /// \note The worldspace part of \a id is ignored
static std::pair<CellCoordinates, bool> fromId (const std::string& id); static std::pair<CellCoordinates, bool> fromId (const std::string& id);
/// \return cell coordinates such that given world coordinates are in it.
static std::pair<int, int> coordinatesToCellIndex (float x, float y); static std::pair<int, int> coordinatesToCellIndex (float x, float y);
}; };

@ -16,6 +16,7 @@
#include "../../model/world/refcollection.hpp" #include "../../model/world/refcollection.hpp"
#include "../../model/world/cellcoordinates.hpp" #include "../../model/world/cellcoordinates.hpp"
#include "cellwater.hpp"
#include "mask.hpp" #include "mask.hpp"
#include "pathgrid.hpp" #include "pathgrid.hpp"
#include "terrainstorage.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)); mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates));
mCellWater.reset(new CellWater(mData, mCellNode, mId, mCoordinates));
} }
} }

@ -35,6 +35,7 @@ namespace CSMWorld
namespace CSVRender namespace CSVRender
{ {
class CellWater;
class Pathgrid; class Pathgrid;
class TagBase; class TagBase;
@ -49,6 +50,7 @@ namespace CSVRender
std::auto_ptr<CellArrow> mCellArrows[4]; std::auto_ptr<CellArrow> mCellArrows[4];
std::auto_ptr<CellMarker> mCellMarker; std::auto_ptr<CellMarker> mCellMarker;
std::auto_ptr<CellBorder> mCellBorder; std::auto_ptr<CellBorder> mCellBorder;
std::auto_ptr<CellWater> mCellWater;
std::auto_ptr<Pathgrid> mPathgrid; std::auto_ptr<Pathgrid> mPathgrid;
bool mDeleted; bool mDeleted;
int mSubMode; int mSubMode;

@ -75,6 +75,7 @@ CSVRender::CellMarker::CellMarker(
mMarkerNode->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN); mMarkerNode->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN);
mMarkerNode->setAutoScaleToScreen(true); mMarkerNode->setAutoScaleToScreen(true);
mMarkerNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); mMarkerNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
mMarkerNode->getOrCreateStateSet()->setRenderBinDetails(osg::StateSet::TRANSPARENT_BIN + 1, "RenderBin");
mMarkerNode->setUserData(new CellMarkerTag(this)); mMarkerNode->setUserData(new CellMarkerTag(this));
mMarkerNode->setNodeMask(Mask_CellMarker); mMarkerNode->setNodeMask(Mask_CellMarker);

@ -0,0 +1,177 @@
#include "cellwater.hpp"
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/PositionAttitudeTransform>
#include <components/esm/loadland.hpp>
#include <components/fallback/fallback.hpp>
#include <components/misc/stringops.hpp>
#include <components/resource/imagemanager.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/sceneutil/waterutil.hpp>
#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)
, mDeleted(false)
, mExterior(false)
, mHasWater(false)
{
mWaterTransform = new osg::PositionAttitudeTransform();
mWaterTransform->setPosition(osg::Vec3f(cellCoords.getX() * CellSize + CellSize / 2.f,
cellCoords.getY() * CellSize + CellSize / 2.f, 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));
}
// 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::Record<CSMWorld::Cell>& cellRecord)
{
mDeleted = cellRecord.isDeleted();
if (!mDeleted)
{
const CSMWorld::Cell& cell = cellRecord.get();
if (mExterior != cell.isExterior() || mHasWater != cell.hasWater())
{
mExterior = cellRecord.get().isExterior();
mHasWater = cellRecord.get().hasWater();
recreate();
}
float waterHeight = -1;
if (!mExterior)
{
waterHeight = cellRecord.get().mWater;
}
osg::Vec3d pos = mWaterTransform->getPosition();
pos.z() = waterHeight;
mWaterTransform->setPosition(pos);
}
else
{
recreate();
}
}
void CellWater::cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
{
const CSMWorld::Collection<CSMWorld::Cell>& 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::Record<CSMWorld::Cell>& cellRecord = cells.getRecord(row);
if (Misc::StringUtils::lowerCase(cellRecord.get().mId) == mId)
updateCellData(cellRecord);
}
}
void CellWater::recreate()
{
const int InteriorScalar = 20;
const int SegmentsPerCell = 1;
const int TextureRepeatsPerCell = 6;
const float Alpha = 0.5f;
const int RenderBin = osg::StateSet::TRANSPARENT_BIN - 1;
if (mWaterGeometry)
{
mWaterNode->removeDrawable(mWaterGeometry);
mWaterGeometry = 0;
}
if (mDeleted || !mHasWater)
return;
float size;
int segments;
float textureRepeats;
if (mExterior)
{
size = CellSize;
segments = SegmentsPerCell;
textureRepeats = TextureRepeatsPerCell;
}
else
{
size = CellSize * InteriorScalar;
segments = SegmentsPerCell * InteriorScalar;
textureRepeats = TextureRepeatsPerCell * InteriorScalar;
}
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<osg::Texture2D> 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);
}
}

@ -0,0 +1,70 @@
#ifndef CSV_RENDER_CELLWATER_H
#define CSV_RENDER_CELLWATER_H
#include <string>
#include <osg/ref_ptr>
#include <QObject>
#include <QModelIndex>
#include "../../model/world/record.hpp"
namespace osg
{
class Geode;
class Geometry;
class Group;
class PositionAttitudeTransform;
}
namespace CSMWorld
{
struct 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::Record<CSMWorld::Cell>& cellRecord);
private slots:
void cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
private:
void recreate();
static const int CellSize;
CSMWorld::Data& mData;
std::string mId;
osg::Group* mParentNode;
osg::ref_ptr<osg::PositionAttitudeTransform> mWaterTransform;
osg::ref_ptr<osg::Geode> mWaterNode;
osg::ref_ptr<osg::Geometry> mWaterGeometry;
bool mDeleted;
bool mExterior;
bool mHasWater;
};
}
#endif

@ -19,6 +19,7 @@
#include "editmode.hpp" #include "editmode.hpp"
#include "mask.hpp" #include "mask.hpp"
#include "cameracontroller.hpp"
bool CSVRender::PagedWorldspaceWidget::adjustCells() bool CSVRender::PagedWorldspaceWidget::adjustCells()
{ {
@ -512,12 +513,15 @@ void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint)
{ {
char ignore1; // : or ; char ignore1; // : or ;
char ignore2; // # char ignore2; // #
// Current coordinate
int x, y; int x, y;
// Loop throught all the coordinates to add them to selection
while (stream >> ignore1 >> ignore2 >> x >> y) while (stream >> ignore1 >> ignore2 >> x >> y)
selection.add (CSMWorld::CellCoordinates (x, y)); selection.add (CSMWorld::CellCoordinates (x, y));
/// \todo adjust camera position // Mark that camera needs setup
mCamPositionSet=false;
} }
} }
else if (hint[0]=='r') else if (hint[0]=='r')

@ -84,7 +84,8 @@ namespace CSVRender
/// hint system. /// hint system.
virtual ~PagedWorldspaceWidget(); virtual ~PagedWorldspaceWidget();
/// Decodes the the hint string to set of cell that are rendered.
void useViewHint (const std::string& hint); void useViewHint (const std::string& hint);
void setCellSelection(const CSMWorld::CellSelection& selection); void setCellSelection(const CSMWorld::CellSelection& selection);

@ -109,14 +109,14 @@ namespace CSVRender
LightingBright mLightingBright; LightingBright mLightingBright;
int mPrevMouseX, mPrevMouseY; int mPrevMouseX, mPrevMouseY;
/// Tells update that camera isn't set
bool mCamPositionSet;
FreeCameraController* mFreeCamControl; FreeCameraController* mFreeCamControl;
OrbitCameraController* mOrbitCamControl; OrbitCameraController* mOrbitCamControl;
CameraController* mCurrentCamControl; CameraController* mCurrentCamControl;
private:
bool mCamPositionSet;
public slots: public slots:
void update(double dt); void update(double dt);

@ -5,7 +5,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/ucontext.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
@ -21,10 +20,11 @@
#ifdef __linux__ #ifdef __linux__
#include <sys/prctl.h> #include <sys/prctl.h>
#include <sys/ucontext.h>
#ifndef PR_SET_PTRACER #ifndef PR_SET_PTRACER
#define PR_SET_PTRACER 0x59616d61 #define PR_SET_PTRACER 0x59616d61
#endif #endif
#elif defined (__APPLE__) || defined (__FreeBSD__) #elif defined (__APPLE__) || defined (__FreeBSD__) || defined(__OpenBSD__)
#include <signal.h> #include <signal.h>
#endif #endif

@ -159,12 +159,14 @@ namespace MWBase
virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0; virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0;
///< Forces an object to refresh its animation state. ///< 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 ///< Run animation for a MW-reference. Calls to this function for references that are currently not
/// in the scene should be ignored. /// in the scene should be ignored.
/// ///
/// \param mode 0 normal, 1 immediate start, 2 immediate loop /// \param mode 0 normal, 1 immediate start, 2 immediate loop
/// \param count How many times the animation should be run /// \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 /// \return Success or error
virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; 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; 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 /// 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) /// paused we may want to do it manually (after equipping permanent enchantment)
virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0; virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0;

@ -1400,12 +1400,12 @@ namespace MWMechanics
iter->second->getCharacterController()->forceStateUpdate(); 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); PtrActorMap::iterator iter = mActors.find(ptr);
if(iter != mActors.end()) if(iter != mActors.end())
{ {
return iter->second->getCharacterController()->playGroup(groupName, mode, number); return iter->second->getCharacterController()->playGroup(groupName, mode, number, persist);
} }
else else
{ {
@ -1428,6 +1428,12 @@ namespace MWMechanics
return false; 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<MWWorld::Ptr>& out) void Actors::getObjectsInRange(const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& out)
{ {
for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter) for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)

@ -109,9 +109,10 @@ namespace MWMechanics
void forceStateUpdate(const MWWorld::Ptr &ptr); 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); void skipAnimation(const MWWorld::Ptr& ptr);
bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName);
void persistAnimationStates();
void getObjectsInRange(const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& out); void getObjectsInRange(const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& out);

@ -762,12 +762,17 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true); refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true);
mAnimation->runAnimation(0.f); mAnimation->runAnimation(0.f);
unpersistAnimationState();
} }
CharacterController::~CharacterController() CharacterController::~CharacterController()
{ {
if (mAnimation) if (mAnimation)
{
persistAnimationState();
mAnimation->setTextKeyListener(NULL); mAnimation->setTextKeyListener(NULL);
}
} }
void split(const std::string &s, char delim, std::vector<std::string> &elems) { void split(const std::string &s, char delim, std::vector<std::string> &elems) {
@ -1557,14 +1562,14 @@ void CharacterController::update(float duration)
{ {
if(mAnimQueue.size() > 1) 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(); mAnimQueue.pop_front();
mAnimation->play(mAnimQueue.front().first, Priority_Default, mAnimation->play(mAnimQueue.front().mGroup, Priority_Default,
MWRender::Animation::BlendMask_All, false, 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) 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(); mAnimQueue.pop_front();
mAnimation->play(mAnimQueue.front().first, Priority_Default, mAnimation->play(mAnimQueue.front().mGroup, Priority_Default,
MWRender::Animation::BlendMask_All, false, 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()); 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)) if(!mAnimation || !mAnimation->hasAnimation(groupname))
{ {
@ -1962,10 +2033,16 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int
else else
{ {
count = std::max(count, 1); 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(); clearAnimQueue();
mAnimQueue.push_back(std::make_pair(groupname, count-1)); mAnimQueue.push_back(entry);
mAnimation->disable(mCurrentIdle); mAnimation->disable(mCurrentIdle);
mCurrentIdle.clear(); mCurrentIdle.clear();
@ -1978,9 +2055,9 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int
else if(mode == 0) else if(mode == 0)
{ {
if (!mAnimQueue.empty()) if (!mAnimQueue.empty())
mAnimation->stopLooping(mAnimQueue.front().first); mAnimation->stopLooping(mAnimQueue.front().mGroup);
mAnimQueue.resize(1); mAnimQueue.resize(1);
mAnimQueue.push_back(std::make_pair(groupname, count-1)); mAnimQueue.push_back(entry);
} }
} }
return true; return true;
@ -2002,7 +2079,7 @@ bool CharacterController::isAnimPlaying(const std::string &groupName)
void CharacterController::clearAnimQueue() void CharacterController::clearAnimQueue()
{ {
if(!mAnimQueue.empty()) if(!mAnimQueue.empty())
mAnimation->disable(mAnimQueue.front().first); mAnimation->disable(mAnimQueue.front().mGroup);
mAnimQueue.clear(); mAnimQueue.clear();
} }

@ -147,7 +147,13 @@ class CharacterController : public MWRender::Animation::TextKeyListener
MWWorld::Ptr mPtr; MWWorld::Ptr mPtr;
MWRender::Animation *mAnimation; MWRender::Animation *mAnimation;
typedef std::deque<std::pair<std::string,size_t> > AnimationQueue; struct AnimationQueueEntry
{
std::string mGroup;
size_t mLoopCount;
bool mPersist;
};
typedef std::deque<AnimationQueueEntry> AnimationQueue;
AnimationQueue mAnimQueue; AnimationQueue mAnimQueue;
CharacterState mIdleState; CharacterState mIdleState;
@ -236,7 +242,10 @@ public:
void update(float duration); 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(); void skipAnim();
bool isAnimPlaying(const std::string &groupName); bool isAnimPlaying(const std::string &groupName);

@ -842,12 +842,12 @@ namespace MWMechanics
mActors.forceStateUpdate(ptr); 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()) if(ptr.getClass().isActor())
return mActors.playAnimationGroup(ptr, groupName, mode, number); return mActors.playAnimationGroup(ptr, groupName, mode, number, persist);
else else
return mObjects.playAnimationGroup(ptr, groupName, mode, number); return mObjects.playAnimationGroup(ptr, groupName, mode, number, persist);
} }
void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr)
{ {
@ -864,6 +864,12 @@ namespace MWMechanics
return false; return false;
} }
void MechanicsManager::persistAnimationStates()
{
mActors.persistAnimationStates();
mObjects.persistAnimationStates();
}
void MechanicsManager::updateMagicEffects(const MWWorld::Ptr &ptr) void MechanicsManager::updateMagicEffects(const MWWorld::Ptr &ptr)
{ {
mActors.updateMagicEffects(ptr); mActors.updateMagicEffects(ptr);

@ -146,9 +146,10 @@ namespace MWMechanics
/// Attempt to play an animation group /// Attempt to play an animation group
/// @return Success or error /// @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 void skipAnimation(const MWWorld::Ptr& ptr);
virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName); 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 /// 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) /// paused we may want to do it manually (after equipping permanent enchantment)

@ -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); PtrControllerMap::iterator iter = mObjects.find(ptr);
if(iter != mObjects.end()) if(iter != mObjects.end())
{ {
return iter->second->playGroup(groupName, mode, number); return iter->second->playGroup(groupName, mode, number, persist);
} }
else else
{ {
@ -99,6 +99,12 @@ void Objects::skipAnimation(const MWWorld::Ptr& ptr)
iter->second->skipAnim(); 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<MWWorld::Ptr>& out) void Objects::getObjectsInRange(const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& out)
{ {
for (PtrControllerMap::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) for (PtrControllerMap::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter)

@ -38,8 +38,9 @@ namespace MWMechanics
void update(float duration, bool paused); void update(float duration, bool paused);
///< Update object animations ///< 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 skipAnimation(const MWWorld::Ptr& ptr);
void persistAnimationStates();
void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& out); void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& out);
}; };

@ -843,6 +843,15 @@ namespace MWRender
return iter->second.getTime(); 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) void Animation::disable(const std::string &groupname)
{ {
AnimStateMap::iterator iter = mStates.find(groupname); AnimStateMap::iterator iter = mStates.find(groupname);

@ -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. /// 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; float getCurrentTime(const std::string& groupname) const;
size_t getCurrentLoopCount(const std::string& groupname) const;
/** Disables the specified animation group; /** Disables the specified animation group;
* \param groupname Animation group to disable. * \param groupname Animation group to disable.
*/ */

@ -24,6 +24,8 @@
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <components/resource/imagemanager.hpp> #include <components/resource/imagemanager.hpp>
#include <components/sceneutil/waterutil.hpp>
#include <components/nifosg/controller.hpp> #include <components/nifosg/controller.hpp>
#include <components/sceneutil/controller.hpp> #include <components/sceneutil/controller.hpp>
@ -40,58 +42,6 @@
#include "renderbin.hpp" #include "renderbin.hpp"
#include "util.hpp" #include "util.hpp"
namespace
{
osg::ref_ptr<osg::Geometry> createWaterGeometry(float size, int segments, float textureRepeats)
{
osg::ref_ptr<osg::Vec3Array> verts (new osg::Vec3Array);
osg::ref_ptr<osg::Vec2Array> 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; x<segments; ++x)
{
for (int y=0; y<segments; ++y)
{
float x1 = -size/2.f + x*step;
float y1 = -size/2.f + y*step;
float x2 = x1 + step;
float y2 = y1 + step;
verts->push_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<osg::Geometry> waterGeom (new osg::Geometry);
waterGeom->setVertexArray(verts);
waterGeom->setTexCoordArray(0, texcoords);
osg::ref_ptr<osg::Vec3Array> 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 namespace MWRender
{ {
@ -465,7 +415,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem
{ {
mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback)); 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->setDrawCallback(new DepthClampCallback);
mWaterGeom->setNodeMask(Mask_Water); mWaterGeom->setNodeMask(Mask_Water);
@ -527,26 +477,11 @@ void Water::updateWaterMaterial()
void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) void Water::createSimpleWaterStateSet(osg::Node* node, float alpha)
{ {
osg::ref_ptr<osg::StateSet> stateset (new osg::StateSet); osg::ref_ptr<osg::StateSet> stateset = SceneUtil::createSimpleWaterStateSet(alpha, MWRender::RenderBin_Water);
osg::ref_ptr<osg::Material> 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<osg::Depth> depth (new osg::Depth);
depth->setWriteMask(false);
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin");
node->setStateSet(stateset); node->setStateSet(stateset);
// Add animated textures
std::vector<osg::ref_ptr<osg::Texture2D> > textures; std::vector<osg::ref_ptr<osg::Texture2D> > textures;
int frameCount = mFallback->getFallbackInt("Water_SurfaceFrameCount"); int frameCount = mFallback->getFallbackInt("Water_SurfaceFrameCount");
std::string texture = mFallback->getFallbackString("Water_SurfaceTexture"); std::string texture = mFallback->getFallbackString("Water_SurfaceTexture");

@ -56,7 +56,7 @@ namespace MWScript
throw std::runtime_error ("animation mode out of range"); throw std::runtime_error ("animation mode out of range");
} }
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, std::numeric_limits<int>::max()); MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, std::numeric_limits<int>::max(), true);
} }
}; };
@ -89,7 +89,7 @@ namespace MWScript
throw std::runtime_error ("animation mode out of range"); 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);
} }
}; };

@ -219,6 +219,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
else else
slot = character->updateSlot (slot, profile); 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 // 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. // existing save file we are overwriting.
std::stringstream stream; std::stringstream stream;

@ -31,6 +31,8 @@ namespace MWWorld
mDeletedByContentFile = refData.mDeletedByContentFile; mDeletedByContentFile = refData.mDeletedByContentFile;
mFlags = refData.mFlags; mFlags = refData.mFlags;
mAnimationState = refData.mAnimationState;
mCustomData = refData.mCustomData ? refData.mCustomData->clone() : 0; mCustomData = refData.mCustomData ? refData.mCustomData->clone() : 0;
} }
@ -65,6 +67,7 @@ namespace MWWorld
mEnabled (objectState.mEnabled != 0), mEnabled (objectState.mEnabled != 0),
mCount (objectState.mCount), mCount (objectState.mCount),
mPosition (objectState.mPosition), mPosition (objectState.mPosition),
mAnimationState(objectState.mAnimationState),
mCustomData (0), mCustomData (0),
mChanged(true), mFlags(objectState.mFlags) // Loading from a savegame -> assume changed mChanged(true), mFlags(objectState.mFlags) // Loading from a savegame -> assume changed
{ {
@ -96,6 +99,8 @@ namespace MWWorld
objectState.mCount = mCount; objectState.mCount = mCount;
objectState.mPosition = mPosition; objectState.mPosition = mPosition;
objectState.mFlags = mFlags; objectState.mFlags = mFlags;
objectState.mAnimationState = mAnimationState;
} }
RefData& RefData::operator= (const RefData& refData) RefData& RefData::operator= (const RefData& refData)
@ -269,4 +274,15 @@ namespace MWWorld
else else
return false; return false;
} }
const ESM::AnimationState& RefData::getAnimationState() const
{
return mAnimationState;
}
ESM::AnimationState& RefData::getAnimationState()
{
return mAnimationState;
}
} }

@ -2,6 +2,7 @@
#define GAME_MWWORLD_REFDATA_H #define GAME_MWWORLD_REFDATA_H
#include <components/esm/defs.hpp> #include <components/esm/defs.hpp>
#include <components/esm/animationstate.hpp>
#include "../mwscript/locals.hpp" #include "../mwscript/locals.hpp"
@ -42,6 +43,8 @@ namespace MWWorld
ESM::Position mPosition; ESM::Position mPosition;
ESM::AnimationState mAnimationState;
CustomData *mCustomData; CustomData *mCustomData;
void copy (const RefData& refData); void copy (const RefData& refData);
@ -132,6 +135,9 @@ namespace MWWorld
bool hasChanged() const; bool hasChanged() const;
///< Has this RefData changed since it was originally loaded? ///< Has this RefData changed since it was originally loaded?
const ESM::AnimationState& getAnimationState() const;
ESM::AnimationState& getAnimationState();
}; };
} }

@ -136,7 +136,7 @@ if (BUILD_WITH_CODE_COVERAGE)
endif() endif()
# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream # 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) target_link_libraries(openmw-wizard dl Xt)
endif() endif()

@ -51,7 +51,7 @@ add_component_dir (shader
add_component_dir (sceneutil add_component_dir (sceneutil
clone attach visitor util statesetupdater controller skeleton riggeometry lightcontroller 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 add_component_dir (nif
@ -79,7 +79,7 @@ add_component_dir (esm
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter 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 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 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 add_component_dir (esmterrain

@ -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);
}
}
}

@ -0,0 +1,34 @@
#ifndef OPENMW_ESM_ANIMATIONSTATE_H
#define OPENMW_ESM_ANIMATIONSTATE_H
#include <string>
#include <vector>
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<ScriptedAnimation> ScriptedAnimations;
ScriptedAnimations mScriptedAnims;
void load(ESMReader& esm);
void save(ESMWriter& esm) const;
};
}
#endif

@ -34,6 +34,8 @@ void ESM::ObjectState::load (ESMReader &esm)
int unused; int unused;
esm.getHNOT(unused, "LTIM"); esm.getHNOT(unused, "LTIM");
mAnimationState.load(esm);
// FIXME: assuming "false" as default would make more sense, but also break compatibility with older save files // FIXME: assuming "false" as default would make more sense, but also break compatibility with older save files
mHasCustomState = true; mHasCustomState = true;
esm.getHNOT (mHasCustomState, "HCUS"); esm.getHNOT (mHasCustomState, "HCUS");
@ -61,6 +63,8 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const
if (mFlags != 0) if (mFlags != 0)
esm.writeHNT ("FLAG", mFlags); esm.writeHNT ("FLAG", mFlags);
mAnimationState.save(esm);
if (!mHasCustomState) if (!mHasCustomState)
esm.writeHNT ("HCUS", false); esm.writeHNT ("HCUS", false);
} }

@ -6,6 +6,7 @@
#include "cellref.hpp" #include "cellref.hpp"
#include "locals.hpp" #include "locals.hpp"
#include "animationstate.hpp"
namespace ESM namespace ESM
{ {
@ -31,6 +32,8 @@ namespace ESM
unsigned int mVersion; unsigned int mVersion;
ESM::AnimationState mAnimationState;
ObjectState() : mHasCustomState(true), mVersion(0) ObjectState() : mHasCustomState(true), mVersion(0)
{} {}

@ -4,7 +4,7 @@
#include <string> #include <string>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
#ifndef ANDROID #ifndef ANDROID
#include <components/files/linuxpath.hpp> #include <components/files/linuxpath.hpp>
namespace Files { typedef LinuxPath TargetPathType; } namespace Files { typedef LinuxPath TargetPathType; }

@ -1,6 +1,6 @@
#include "linuxpath.hpp" #include "linuxpath.hpp"
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
@ -159,4 +159,4 @@ boost::filesystem::path LinuxPath::getInstallPath() const
} /* namespace Files */ } /* namespace Files */
#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */ #endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) */

@ -1,7 +1,7 @@
#ifndef COMPONENTS_FILES_LINUXPATH_H #ifndef COMPONENTS_FILES_LINUXPATH_H
#define 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 <boost/filesystem.hpp> #include <boost/filesystem.hpp>
@ -56,6 +56,6 @@ struct LinuxPath
} /* namespace Files */ } /* 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 */ #endif /* COMPONENTS_FILES_LINUXPATH_H */

@ -0,0 +1,79 @@
#include "waterutil.hpp"
#include <osg/Depth>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/StateSet>
namespace SceneUtil
{
osg::ref_ptr<osg::Geometry> createWaterGeometry(float size, int segments, float textureRepeats)
{
osg::ref_ptr<osg::Vec3Array> verts (new osg::Vec3Array);
osg::ref_ptr<osg::Vec2Array> 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; x<segments; ++x)
{
for (int y=0; y<segments; ++y)
{
float x1 = -size/2.f + x*step;
float y1 = -size/2.f + y*step;
float x2 = x1 + step;
float y2 = y1 + step;
verts->push_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<osg::Geometry> waterGeom (new osg::Geometry);
waterGeom->setVertexArray(verts);
waterGeom->setTexCoordArray(0, texcoords);
osg::ref_ptr<osg::Vec3Array> 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<osg::StateSet> createSimpleWaterStateSet(float alpha, int renderBin)
{
osg::ref_ptr<osg::StateSet> stateset (new osg::StateSet);
osg::ref_ptr<osg::Material> 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<osg::Depth> depth (new osg::Depth);
depth->setWriteMask(false);
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
stateset->setRenderBinDetails(renderBin, "RenderBin");
return stateset;
}
}

@ -0,0 +1,19 @@
#ifndef OPENMW_COMPONENTS_WATERUTIL_H
#define OPENMW_COMPONENTS_WATERUTIL_H
#include <osg/ref_ptr>
namespace osg
{
class Geometry;
class StateSet;
}
namespace SceneUtil
{
osg::ref_ptr<osg::Geometry> createWaterGeometry(float size, int segments, float textureRepeats);
osg::ref_ptr<osg::StateSet> createSimpleWaterStateSet(float alpha, int renderBin);
}
#endif

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

@ -77,7 +77,7 @@
<file alias="day">Sun-48.png</file> <file alias="day">Sun-48.png</file>
<file alias="bright">Lightbulb-48.png</file> <file alias="bright">Lightbulb-48.png</file>
<file alias="1st-person">eyeballdude.png</file> <file alias="1st-person">eyeballdude.png</file>
<file alias="free-camera">flying eye.png</file> <file alias="free-camera">flying-eye.png</file>
<file alias="orbiting-camera">orbit2.png</file> <file alias="orbiting-camera">orbit2.png</file>
<file alias="play">scene-play.png</file> <file alias="play">scene-play.png</file>
<file alias="scene-view-1">scene-view-references.png</file> <file alias="scene-view-1">scene-view-references.png</file>

Loading…
Cancel
Save