forked from teamnwah/openmw-tes3coop
Merge remote-tracking branch 'scrawl/master'
This commit is contained in:
commit
ef8c0fab73
7 changed files with 128 additions and 40 deletions
|
@ -141,7 +141,6 @@ namespace MWGui
|
||||||
, mMaxTime(0)
|
, mMaxTime(0)
|
||||||
{
|
{
|
||||||
// defines
|
// defines
|
||||||
mFixedWidth = 300;
|
|
||||||
mBottomPadding = 20;
|
mBottomPadding = 20;
|
||||||
mNextBoxPadding = 20;
|
mNextBoxPadding = 20;
|
||||||
|
|
||||||
|
@ -149,41 +148,21 @@ namespace MWGui
|
||||||
|
|
||||||
mMessageWidget->setOverflowToTheLeft(true);
|
mMessageWidget->setOverflowToTheLeft(true);
|
||||||
mMessageWidget->setCaptionWithReplacing(mMessage);
|
mMessageWidget->setCaptionWithReplacing(mMessage);
|
||||||
|
|
||||||
MyGUI::IntSize size;
|
|
||||||
size.width = mFixedWidth;
|
|
||||||
size.height = 100; // dummy
|
|
||||||
|
|
||||||
mMessageWidget->setSize(size);
|
|
||||||
|
|
||||||
MyGUI::IntSize textSize = mMessageWidget->getTextSize();
|
|
||||||
|
|
||||||
size.height = mHeight = textSize.height + 20; // this is the padding between the text and the box
|
|
||||||
|
|
||||||
mMainWidget->setSize(size);
|
|
||||||
size.width -= 15; // this is to center the text (see messagebox.layout, Widget type="Edit" position="-2 -3 0 0")
|
|
||||||
mMessageWidget->setSize(size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageBox::update (int height)
|
void MessageBox::update (int height)
|
||||||
{
|
{
|
||||||
MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize();
|
MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize();
|
||||||
MyGUI::IntCoord coord;
|
MyGUI::IntPoint pos;
|
||||||
coord.left = (gameWindowSize.width - mFixedWidth)/2;
|
pos.left = (gameWindowSize.width - mMainWidget->getWidth())/2;
|
||||||
coord.top = (gameWindowSize.height - mHeight - height - mBottomPadding);
|
pos.top = (gameWindowSize.height - mMainWidget->getHeight() - height - mBottomPadding);
|
||||||
|
|
||||||
MyGUI::IntSize size;
|
mMainWidget->setPosition(pos);
|
||||||
size.width = mFixedWidth;
|
|
||||||
size.height = mHeight;
|
|
||||||
|
|
||||||
mMainWidget->setCoord(coord);
|
|
||||||
mMainWidget->setSize(size);
|
|
||||||
mMainWidget->setVisible(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int MessageBox::getHeight ()
|
int MessageBox::getHeight ()
|
||||||
{
|
{
|
||||||
return mHeight+mNextBoxPadding; // 20 is the padding between this and the next MessageBox
|
return mMainWidget->getHeight()+mNextBoxPadding; // 20 is the padding between this and the next MessageBox
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -63,10 +63,8 @@ namespace MWGui
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MessageBoxManager& mMessageBoxManager;
|
MessageBoxManager& mMessageBoxManager;
|
||||||
int mHeight;
|
|
||||||
const std::string& mMessage;
|
const std::string& mMessage;
|
||||||
MyGUI::EditBox* mMessageWidget;
|
MyGUI::EditBox* mMessageWidget;
|
||||||
int mFixedWidth;
|
|
||||||
int mBottomPadding;
|
int mBottomPadding;
|
||||||
int mNextBoxPadding;
|
int mNextBoxPadding;
|
||||||
};
|
};
|
||||||
|
|
|
@ -59,6 +59,15 @@ std::string getVampireHead(const std::string& race, bool female)
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
|
||||||
|
float SayAnimationValue::getValue() const
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getSoundManager()->sayDone(mReference))
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
// TODO: Use the loudness of the currently playing sound
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static NpcAnimation::PartBoneMap createPartListMap()
|
static NpcAnimation::PartBoneMap createPartListMap()
|
||||||
{
|
{
|
||||||
NpcAnimation::PartBoneMap result;
|
NpcAnimation::PartBoneMap result;
|
||||||
|
@ -115,6 +124,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v
|
||||||
{
|
{
|
||||||
mNpc = mPtr.get<ESM::NPC>()->mBase;
|
mNpc = mPtr.get<ESM::NPC>()->mBase;
|
||||||
|
|
||||||
|
mSayAnimationValue = Ogre::SharedPtr<SayAnimationValue>(new SayAnimationValue(mPtr));
|
||||||
|
|
||||||
for(size_t i = 0;i < ESM::PRT_Count;i++)
|
for(size_t i = 0;i < ESM::PRT_Count;i++)
|
||||||
{
|
{
|
||||||
mPartslots[i] = -1; //each slot is empty
|
mPartslots[i] = -1; //each slot is empty
|
||||||
|
@ -558,15 +569,18 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// type == ESM::PRT_Head should get an animation source based on the current output of
|
|
||||||
// the actor's 'say' sound (0 = silent, 1 = loud?).
|
|
||||||
// type == ESM::PRT_Weapon should get an animation source based on the current offset
|
// type == ESM::PRT_Weapon should get an animation source based on the current offset
|
||||||
// of the weapon attack animation (from its beginning, or start marker?)
|
// of the weapon attack animation (from its beginning, or start marker?)
|
||||||
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(mObjectParts[type].mControllers.begin());
|
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(mObjectParts[type].mControllers.begin());
|
||||||
for(;ctrl != mObjectParts[type].mControllers.end();ctrl++)
|
for(;ctrl != mObjectParts[type].mControllers.end();ctrl++)
|
||||||
{
|
{
|
||||||
if(ctrl->getSource().isNull())
|
if(ctrl->getSource().isNull())
|
||||||
|
{
|
||||||
ctrl->setSource(mNullAnimationValuePtr);
|
ctrl->setSource(mNullAnimationValuePtr);
|
||||||
|
|
||||||
|
if (type == ESM::PRT_Head)
|
||||||
|
ctrl->setSource(mSayAnimationValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -13,6 +13,18 @@ namespace ESM
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class SayAnimationValue : public Ogre::ControllerValue<Ogre::Real>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
MWWorld::Ptr mReference;
|
||||||
|
public:
|
||||||
|
SayAnimationValue(MWWorld::Ptr reference) : mReference(reference) {}
|
||||||
|
|
||||||
|
virtual Ogre::Real getValue() const;
|
||||||
|
virtual void setValue(Ogre::Real value)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
class NpcAnimation : public Animation, public MWWorld::InventoryStoreListener
|
class NpcAnimation : public Animation, public MWWorld::InventoryStoreListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -50,6 +62,8 @@ private:
|
||||||
|
|
||||||
Ogre::Vector3 mFirstPersonOffset;
|
Ogre::Vector3 mFirstPersonOffset;
|
||||||
|
|
||||||
|
Ogre::SharedPtr<SayAnimationValue> mSayAnimationValue;
|
||||||
|
|
||||||
void updateNpcBase();
|
void updateNpcBase();
|
||||||
|
|
||||||
NifOgre::ObjectList insertBoundedPart(const std::string &model, int group, const std::string &bonename,
|
NifOgre::ObjectList insertBoundedPart(const std::string &model, int group, const std::string &bonename,
|
||||||
|
|
|
@ -116,6 +116,7 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape
|
||||||
Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC;
|
Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC;
|
||||||
bool vertShadowBuffer = false;
|
bool vertShadowBuffer = false;
|
||||||
|
|
||||||
|
bool geomMorpherController = false;
|
||||||
if(!shape->controller.empty())
|
if(!shape->controller.empty())
|
||||||
{
|
{
|
||||||
Nif::ControllerPtr ctrl = shape->controller;
|
Nif::ControllerPtr ctrl = shape->controller;
|
||||||
|
@ -124,6 +125,7 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape
|
||||||
{
|
{
|
||||||
vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY;
|
vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY;
|
||||||
vertShadowBuffer = true;
|
vertShadowBuffer = true;
|
||||||
|
geomMorpherController = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while(!(ctrl=ctrl->next).empty());
|
} while(!(ctrl=ctrl->next).empty());
|
||||||
|
@ -347,6 +349,11 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape
|
||||||
if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest))
|
if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest))
|
||||||
mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest);
|
mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a dummy vertex animation track if there's a geom morpher controller
|
||||||
|
// This is required to make Ogre create the buffers we will use for software vertex animation
|
||||||
|
if (srcVerts.size() && geomMorpherController)
|
||||||
|
mesh->createAnimation("dummy", 0)->createVertexTrack(1, sub->vertexData, Ogre::VAT_MORPH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -385,12 +385,35 @@ public:
|
||||||
private:
|
private:
|
||||||
Ogre::SubEntity *mSubEntity;
|
Ogre::SubEntity *mSubEntity;
|
||||||
std::vector<Nif::NiMorphData::MorphData> mMorphs;
|
std::vector<Nif::NiMorphData::MorphData> mMorphs;
|
||||||
|
std::vector<float> mValues;
|
||||||
|
|
||||||
|
std::vector<Ogre::Vector3> mVertices;
|
||||||
|
|
||||||
|
static float interpKey(const Nif::FloatKeyList::VecType &keys, float time)
|
||||||
|
{
|
||||||
|
if(time <= keys.front().mTime)
|
||||||
|
return keys.front().mValue;
|
||||||
|
|
||||||
|
Nif::FloatKeyList::VecType::const_iterator iter(keys.begin()+1);
|
||||||
|
for(;iter != keys.end();iter++)
|
||||||
|
{
|
||||||
|
if(iter->mTime < time)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Nif::FloatKeyList::VecType::const_iterator last(iter-1);
|
||||||
|
float a = (time-last->mTime) / (iter->mTime-last->mTime);
|
||||||
|
return last->mValue + ((iter->mValue - last->mValue)*a);
|
||||||
|
}
|
||||||
|
return keys.back().mValue;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Value(Ogre::SubEntity *subent, const Nif::NiMorphData *data)
|
Value(Ogre::SubEntity *subent, const Nif::NiMorphData *data)
|
||||||
: mSubEntity(subent)
|
: mSubEntity(subent)
|
||||||
, mMorphs(data->mMorphs)
|
, mMorphs(data->mMorphs)
|
||||||
{ }
|
{
|
||||||
|
mValues.resize(mMorphs.size()-1, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
virtual Ogre::Real getValue() const
|
virtual Ogre::Real getValue() const
|
||||||
{
|
{
|
||||||
|
@ -398,9 +421,63 @@ public:
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setValue(Ogre::Real value)
|
virtual void setValue(Ogre::Real time)
|
||||||
{
|
{
|
||||||
// TODO: Implement
|
if (mMorphs.size() <= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if OGRE_DOUBLE_PRECISION
|
||||||
|
#error "This code needs to be rewritten for double precision mode"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Ogre::VertexData* data = mSubEntity->_getSoftwareVertexAnimVertexData();
|
||||||
|
|
||||||
|
const Ogre::VertexElement* posElem =
|
||||||
|
data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
|
||||||
|
|
||||||
|
Ogre::HardwareVertexBufferSharedPtr vbuf =
|
||||||
|
data->vertexBufferBinding->getBuffer(posElem->getSource());
|
||||||
|
|
||||||
|
bool needToUpdate = false;
|
||||||
|
int i=0;
|
||||||
|
for (std::vector<Nif::NiMorphData::MorphData>::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i)
|
||||||
|
{
|
||||||
|
float val = 0;
|
||||||
|
if (!it->mData.mKeys.empty())
|
||||||
|
val = interpKey(it->mData.mKeys, time);
|
||||||
|
val = std::max(0.f, std::min(1.f, val));
|
||||||
|
|
||||||
|
if (val != mValues[i])
|
||||||
|
needToUpdate = true;
|
||||||
|
mValues[i] = val;
|
||||||
|
}
|
||||||
|
if (!needToUpdate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// The first morph key always contains the original positions
|
||||||
|
mVertices = mMorphs[0].mVertices;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
for (std::vector<Nif::NiMorphData::MorphData>::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i)
|
||||||
|
{
|
||||||
|
float val = mValues[i];
|
||||||
|
|
||||||
|
if (it->mVertices.size() != mMorphs[0].mVertices.size())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (val != 0)
|
||||||
|
{
|
||||||
|
for (unsigned int v=0; v<mVertices.size(); ++v)
|
||||||
|
mVertices[v] += it->mVertices[v] * val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mVertices.size() * sizeof(float)*3 != vbuf->getSizeInBytes())
|
||||||
|
return;
|
||||||
|
|
||||||
|
vbuf->writeData(0, vbuf->getSizeInBytes(), &mVertices[0]);
|
||||||
|
|
||||||
|
mSubEntity->_markBuffersUsedForAnimation();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -480,11 +557,10 @@ class NIFObjectLoader
|
||||||
{
|
{
|
||||||
const Nif::NiGeomMorpherController *geom = static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr());
|
const Nif::NiGeomMorpherController *geom = static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr());
|
||||||
|
|
||||||
Ogre::SubEntity *subent = entity->getSubEntity(0);
|
|
||||||
Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ?
|
Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ?
|
||||||
Ogre::ControllerManager::getSingleton().getFrameTimeSource() :
|
Ogre::ControllerManager::getSingleton().getFrameTimeSource() :
|
||||||
Ogre::ControllerValueRealPtr());
|
Ogre::ControllerValueRealPtr());
|
||||||
Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value(subent, geom->data.getPtr()));
|
Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value(entity->getSubEntity(0), geom->data.getPtr()));
|
||||||
|
|
||||||
GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
|
GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
|
||||||
objectlist.mMaxControllerLength = std::max(function->mStopTime, objectlist.mMaxControllerLength);
|
objectlist.mMaxControllerLength = std::max(function->mStopTime, objectlist.mMaxControllerLength);
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<MyGUI type="Layout">
|
<MyGUI type="Layout">
|
||||||
<!--Widget type="Window" skin="MW_Dialog" layer="Windows" position="0 0 0 0" name="_Main">
|
<Widget type="VBox" skin="MW_Dialog" layer="Notification" position="0 0 0 0" name="_Main">
|
||||||
<Widget type="TextBox" skin="TextBox" position="4 4 4 4" name="message"/>
|
<Property key="Padding" value="10"/>
|
||||||
</Widget-->
|
<Property key="AutoResize" value="true"/>
|
||||||
<Widget type="Window" skin="MW_Dialog" layer="Notification" position="0 0 0 0" name="_Main">
|
|
||||||
<Widget type="EditBox" skin="MW_TextEditClient" position="5 -5 0 0" name="message" align="Left Top Stretch">
|
<Widget type="AutoSizedEditBox" skin="MW_TextEditClient" position="0 0 300 0" name="message" align="Left Top">
|
||||||
<Property key="FontName" value="Default"/>
|
<Property key="FontName" value="Default"/>
|
||||||
<Property key="TextAlign" value="Center"/>
|
<Property key="TextAlign" value="Center"/>
|
||||||
<Property key="TextColour" value="0.75 0.6 0.35"/>
|
<Property key="TextColour" value="0.75 0.6 0.35"/>
|
||||||
|
|
Loading…
Reference in a new issue