1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 11:19:55 +00:00
openmw-tes3mp/apps/openmw/mwrender/animation.cpp

500 lines
14 KiB
C++
Raw Normal View History

2011-12-12 04:42:39 +00:00
#include "animation.hpp"
2011-12-12 04:42:39 +00:00
namespace MWRender{
std::map<std::string, int> Animation::mUniqueIDs;
2011-12-27 00:23:46 +00:00
Animation::Animation(MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend)
: insert(NULL)
, mRend(_rend)
, mEnvironment(_env)
, vecRotPos()
, time(0.0f)
, startTime(0.0f)
, stopTime(0.0f)
, animate(0)
, rindexI()
, tindexI()
, shapeNumber(0)
, shapeIndexI()
, shapes(NULL)
, transformations(NULL)
, textmappings(NULL)
, base(NULL)
{
}
Animation::~Animation()
{
2011-12-12 04:42:39 +00:00
}
2011-12-27 00:23:46 +00:00
std::string Animation::getUniqueID(std::string mesh){
int counter;
2012-01-13 07:19:28 +00:00
std::string copy = mesh;
std::transform(copy.begin(), copy.end(), copy.begin(), ::tolower);
if(mUniqueIDs.find(copy) == mUniqueIDs.end()){
counter = mUniqueIDs[copy] = 0;
}
else{
mUniqueIDs[copy] = mUniqueIDs[copy] + 1;
counter = mUniqueIDs[copy];
}
2012-02-20 13:02:24 +00:00
std::stringstream out;
if(counter > 99 && counter < 1000)
out << "0";
else if(counter > 9)
out << "00";
else
out << "000";
out << counter;
return out.str();
}
void Animation::startScript(std::string groupname, int mode, int loops){
//If groupname is recognized set animate to true
//Set the start time and stop time
//How many times to loop
2011-12-27 00:23:46 +00:00
if(groupname == "all"){
animate = loops;
2011-12-27 00:23:46 +00:00
time = startTime;
}
2012-01-06 07:27:10 +00:00
else if(textmappings){
2012-02-20 13:02:24 +00:00
2012-01-07 03:52:15 +00:00
std::string startName = groupname + ": loop start";
std::string stopName = groupname + ": loop stop";
bool first = false;
if(loops > 1){
startName = groupname + ": loop start";
2012-01-07 03:52:15 +00:00
stopName = groupname + ": loop stop";
for(std::map<std::string, float>::iterator iter = textmappings->begin(); iter != textmappings->end(); iter++){
2012-02-20 13:02:24 +00:00
2012-01-07 03:52:15 +00:00
std::string current = iter->first.substr(0, startName.size());
std::transform(current.begin(), current.end(), current.begin(), ::tolower);
std::string current2 = iter->first.substr(0, stopName.size());
std::transform(current2.begin(), current2.end(), current2.begin(), ::tolower);
if(current == startName){
startTime = iter->second;
animate = loops;
time = startTime;
first = true;
}
if(current2 == stopName){
stopTime = iter->second;
if(first)
break;
}
}
}
2012-01-07 03:52:15 +00:00
if(!first){
startName = groupname + ": start";
stopName = groupname + ": stop";
2012-02-20 13:02:24 +00:00
2012-01-06 07:27:10 +00:00
for(std::map<std::string, float>::iterator iter = textmappings->begin(); iter != textmappings->end(); iter++){
2012-02-20 13:02:24 +00:00
2012-01-06 07:27:10 +00:00
std::string current = iter->first.substr(0, startName.size());
std::transform(current.begin(), current.end(), current.begin(), ::tolower);
std::string current2 = iter->first.substr(0, stopName.size());
std::transform(current2.begin(), current2.end(), current2.begin(), ::tolower);
if(current == startName){
startTime = iter->second;
animate = loops;
time = startTime;
first = true;
}
if(current2 == stopName){
stopTime = iter->second;
if(first)
break;
}
}
2012-01-07 03:52:15 +00:00
}
2012-02-20 13:02:24 +00:00
2012-01-06 07:27:10 +00:00
}
2012-02-20 13:02:24 +00:00
}
void Animation::stopScript(){
animate = 0;
}
2011-12-15 05:33:10 +00:00
void Animation::handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel){
shapeNumber = 0;
2012-02-20 13:02:24 +00:00
Fix for segfault when doing 'coc "seyda neen"'. This is a fix for segfault: ==8683== Process terminating with default action of signal 11 (SIGSEGV) ==8683== Access not within mapped region at address 0x0 ==8683== at 0x59DFE4: MWRender::Animation::handleShapes(std::vector<Nif::NiTriShapeCopy, std::allocator<Nif::NiTriShapeCopy> >*, Ogre::Entity*, Ogre::SkeletonInstance*) (animation.cpp:503) ==8683== by 0x5A4ECE: MWRender::Actors::update(float) (actors.cpp:134) ==8683== by 0x5937A9: MWRender::RenderingManager::update(float) (renderingmanager.cpp:168) ==8683== by 0x629AD6: MWWorld::World::update(float) (world.cpp:705) ==8683== by 0x68B022: OMW::Engine::frameRenderingQueued(Ogre::FrameEvent const&) (engine.cpp:157) ==8683== by 0x51F9574: Ogre::Root::_fireFrameRenderingQueued(Ogre::FrameEvent&) (in /usr/lib/libOgreMain.so.1.8.0) ==8683== by 0x51F964F: Ogre::Root::_fireFrameRenderingQueued() (in /usr/lib/libOgreMain.so.1.8.0) ==8683== by 0x51F9681: Ogre::Root::_updateAllRenderTargets() (in /usr/lib/libOgreMain.so.1.8.0) ==8683== by 0x51F98CF: Ogre::Root::renderOneFrame() (in /usr/lib/libOgreMain.so.1.8.0) ==8683== by 0x51F990C: Ogre::Root::startRendering() (in /usr/lib/libOgreMain.so.1.8.0) ==8683== by 0x68A669: OMW::Engine::go() (engine.cpp:408) ==8683== by 0x51CECB: main (main.cpp:254) ==8683== If you believe this happened as a result of a stack ==8683== overflow in your program's main thread (unlikely but ==8683== possible), you can try to increase the size of the ==8683== main thread stack using the --main-stacksize= flag. ==8683== The main thread stack size used in this run was 8388608. when doing 'coc "seyda neen"' when animations are enabled (Animation::animate member variable is set to 1).
2012-03-31 19:34:40 +00:00
if (allshapes == NULL || creaturemodel == NULL || skel == NULL)
{
return;
}
2011-12-15 05:33:10 +00:00
std::vector<Nif::NiTriShapeCopy>::iterator allshapesiter;
for(allshapesiter = allshapes->begin(); allshapesiter != allshapes->end(); allshapesiter++)
2012-02-20 13:02:24 +00:00
2011-12-28 22:34:47 +00:00
{
//std::map<unsigned short, PosAndRot> vecPosRot;
2012-02-20 13:02:24 +00:00
2011-12-27 00:23:46 +00:00
Nif::NiTriShapeCopy& copy = *allshapesiter;
std::vector<Ogre::Vector3>* allvertices = &copy.vertices;
2011-12-15 05:33:10 +00:00
//std::set<unsigned int> vertices;
2012-01-02 01:51:26 +00:00
//std::set<unsigned int> normals;
//std::vector<Nif::NiSkinData::BoneInfoCopy> boneinfovector = copy.boneinfo;
2012-02-20 13:02:24 +00:00
std::map<int, std::vector<Nif::NiSkinData::IndividualWeight> >* verticesToChange = &copy.vertsToWeights;
2011-12-15 05:33:10 +00:00
//std::cout << "Name " << copy.sname << "\n";
Ogre::HardwareVertexBufferSharedPtr vbuf = creaturemodel->getMesh()->getSubMesh(copy.sname)->vertexData->vertexBufferBinding->getBuffer(0);
Ogre::Real* pReal = static_cast<Ogre::Real*>(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
2012-02-20 13:02:24 +00:00
2011-12-15 05:33:10 +00:00
std::vector<Ogre::Vector3> initialVertices = copy.morph.getInitialVertices();
//Each shape has multiple indices
if(initialVertices.size() )
{
if(copy.vertices.size() == initialVertices.size())
{
//Create if it doesn't already exist
2012-02-20 13:02:24 +00:00
if(shapeIndexI.size() == static_cast<std::size_t> (shapeNumber))
2011-12-15 05:33:10 +00:00
{
std::vector<int> vec;
shapeIndexI.push_back(vec);
}
if(time >= copy.morph.getStartTime() && time <= copy.morph.getStopTime()){
float x;
2012-01-06 02:45:17 +00:00
for (unsigned int i = 0; i < copy.morph.getAdditionalVertices().size(); i++){
2011-12-15 05:33:10 +00:00
int j = 0;
if(shapeIndexI[shapeNumber].size() <= i)
shapeIndexI[shapeNumber].push_back(0);
if(timeIndex(time,copy.morph.getRelevantTimes()[i],(shapeIndexI[shapeNumber])[i], j, x)){
int indexI = (shapeIndexI[shapeNumber])[i];
std::vector<Ogre::Vector3> relevantData = (copy.morph.getRelevantData()[i]);
float v1 = relevantData[indexI].x;
float v2 = relevantData[j].x;
float t = v1 + (v2 - v1) * x;
if ( t < 0 ) t = 0;
if ( t > 1 ) t = 1;
if( t != 0 && initialVertices.size() == copy.morph.getAdditionalVertices()[i].size())
{
2012-01-06 02:45:17 +00:00
for (unsigned int v = 0; v < initialVertices.size(); v++){
2011-12-15 05:33:10 +00:00
initialVertices[v] += ((copy.morph.getAdditionalVertices()[i])[v]) * t;
}
}
}
2012-02-20 13:02:24 +00:00
2011-12-15 05:33:10 +00:00
}
2012-02-20 13:02:24 +00:00
allvertices = &initialVertices;
2011-12-15 05:33:10 +00:00
}
shapeNumber++;
}
}
if(verticesToChange->size() > 0){
2012-02-20 13:02:24 +00:00
for(std::map<int, std::vector<Nif::NiSkinData::IndividualWeight> >::iterator iter = verticesToChange->begin();
iter != verticesToChange->end(); iter++)
{
std::vector<Nif::NiSkinData::IndividualWeight> inds = iter->second;
int verIndex = iter->first;
Ogre::Vector3 currentVertex = (*allvertices)[verIndex];
Nif::NiSkinData::BoneInfoCopy* boneinfocopy = &(allshapesiter->boneinfo[inds[0].boneinfocopyindex]);
Ogre::Bone *bonePtr = 0;
2012-02-20 13:02:24 +00:00
2012-01-29 05:42:55 +00:00
Ogre::Vector3 vecPos;
2012-02-20 13:02:24 +00:00
Ogre::Quaternion vecRot;
std::map<Nif::NiSkinData::BoneInfoCopy*, PosAndRot>::iterator result = vecRotPos.find(boneinfocopy);
2012-02-20 13:02:24 +00:00
if(result == vecRotPos.end()){
bonePtr = skel->getBone(boneinfocopy->bonename);
2012-02-20 13:02:24 +00:00
vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans;
vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation;
2012-02-20 13:02:24 +00:00
PosAndRot both;
both.vecPos = vecPos;
both.vecRot = vecRot;
vecRotPos[boneinfocopy] = both;
2012-02-20 13:02:24 +00:00
}
else{
PosAndRot both = result->second;
vecPos = both.vecPos;
vecRot = both.vecRot;
}
Ogre::Vector3 absVertPos = (vecPos + vecRot * currentVertex) * inds[0].weight;
2012-02-20 13:02:24 +00:00
2012-02-19 22:59:50 +00:00
for(std::size_t i = 1; i < inds.size(); i++){
boneinfocopy = &(allshapesiter->boneinfo[inds[i].boneinfocopyindex]);
result = vecRotPos.find(boneinfocopy);
2012-02-20 13:02:24 +00:00
if(result == vecRotPos.end()){
bonePtr = skel->getBone(boneinfocopy->bonename);
vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans;
vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation;
2012-02-20 13:02:24 +00:00
PosAndRot both;
both.vecPos = vecPos;
both.vecRot = vecRot;
vecRotPos[boneinfocopy] = both;
2012-02-20 13:02:24 +00:00
}
else{
PosAndRot both = result->second;
vecPos = both.vecPos;
vecRot = both.vecRot;
}
2012-02-20 13:02:24 +00:00
absVertPos += (vecPos + vecRot * currentVertex) * inds[i].weight;
2012-02-20 13:02:24 +00:00
}
Ogre::Real* addr = (pReal + 3 * verIndex);
*addr = absVertPos.x;
*(addr+1) = absVertPos.y;
*(addr+2) = absVertPos.z;
2012-02-20 13:02:24 +00:00
}
2012-02-20 13:02:24 +00:00
}
2011-12-15 05:33:10 +00:00
else
{
//Ogre::Bone *bonePtr = creaturemodel->getSkeleton()->getBone(copy.bonename);
Ogre::Quaternion shaperot = copy.trafo.rotation;
Ogre::Vector3 shapetrans = copy.trafo.trans;
float shapescale = copy.trafo.scale;
std::vector<std::string> boneSequence = copy.boneSequence;
2012-02-20 13:02:24 +00:00
2011-12-15 05:33:10 +00:00
Ogre::Vector3 transmult;
Ogre::Quaternion rotmult;
float scale;
if(boneSequence.size() > 0){
std::vector<std::string>::iterator boneSequenceIter = boneSequence.begin();
if(skel->hasBone(*boneSequenceIter)){
2011-12-27 00:23:46 +00:00
Ogre::Bone *bonePtr = skel->getBone(*boneSequenceIter);
2012-02-20 13:02:24 +00:00
2011-12-15 05:33:10 +00:00
transmult = bonePtr->getPosition();
rotmult = bonePtr->getOrientation();
scale = bonePtr->getScale().x;
boneSequenceIter++;
2011-12-15 05:33:10 +00:00
for(; boneSequenceIter != boneSequence.end(); boneSequenceIter++)
{
if(creaturemodel->getSkeleton()->hasBone(*boneSequenceIter)){
Ogre::Bone *bonePtr = creaturemodel->getSkeleton()->getBone(*boneSequenceIter);
// Computes C = B + AxC*scale
transmult = transmult + rotmult * bonePtr->getPosition();
rotmult = rotmult * bonePtr->getOrientation();
scale = scale * bonePtr->getScale().x;
}
//std::cout << "Bone:" << *boneSequenceIter << " ";
}
transmult = transmult + rotmult * shapetrans;
rotmult = rotmult * shaperot;
scale = shapescale * scale;
//std::cout << "Position: " << transmult << "Rotation: " << rotmult << "\n";
}
}
2011-12-15 05:33:10 +00:00
else
{
transmult = shapetrans;
rotmult = shaperot;
scale = shapescale;
}
2012-02-20 13:02:24 +00:00
2011-12-15 05:33:10 +00:00
// Computes C = B + AxC*scale
// final_vector = old_vector + old_rotation*new_vector*old_scale/
2012-02-20 13:02:24 +00:00
for(unsigned int i = 0; i < allvertices->size(); i++){
Ogre::Vector3 current = transmult + rotmult * (*allvertices)[i];
2011-12-15 05:33:10 +00:00
Ogre::Real* addr = pReal + i * 3;
*addr = current.x;
*(addr+1) = current.y;
*(addr + 2) = current.z;
2012-01-02 01:51:26 +00:00
}/*
2011-12-15 05:33:10 +00:00
for(int i = 0; i < allnormals.size(); i++){
Ogre::Vector3 current =rotmult * allnormals[i];
Ogre::Real* addr = pRealNormal + i * 3;
*addr = current.x;
*(addr+1) = current.y;
*(addr + 2) = current.z;
2012-01-02 01:51:26 +00:00
}*/
2011-12-15 05:33:10 +00:00
}
2011-12-28 22:34:47 +00:00
vbuf->unlock();
2012-02-20 13:02:24 +00:00
2011-12-28 22:34:47 +00:00
}
2011-12-15 05:33:10 +00:00
}
2012-03-06 23:28:41 +00:00
bool Animation::timeIndex( float time, const std::vector<float> & times, int & i, int & j, float & x ){
2011-12-15 05:33:10 +00:00
int count;
if ( (count = times.size()) > 0 )
{
if ( time <= times[0] )
{
i = j = 0;
x = 0.0;
return true;
}
if ( time >= times[count - 1] )
{
i = j = count - 1;
x = 0.0;
return true;
}
2012-02-20 13:02:24 +00:00
2011-12-15 05:33:10 +00:00
if ( i < 0 || i >= count )
i = 0;
2012-02-20 13:02:24 +00:00
2011-12-15 05:33:10 +00:00
float tI = times[i];
if ( time > tI )
{
j = i + 1;
float tJ;
while ( time >= ( tJ = times[j]) )
{
i = j++;
tI = tJ;
}
x = ( time - tI ) / ( tJ - tI );
return true;
}
else if ( time < tI )
{
j = i - 1;
float tJ;
while ( time <= ( tJ = times[j] ) )
{
i = j--;
tI = tJ;
}
x = ( time - tI ) / ( tJ - tI );
return true;
}
else
{
j = i;
x = 0.0;
return true;
}
}
else
return false;
2011-12-18 08:18:26 +00:00
}
2011-12-28 03:35:22 +00:00
void Animation::handleAnimationTransforms(){
2012-02-27 02:27:54 +00:00
2011-12-28 03:35:22 +00:00
Ogre::SkeletonInstance* skel = base->getSkeleton();
2012-02-20 13:02:24 +00:00
2011-12-27 05:20:14 +00:00
Ogre::Bone* b = skel->getRootBone();
2012-01-06 02:45:17 +00:00
b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3)); //This is a trick
2012-02-20 13:02:24 +00:00
2011-12-27 05:20:14 +00:00
skel->_updateTransforms();
2012-01-13 05:48:52 +00:00
//skel->_notifyManualBonesDirty();
2011-12-27 05:20:14 +00:00
2011-12-28 03:35:22 +00:00
base->getAllAnimationStates()->_notifyDirty();
2012-01-13 05:48:52 +00:00
//base->_updateAnimation();
2012-01-29 05:42:55 +00:00
//base->_notifyMoved();
2011-12-28 03:35:22 +00:00
2012-04-08 02:02:20 +00:00
2011-12-18 08:18:26 +00:00
2011-12-18 08:18:26 +00:00
std::vector<Nif::NiKeyframeData>::iterator iter;
int slot = 0;
if(transformations){
for(iter = transformations->begin(); iter != transformations->end(); iter++){
if(time < iter->getStartTime() || time < startTime || time > iter->getStopTime())
{
2011-12-27 05:20:14 +00:00
slot++;
2012-02-20 13:02:24 +00:00
continue;
2011-12-18 08:18:26 +00:00
}
2011-12-28 03:35:22 +00:00
float x;
2011-12-18 08:18:26 +00:00
float x2;
2012-02-20 13:02:24 +00:00
2012-03-06 23:28:41 +00:00
const std::vector<Ogre::Quaternion> & quats = iter->getQuat();
2011-12-18 08:18:26 +00:00
2012-03-06 23:28:41 +00:00
const std::vector<float> & ttime = iter->gettTime();
2012-02-20 13:02:24 +00:00
2012-03-06 23:28:41 +00:00
const std::vector<float> & rtime = iter->getrTime();
2012-02-27 02:27:54 +00:00
int rindexJ = rindexI[slot];
2011-12-18 08:18:26 +00:00
timeIndex(time, rtime, rindexI[slot], rindexJ, x2);
2012-02-27 02:27:54 +00:00
int tindexJ = tindexI[slot];
2011-12-18 08:18:26 +00:00
2012-03-06 23:28:41 +00:00
const std::vector<Ogre::Vector3> & translist1 = iter->getTranslist1();
2011-12-18 08:18:26 +00:00
timeIndex(time, ttime, tindexI[slot], tindexJ, x);
2011-12-28 03:35:22 +00:00
Ogre::Vector3 t;
Ogre::Quaternion r;
2012-02-20 13:02:24 +00:00
2011-12-28 03:35:22 +00:00
bool bTrans = translist1.size() > 0;
2012-02-20 13:02:24 +00:00
2011-12-28 03:35:22 +00:00
bool bQuats = quats.size() > 0;
2011-12-28 03:35:22 +00:00
if(skel->hasBone(iter->getBonename())){
Ogre::Bone* bone = skel->getBone(iter->getBonename());
if(bTrans){
Ogre::Vector3 v1 = translist1[tindexI[slot]];
Ogre::Vector3 v2 = translist1[tindexJ];
t = (v1 + (v2 - v1) * x);
2011-12-28 03:35:22 +00:00
bone->setPosition(t);
}
if(bQuats){
r = Ogre::Quaternion::Slerp(x2, quats[rindexI[slot]], quats[rindexJ], true);
2011-12-28 03:35:22 +00:00
bone->setOrientation(r);
}
2012-01-05 00:47:06 +00:00
2012-02-20 13:02:24 +00:00
2012-02-20 13:02:24 +00:00
}
2012-02-20 13:02:24 +00:00
2011-12-18 08:18:26 +00:00
slot++;
}
skel->_updateTransforms();
base->getAllAnimationStates()->_notifyDirty();
2011-12-18 08:18:26 +00:00
}
2011-12-15 05:33:10 +00:00
}
2012-01-10 07:00:04 +00:00
2012-02-20 13:02:24 +00:00
}