forked from teamnwah/openmw-tes3coop
Merge pull request #34 from OpenMW/master
Add OpenMW commits from 1st week of August
This commit is contained in:
commit
babba95413
46 changed files with 709 additions and 118 deletions
|
@ -37,6 +37,7 @@ Programmers
|
|||
Cory F. Cohen (cfcohen)
|
||||
Cris Mihalache (Mirceam)
|
||||
darkf
|
||||
devnexen
|
||||
Dieho
|
||||
Dmitry Shkurskiy (endorph)
|
||||
Douglas Diniz (Dgdiniz)
|
||||
|
@ -75,6 +76,7 @@ Programmers
|
|||
Lars Söderberg (Lazaroth)
|
||||
lazydev
|
||||
Leon Saunders (emoose)
|
||||
lohikaarme
|
||||
Lukasz Gromanowski (lgro)
|
||||
Manuel Edelmann (vorenon)
|
||||
Marc Bouvier (CramitDeFrog)
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
#include <string>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#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<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/npcstats.hpp>
|
||||
#include <components/esm/loadskil.hpp>
|
||||
#include <components/esm/animationstate.hpp>
|
||||
|
||||
#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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -37,7 +37,8 @@ namespace CSMWorld
|
|||
///
|
||||
/// \note The worldspace part of \a id is ignored
|
||||
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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace CSMWorld
|
|||
|
||||
namespace CSVRender
|
||||
{
|
||||
class CellWater;
|
||||
class Pathgrid;
|
||||
class TagBase;
|
||||
|
||||
|
@ -49,6 +50,7 @@ namespace CSVRender
|
|||
std::auto_ptr<CellArrow> mCellArrows[4];
|
||||
std::auto_ptr<CellMarker> mCellMarker;
|
||||
std::auto_ptr<CellBorder> mCellBorder;
|
||||
std::auto_ptr<CellWater> mCellWater;
|
||||
std::auto_ptr<Pathgrid> mPathgrid;
|
||||
bool mDeleted;
|
||||
int mSubMode;
|
||||
|
|
|
@ -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(osg::StateSet::TRANSPARENT_BIN + 1, "RenderBin");
|
||||
|
||||
mMarkerNode->setUserData(new CellMarkerTag(this));
|
||||
mMarkerNode->setNodeMask(Mask_CellMarker);
|
||||
|
|
177
apps/opencs/view/render/cellwater.cpp
Normal file
177
apps/opencs/view/render/cellwater.cpp
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
70
apps/opencs/view/render/cellwater.hpp
Normal file
70
apps/opencs/view/render/cellwater.hpp
Normal file
|
@ -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 "mask.hpp"
|
||||
#include "cameracontroller.hpp"
|
||||
|
||||
bool CSVRender::PagedWorldspaceWidget::adjustCells()
|
||||
{
|
||||
|
@ -512,12 +513,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
|
||||
|
||||
// Mark that camera needs setup
|
||||
mCamPositionSet=false;
|
||||
}
|
||||
}
|
||||
else if (hint[0]=='r')
|
||||
|
|
|
@ -84,7 +84,8 @@ namespace CSVRender
|
|||
/// hint system.
|
||||
|
||||
virtual ~PagedWorldspaceWidget();
|
||||
|
||||
|
||||
/// Decodes the the hint string to set of cell that are rendered.
|
||||
void useViewHint (const std::string& hint);
|
||||
|
||||
void setCellSelection(const CSMWorld::CellSelection& selection);
|
||||
|
|
|
@ -109,14 +109,14 @@ namespace CSVRender
|
|||
LightingBright mLightingBright;
|
||||
|
||||
int mPrevMouseX, mPrevMouseY;
|
||||
|
||||
/// Tells update that camera isn't set
|
||||
bool mCamPositionSet;
|
||||
|
||||
FreeCameraController* mFreeCamControl;
|
||||
OrbitCameraController* mOrbitCamControl;
|
||||
CameraController* mCurrentCamControl;
|
||||
|
||||
private:
|
||||
bool mCamPositionSet;
|
||||
|
||||
public slots:
|
||||
void update(double dt);
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
@ -21,10 +20,11 @@
|
|||
|
||||
#ifdef __linux__
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/ucontext.h>
|
||||
#ifndef PR_SET_PTRACER
|
||||
#define PR_SET_PTRACER 0x59616d61
|
||||
#endif
|
||||
#elif defined (__APPLE__) || defined (__FreeBSD__)
|
||||
#elif defined (__APPLE__) || defined (__FreeBSD__) || defined(__OpenBSD__)
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1400,12 +1400,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
|
||||
{
|
||||
|
@ -1428,6 +1428,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<MWWorld::Ptr>& out)
|
||||
{
|
||||
for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
|
||||
|
|
|
@ -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<MWWorld::Ptr>& out);
|
||||
|
||||
|
|
|
@ -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<std::string> &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();
|
||||
|
||||
bool CharacterController::playGroup(const std::string &groupname, int mode, int count)
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -147,7 +147,13 @@ class CharacterController : public MWRender::Animation::TextKeyListener
|
|||
MWWorld::Ptr mPtr;
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<MWWorld::Ptr>& out)
|
||||
{
|
||||
for (PtrControllerMap::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter)
|
||||
|
|
|
@ -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<MWWorld::Ptr>& out);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <components/resource/resourcesystem.hpp>
|
||||
#include <components/resource/imagemanager.hpp>
|
||||
|
||||
#include <components/sceneutil/waterutil.hpp>
|
||||
|
||||
#include <components/nifosg/controller.hpp>
|
||||
#include <components/sceneutil/controller.hpp>
|
||||
|
||||
|
@ -40,58 +42,6 @@
|
|||
#include "renderbin.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
|
||||
{
|
||||
|
||||
|
@ -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<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(MWRender::RenderBin_Water, "RenderBin");
|
||||
osg::ref_ptr<osg::StateSet> stateset = SceneUtil::createSimpleWaterStateSet(alpha, MWRender::RenderBin_Water);
|
||||
|
||||
node->setStateSet(stateset);
|
||||
|
||||
// Add animated textures
|
||||
std::vector<osg::ref_ptr<osg::Texture2D> > textures;
|
||||
int frameCount = mFallback->getFallbackInt("Water_SurfaceFrameCount");
|
||||
std::string texture = mFallback->getFallbackString("Water_SurfaceTexture");
|
||||
|
|
|
@ -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<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");
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define GAME_MWWORLD_REFDATA_H
|
||||
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm/animationstate.hpp>
|
||||
|
||||
#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();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -51,7 +51,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
|
||||
|
@ -79,7 +79,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
|
||||
|
|
37
components/esm/animationstate.cpp
Normal file
37
components/esm/animationstate.cpp
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
34
components/esm/animationstate.hpp
Normal file
34
components/esm/animationstate.hpp
Normal file
|
@ -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;
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <string>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
|
||||
#ifndef ANDROID
|
||||
#include <components/files/linuxpath.hpp>
|
||||
namespace Files { typedef LinuxPath TargetPathType; }
|
||||
|
|
|
@ -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 <cstdlib>
|
||||
#include <cstring>
|
||||
|
@ -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__) */
|
||||
|
|
|
@ -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 <boost/filesystem.hpp>
|
||||
|
||||
|
@ -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 */
|
||||
|
|
79
components/sceneutil/waterutil.cpp
Normal file
79
components/sceneutil/waterutil.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
19
components/sceneutil/waterutil.hpp
Normal file
19
components/sceneutil/waterutil.hpp
Normal file
|
@ -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="bright">Lightbulb-48.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="play">scene-play.png</file>
|
||||
<file alias="scene-view-1">scene-view-references.png</file>
|
||||
|
|
Loading…
Reference in a new issue