From d51dfebde1c24805bdf69d76161baff2c279abfa Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Thu, 15 Dec 2011 00:33:10 -0500 Subject: [PATCH] NPCs fully rendered --- apps/openmw/mwrender/actors.cpp | 1 + apps/openmw/mwrender/actors.hpp | 2 +- apps/openmw/mwrender/animation.cpp | 296 +++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 3 + apps/openmw/mwrender/creatureanimation.cpp | 15 ++ apps/openmw/mwrender/npcanimation.cpp | 30 ++- components/nifogre/ogre_nif_loader.cpp | 3 + 7 files changed, 344 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index d3493bf4a..7454261f0 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -59,6 +59,7 @@ void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){ void Actors::insertCreature (const MWWorld::Ptr& ptr){ insertBegin(ptr, true, true); CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr, mEnvironment, mRend); + //mAllActors.insert(std::pair(ptr,anim)); mAllActors.push_back(anim); //mAllActors.push_back(&anim); } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index afd6e9ae6..011180f19 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -23,7 +23,7 @@ namespace MWRender{ std::map mCellSceneNodes; Ogre::SceneNode* mMwRoot; MWWorld::Environment& mEnvironment; - std::list mAllActors; + std::list mAllActors; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 067fb8f2a..857798e8c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -4,4 +4,300 @@ namespace MWRender{ Animation::~Animation(){ base = 0; } + void Animation::handleShapes(std::vector* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel){ + shapeNumber = 0; + std::vector::iterator allshapesiter; + for(allshapesiter = allshapes->begin(); allshapesiter != allshapes->end(); allshapesiter++) + { + + Nif::NiTriShapeCopy copy = *allshapesiter; + std::vector allvertices = copy.vertices; + std::vector allnormals = copy.normals; + + + + std::map vertices; + std::map normals; + std::vector boneinfovector = copy.boneinfo; + + //std::cout << "Name " << copy.sname << "\n"; + Ogre::HardwareVertexBufferSharedPtr vbuf = creaturemodel->getMesh()->getSubMesh(copy.sname)->vertexData->vertexBufferBinding->getBuffer(0); + Ogre::Real* pReal = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL)); + Ogre::HardwareVertexBufferSharedPtr vbufNormal = creaturemodel->getMesh()->getSubMesh(copy.sname)->vertexData->vertexBufferBinding->getBuffer(1); + Ogre::Real* pRealNormal = static_cast(vbufNormal->lock(Ogre::HardwareBuffer::HBL_NORMAL)); + + std::vector 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 + if(shapeIndexI.size() == shapeNumber) + { + std::vector vec; + shapeIndexI.push_back(vec); + } + if(time >= copy.morph.getStartTime() && time <= copy.morph.getStopTime()){ + float x; + for (int i = 0; i < copy.morph.getAdditionalVertices().size(); i++){ + 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 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()) + { + for (int v = 0; v < initialVertices.size(); v++){ + initialVertices[v] += ((copy.morph.getAdditionalVertices()[i])[v]) * t; + } + } + + } + + + + } + //After everything, write everything out + + /* + for(int i = 0; i < initialVertices.size(); i++){ + Ogre::Vector3 current = initialVertices[i]; + Ogre::Real* addr = pReal + i * 3; + *addr = current.x; + *(addr+1) = current.y; + *(addr + 2) = current.z; + + }*/ + allvertices = initialVertices; + } + shapeNumber++; + } + } + + + if(boneinfovector.size() > 0){ + + + for (int i = 0; i < boneinfovector.size(); i++) + { + Nif::NiSkinData::BoneInfoCopy boneinfo = boneinfovector[i]; + if(skel->hasBone(boneinfo.bonename)){ + Ogre::Bone *bonePtr = skel->getBone(boneinfo.bonename); + Ogre::Vector3 vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfo.trafo.trans; + Ogre::Quaternion vecRot = bonePtr->_getDerivedOrientation() * boneinfo.trafo.rotation; + //std::cout << "Bone" << bonePtr->getName() << "\n"; + for (unsigned int j=0; j < boneinfo.weights.size(); j++) + { + unsigned int verIndex = boneinfo.weights[j].vertex; + if(vertices.find(verIndex) == vertices.end()) + { + Ogre::Vector3 absVertPos = vecPos + vecRot * allvertices[verIndex]; + absVertPos = absVertPos * boneinfo.weights[j].weight; + vertices[verIndex] = true; + Ogre::Real* addr = (pReal + 3 * verIndex); + *addr = absVertPos.x; + *(addr+1) = absVertPos.y; + *(addr+2) = absVertPos.z; + + //std::cout << "Vertex" << vertices[verIndex] << "\n"; + } + else + { + + Ogre::Vector3 absVertPos = vecPos + vecRot * allvertices[verIndex]; + absVertPos = absVertPos * boneinfo.weights[j].weight; + Ogre::Vector3 old = Ogre::Vector3(pReal + 3 * verIndex); + absVertPos = absVertPos + old; + Ogre::Real* addr = (pReal + 3 * verIndex); + *addr = absVertPos.x; + *(addr+1) = absVertPos.y; + *(addr+2) = absVertPos.z; + //std::cout << "Vertex" << verIndex << "Weight: " << boneinfo.weights[i].weight << "was seen twice\n"; + + } + + if(normals.find(verIndex) == normals.end()) + { + Ogre::Vector3 absNormalsPos = vecRot * allnormals[verIndex]; + absNormalsPos = absNormalsPos * boneinfo.weights[j].weight; + normals[verIndex] = true; + Ogre::Real* addr = (pRealNormal + 3 * verIndex); + *addr = absNormalsPos.x; + *(addr+1) = absNormalsPos.y; + *(addr+2) = absNormalsPos.z; + } + else + { + Ogre::Vector3 absNormalsPos = vecRot * allnormals[verIndex]; + absNormalsPos = absNormalsPos * boneinfo.weights[j].weight; + Ogre::Vector3 old = Ogre::Vector3(pRealNormal + 3 * verIndex); + absNormalsPos = absNormalsPos + old; + + Ogre::Real* addr = (pRealNormal + 3 * verIndex); + *addr = absNormalsPos.x; + *(addr+1) = absNormalsPos.y; + *(addr+2) = absNormalsPos.z; + + } + + } + } + + + } + + + } + 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 boneSequence = copy.boneSequence; + std::vector::iterator boneSequenceIter = boneSequence.begin(); + Ogre::Vector3 transmult; + Ogre::Quaternion rotmult; + float scale; + if(creaturemodel->getSkeleton()->hasBone(*boneSequenceIter)){ + Ogre::Bone *bonePtr = creaturemodel->getSkeleton()->getBone(*boneSequenceIter); + + + + + transmult = bonePtr->getPosition(); + rotmult = bonePtr->getOrientation(); + scale = bonePtr->getScale().x; + boneSequenceIter++; + 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"; + } + else + { + transmult = shapetrans; + rotmult = shaperot; + scale = shapescale; + } + + + + + // Computes C = B + AxC*scale + // final_vector = old_vector + old_rotation*new_vector*old_scale/ + + for(int i = 0; i < allvertices.size(); i++){ + Ogre::Vector3 current = transmult + rotmult * allvertices[i]; + Ogre::Real* addr = pReal + i * 3; + *addr = current.x; + *(addr+1) = current.y; + *(addr + 2) = current.z; + + } + 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; + + } + + } + + } + + + for(allshapesiter = allshapes->begin(); allshapesiter != allshapes->end(); allshapesiter++) + { + Nif::NiTriShapeCopy copy = *allshapesiter; + Ogre::HardwareVertexBufferSharedPtr vbuf = creaturemodel->getMesh()->getSubMesh(copy.sname)->vertexData->vertexBufferBinding->getBuffer(0); + + Ogre::HardwareVertexBufferSharedPtr vbufNormal = creaturemodel->getMesh()->getSubMesh(copy.sname)->vertexData->vertexBufferBinding->getBuffer(1); + vbuf->unlock(); + vbufNormal->unlock(); + } + + + + } + bool Animation::timeIndex( float time, std::vector times, int & i, int & j, float & x ){ + 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; + } + + if ( i < 0 || i >= count ) + i = 0; + + 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; + +} } \ No newline at end of file diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 111e2d0c7..31910b814 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -6,6 +6,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" #include "../mwworld/environment.hpp" +#include namespace MWRender{ @@ -34,8 +35,10 @@ class Animation{ std::vector* transformations; std::map textmappings; Ogre::Entity* base; + void handleShapes(std::vector* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel); public: Animation(MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend): mRend(_rend), mEnvironment(_env){}; + bool timeIndex( float time, std::vector times, int & i, int & j, float & x ); ~Animation(); }; diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 66bc4d4d9..fac54db64 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -21,6 +21,21 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environme NifOgre::NIFLoader::load(mesh); base = mRend.getScene()->createEntity(mesh); + + if(transformations = (NIFLoader::getSingletonPtr())->getAnim(mesh)){ + + for(int init = 0; init < transformations->size(); init++){ + rindexI.push_back(0); + //a.rindexJ.push_back(0); + tindexI.push_back(0); + //a.tindexJ.push_back(0); + } + loop = false; + skel = base->getSkeleton(); + stopTime = transformations->begin()->getStopTime(); + //a.startTime = NIFLoader::getSingletonPtr()->getTime(item.smodel, "IdleSneak: Start"); + startTime = transformations->end()->getStartTime(); + } insert->attachObject(base); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index bd60a548e..17cb639ce 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -56,14 +56,21 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O base = mRend.getScene()->createEntity(smodel); - /* - transformations = &(NIFLoader::getSingletonPtr())->getAnim(smodel); + + if(transformations = (NIFLoader::getSingletonPtr())->getAnim(smodel)){ + for(int init = 0; init < transformations->size(); init++){ rindexI.push_back(0); //a.rindexJ.push_back(0); tindexI.push_back(0); //a.tindexJ.push_back(0); - }*/ + } + loop = false; + skel = base->getSkeleton(); + stopTime = transformations->begin()->getStopTime(); + //a.startTime = NIFLoader::getSingletonPtr()->getTime(item.smodel, "IdleSneak: Start"); + startTime = transformations->end()->getStartTime(); + } insert->attachObject(base); std::string headModel = "meshes\\" + @@ -173,6 +180,17 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O insertFreePart("meshes\\" + handr->model + "|?", insert); } + if (handl){ + insertFreePart("meshes\\" + handl->model + "|>", insert); + + } + if(tail){ + insertFreePart("meshes\\" + tail->model + "|*", insert); + } + if(feet){ + insertFreePart("meshes\\" + feet->model + "|<", insert); + insertFreePart("meshes\\" + feet->model + "|:", insert); + } } Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::string bonename){ @@ -187,9 +205,11 @@ void NpcAnimation::insertFreePart(const std::string &mesh, Ogre::SceneNode* inse Entity* ent = mRend.getScene()->createEntity(mesh); insert->attachObject(ent); entityparts.push_back(ent); - //std::vector shapes = (NIFLoader::getSingletonPtr())->getShapes(mesh); std::vector* shapes = ((NIFLoader::getSingletonPtr())->getShapes(mesh)); - shapeparts.push_back(shapes); + if(shapes){ + shapeparts.push_back(shapes); + handleShapes(shapes, ent, skel); + } } diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 26b1111a1..21dea31b1 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1121,6 +1121,8 @@ void NIFLoader::handleNode(Nif::Node *node, int flags, void NIFLoader::loadResource(Resource *resource) { + allanim.clear(); + shapes.clear(); mBoundingBox.setNull(); mesh = 0; mSkel.setNull(); @@ -1276,6 +1278,7 @@ void NIFLoader::loadResource(Resource *resource) if(!mSkel.isNull() && shapes.size() > 0 && addAnim) { allshapesmap[name] = shapes; + } if(flip){