1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-22 10:23:53 +00:00
This commit is contained in:
greye 2012-07-25 20:29:46 +04:00
commit dd196b013c
23 changed files with 1742 additions and 3056 deletions

View file

@ -186,6 +186,9 @@ if (UNIX AND NOT APPLE)
find_package (Threads) find_package (Threads)
endif() endif()
# find boost without components so we can use Boost_VERSION
find_package(Boost REQUIRED)
set(BOOST_COMPONENTS system filesystem program_options thread) set(BOOST_COMPONENTS system filesystem program_options thread)
if (Boost_VERSION LESS 104900) if (Boost_VERSION LESS 104900)

View file

@ -56,11 +56,8 @@ void OMW::Engine::executeLocalScripts()
localScripts.setIgnore (MWWorld::Ptr()); localScripts.setIgnore (MWWorld::Ptr());
} }
void OMW::Engine::setAnimationVerbose(bool animverbose){ void OMW::Engine::setAnimationVerbose(bool animverbose)
if(animverbose){ {
NifOgre::NIFLoader::getSingletonPtr()->setOutputAnimFiles(true);
NifOgre::NIFLoader::getSingletonPtr()->setVerbosePath(mCfgMgr.getLogPath().string());
}
} }
bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)

View file

@ -122,15 +122,13 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store){
void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number){ void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number){
if(mAllActors.find(ptr) != mAllActors.end()) if(mAllActors.find(ptr) != mAllActors.end())
mAllActors[ptr]->startScript(groupName, mode, number); mAllActors[ptr]->playGroup(groupName, mode, number);
} }
void Actors::skipAnimation (const MWWorld::Ptr& ptr){ void Actors::skipAnimation (const MWWorld::Ptr& ptr){
if(mAllActors.find(ptr) != mAllActors.end()) if(mAllActors.find(ptr) != mAllActors.end())
mAllActors[ptr]->stopScript(); mAllActors[ptr]->skipAnim();
} }
void Actors::update (float duration){ void Actors::update (float duration){
for(std::map<MWWorld::Ptr, Animation*>::iterator iter = mAllActors.begin(); iter != mAllActors.end(); iter++) for(std::map<MWWorld::Ptr, Animation*>::iterator iter = mAllActors.begin(); iter != mAllActors.end(); iter++)
{ iter->second->runAnimation(duration);
(iter->second)->runAnimation(duration);
}
} }

View file

@ -5,498 +5,171 @@
#include <OgreEntity.h> #include <OgreEntity.h>
#include <OgreBone.h> #include <OgreBone.h>
#include <OgreSubMesh.h> #include <OgreSubMesh.h>
#include <OgreSceneManager.h>
namespace MWRender namespace MWRender
{ {
std::map<std::string, int> Animation::sUniqueIDs;
Animation::Animation(OEngine::Render::OgreRenderer& _rend) Animation::Animation(OEngine::Render::OgreRenderer& _rend)
: mInsert(NULL) : mInsert(NULL)
, mRend(_rend) , mRend(_rend)
, mVecRotPos() , mTime(0.0f)
, mTime(0.0f) , mSkipFrame(false)
, mStartTime(0.0f) {
, mStopTime(0.0f) }
, mAnimate(0)
, mRindexI() Animation::~Animation()
, mTindexI() {
, mShapeNumber(0) Ogre::SceneManager *sceneMgr = mInsert->getCreator();
, mShapeIndexI() for(size_t i = 0;i < mEntityList.mEntities.size();i++)
, mShapes(NULL) sceneMgr->destroyEntity(mEntityList.mEntities[i]);
, mTransformations(NULL) mEntityList.mEntities.clear();
, mTextmappings(NULL) }
, mBase(NULL)
struct checklow {
bool operator()(const char &a, const char &b) const
{ {
return ::tolower(a) == ::tolower(b);
} }
};
Animation::~Animation() bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times)
{
const std::string &start = groupname+": start";
const std::string &startloop = groupname+": loop start";
const std::string &stop = groupname+": stop";
const std::string &stoploop = groupname+": loop stop";
NifOgre::TextKeyMap::const_iterator iter;
for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++)
{ {
} if(times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f)
return true;
std::string Animation::getUniqueID(std::string mesh) std::string::const_iterator strpos = iter->second.begin();
{ std::string::const_iterator strend = iter->second.end();
int counter;
std::string copy = mesh; while(strpos != strend)
std::transform(copy.begin(), copy.end(), copy.begin(), ::tolower);
if(sUniqueIDs.find(copy) == sUniqueIDs.end())
{ {
counter = sUniqueIDs[copy] = 0; size_t strlen = strend-strpos;
} std::string::const_iterator striter;
else
{
sUniqueIDs[copy] = sUniqueIDs[copy] + 1;
counter = sUniqueIDs[copy];
}
std::stringstream out; if(start.size() <= strlen &&
((striter=std::mismatch(strpos, strend, start.begin(), checklow()).first) == strend ||
if(counter > 99 && counter < 1000) *striter == '\r' || *striter == '\n'))
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
if(groupname == "all")
{
mAnimate = loops;
mTime = mStartTime;
}
else if(mTextmappings)
{
std::string startName = groupname + ": loop start";
std::string stopName = groupname + ": loop stop";
bool first = false;
if(loops > 1)
{ {
startName = groupname + ": loop start"; times->mStart = iter->first;
stopName = groupname + ": loop stop"; times->mLoopStart = iter->first;
for(std::map<std::string, float>::iterator iter = mTextmappings->begin(); iter != mTextmappings->end(); iter++)
{
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)
{
mStartTime = iter->second;
mAnimate = loops;
mTime = mStartTime;
first = true;
}
if(current2 == stopName)
{
mStopTime = iter->second;
if(first)
break;
}
}
} }
if(!first) else if(startloop.size() <= strlen &&
((striter=std::mismatch(strpos, strend, startloop.begin(), checklow()).first) == strend ||
*striter == '\r' || *striter == '\n'))
{ {
startName = groupname + ": start"; times->mLoopStart = iter->first;
stopName = groupname + ": stop"; }
else if(stoploop.size() <= strlen &&
((striter=std::mismatch(strpos, strend, stoploop.begin(), checklow()).first) == strend ||
*striter == '\r' || *striter == '\n'))
{
times->mLoopStop = iter->first;
}
else if(stop.size() <= strlen &&
((striter=std::mismatch(strpos, strend, stop.begin(), checklow()).first) == strend ||
*striter == '\r' || *striter == '\n'))
{
times->mStop = iter->first;
if(times->mLoopStop < 0.0f)
times->mLoopStop = iter->first;
break;
}
for(std::map<std::string, float>::iterator iter = mTextmappings->begin(); iter != mTextmappings->end(); iter++) strpos = std::find(strpos+1, strend, '\n');
{ while(strpos != strend && *strpos == '\n')
strpos++;
}
}
std::string current = iter->first.substr(0, startName.size()); return (times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f);
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)
{ void Animation::playGroup(std::string groupname, int mode, int loops)
mStartTime = iter->second; {
mAnimate = loops; GroupTimes times;
mTime = mStartTime; times.mLoops = loops;
first = true;
} if(groupname == "all")
if(current2 == stopName) {
{ times.mStart = times.mLoopStart = 0.0f;
mStopTime = iter->second; times.mLoopStop = times.mStop = 0.0f;
if(first)
break; if(mEntityList.mSkelBase)
} {
} Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates();
Ogre::AnimationStateIterator as = aset->getAnimationStateIterator();
while(as.hasMoreElements())
{
Ogre::AnimationState *state = as.getNext();
times.mLoopStop = times.mStop = state->getLength();
break;
} }
} }
} }
else if(!findGroupTimes(groupname, &times))
void Animation::stopScript() throw std::runtime_error("Failed to find animation group "+groupname);
if(mode == 0 && mCurGroup.mLoops > 0)
mNextGroup = times;
else
{ {
mAnimate = 0; mCurGroup = times;
mNextGroup = GroupTimes();
mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart);
} }
}
void Animation::handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel)
void Animation::skipAnim()
{
mSkipFrame = true;
}
void Animation::runAnimation(float timepassed)
{
if(mCurGroup.mLoops > 0 && !mSkipFrame)
{ {
mShapeNumber = 0; mTime += timepassed;
if(mTime >= mCurGroup.mLoopStop)
if (allshapes == NULL || creaturemodel == NULL || skel == NULL)
return;
std::vector<Nif::NiTriShapeCopy>::iterator allshapesiter;
for(allshapesiter = allshapes->begin(); allshapesiter != allshapes->end(); allshapesiter++)
{ {
//std::map<unsigned short, PosAndRot> vecPosRot; if(mCurGroup.mLoops > 1)
Nif::NiTriShapeCopy& copy = *allshapesiter;
std::vector<Ogre::Vector3>* allvertices = &copy.vertices;
//std::set<unsigned int> vertices;
//std::set<unsigned int> normals;
//std::vector<Nif::NiSkinData::BoneInfoCopy> boneinfovector = copy.boneinfo;
std::map<int, std::vector<Nif::NiSkinData::IndividualWeight> >* verticesToChange = &copy.vertsToWeights;
//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));
std::vector<Ogre::Vector3> initialVertices = copy.morph.getInitialVertices();
//Each shape has multiple indices
if(initialVertices.size() )
{ {
if(copy.vertices.size() == initialVertices.size()) mCurGroup.mLoops--;
{ mTime = mTime - mCurGroup.mLoopStop + mCurGroup.mLoopStart;
//Create if it doesn't already exist
if(mShapeIndexI.size() == static_cast<std::size_t> (mShapeNumber))
{
std::vector<int> vec;
mShapeIndexI.push_back(vec);
}
if(mTime >= copy.morph.getStartTime() && mTime <= copy.morph.getStopTime())
{
float x;
for (unsigned int i = 0; i < copy.morph.getAdditionalVertices().size(); i++)
{
int j = 0;
if(mShapeIndexI[mShapeNumber].size() <= i)
mShapeIndexI[mShapeNumber].push_back(0);
if(timeIndex(mTime,copy.morph.getRelevantTimes()[i],(mShapeIndexI[mShapeNumber])[i], j, x))
{
int indexI = (mShapeIndexI[mShapeNumber])[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())
for (unsigned int v = 0; v < initialVertices.size(); v++)
initialVertices[v] += ((copy.morph.getAdditionalVertices()[i])[v]) * t;
}
}
allvertices = &initialVertices;
}
mShapeNumber++;
}
} }
else if(mTime >= mCurGroup.mStop)
if(verticesToChange->size() > 0)
{ {
if(mNextGroup.mLoops > 0)
for(std::map<int, std::vector<Nif::NiSkinData::IndividualWeight> >::iterator iter = verticesToChange->begin(); mTime = mTime - mCurGroup.mStop + mNextGroup.mStart;
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;
Ogre::Vector3 vecPos;
Ogre::Quaternion vecRot;
std::map<Nif::NiSkinData::BoneInfoCopy*, PosAndRot>::iterator result = mVecRotPos.find(boneinfocopy);
if(result == mVecRotPos.end())
{
bonePtr = skel->getBone(boneinfocopy->bonename);
vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans;
vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation;
PosAndRot both;
both.vecPos = vecPos;
both.vecRot = vecRot;
mVecRotPos[boneinfocopy] = both;
}
else
{
PosAndRot both = result->second;
vecPos = both.vecPos;
vecRot = both.vecRot;
}
Ogre::Vector3 absVertPos = (vecPos + vecRot * currentVertex) * inds[0].weight;
for(std::size_t i = 1; i < inds.size(); i++)
{
boneinfocopy = &(allshapesiter->boneinfo[inds[i].boneinfocopyindex]);
result = mVecRotPos.find(boneinfocopy);
if(result == mVecRotPos.end())
{
bonePtr = skel->getBone(boneinfocopy->bonename);
vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans;
vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation;
PosAndRot both;
both.vecPos = vecPos;
both.vecRot = vecRot;
mVecRotPos[boneinfocopy] = both;
}
else
{
PosAndRot both = result->second;
vecPos = both.vecPos;
vecRot = both.vecRot;
}
absVertPos += (vecPos + vecRot * currentVertex) * inds[i].weight;
}
Ogre::Real* addr = (pReal + 3 * verIndex);
*addr = absVertPos.x;
*(addr+1) = absVertPos.y;
*(addr+2) = absVertPos.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<std::string> boneSequence = copy.boneSequence;
Ogre::Vector3 transmult;
Ogre::Quaternion rotmult;
float scale;
if(boneSequence.size() > 0)
{
std::vector<std::string>::iterator boneSequenceIter = boneSequence.begin();
if(skel->hasBone(*boneSequenceIter))
{
Ogre::Bone *bonePtr = skel->getBone(*boneSequenceIter);
transmult = bonePtr->getPosition();
rotmult = bonePtr->getOrientation();
scale = bonePtr->getScale().x;
boneSequenceIter++;
for(; boneSequenceIter != boneSequence.end(); boneSequenceIter++)
{
if(skel->hasBone(*boneSequenceIter))
{
Ogre::Bone *bonePtr = skel->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 else
{ mTime = mCurGroup.mStop;
transmult = shapetrans; mCurGroup = mNextGroup;
rotmult = shaperot; mNextGroup = GroupTimes();
scale = shapescale;
}
// Computes C = B + AxC*scale
// final_vector = old_vector + old_rotation*new_vector*old_scale/
for(unsigned 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;
}*/
} }
vbuf->unlock();
} }
} if(mEntityList.mSkelBase)
bool Animation::timeIndex( float time, const std::vector<float> & times, int & i, int & j, float & x )
{
int count;
if ( (count = times.size()) > 0 )
{ {
if ( time <= times[0] ) Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates();
Ogre::AnimationStateIterator as = aset->getAnimationStateIterator();
while(as.hasMoreElements())
{ {
i = j = 0; Ogre::AnimationState *state = as.getNext();
x = 0.0; state->setTimePosition(mTime);
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;
}
void Animation::handleAnimationTransforms()
{
Ogre::SkeletonInstance* skel = mBase->getSkeleton();
Ogre::Bone* b = skel->getRootBone();
b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3)); //This is a trick
skel->_updateTransforms();
//skel->_notifyManualBonesDirty();
mBase->getAllAnimationStates()->_notifyDirty();
//mBase->_updateAnimation();
//mBase->_notifyMoved();
std::vector<Nif::NiKeyframeData>::iterator iter;
int slot = 0;
if(mTransformations)
{
for(iter = mTransformations->begin(); iter != mTransformations->end(); iter++)
{
if(mTime < iter->getStartTime() || mTime < mStartTime || mTime > iter->getStopTime())
{
slot++;
continue;
}
float x;
float x2;
const std::vector<Ogre::Quaternion> & quats = iter->getQuat();
const std::vector<float> & ttime = iter->gettTime();
const std::vector<float> & rtime = iter->getrTime();
int rindexJ = mRindexI[slot];
timeIndex(mTime, rtime, mRindexI[slot], rindexJ, x2);
int tindexJ = mTindexI[slot];
const std::vector<Ogre::Vector3> & translist1 = iter->getTranslist1();
timeIndex(mTime, ttime, mTindexI[slot], tindexJ, x);
Ogre::Vector3 t;
Ogre::Quaternion r;
bool bTrans = translist1.size() > 0;
bool bQuats = quats.size() > 0;
if(skel->hasBone(iter->getBonename()))
{
Ogre::Bone* bone = skel->getBone(iter->getBonename());
if(bTrans)
{
Ogre::Vector3 v1 = translist1[mTindexI[slot]];
Ogre::Vector3 v2 = translist1[tindexJ];
t = (v1 + (v2 - v1) * x);
bone->setPosition(t);
}
if(bQuats)
{
r = Ogre::Quaternion::Slerp(x2, quats[mRindexI[slot]], quats[rindexJ], true);
bone->setOrientation(r);
}
}
slot++;
}
skel->_updateTransforms();
mBase->getAllAnimationStates()->_notifyDirty();
}
} }
mSkipFrame = false;
}
} }

View file

@ -1,6 +1,9 @@
#ifndef _GAME_RENDER_ANIMATION_H #ifndef _GAME_RENDER_ANIMATION_H
#define _GAME_RENDER_ANIMATION_H #define _GAME_RENDER_ANIMATION_H
#include <vector>
#include <components/nifogre/ogre_nif_loader.hpp>
#include <openengine/ogre/renderer.hpp> #include <openengine/ogre/renderer.hpp>
#include "../mwworld/actiontalk.hpp" #include "../mwworld/actiontalk.hpp"
#include <components/nif/node.hpp> #include <components/nif/node.hpp>
@ -8,53 +11,47 @@
namespace MWRender{
struct PosAndRot{ namespace MWRender {
Ogre::Quaternion vecRot;
Ogre::Vector3 vecPos;
};
class Animation{ class Animation {
struct GroupTimes {
float mStart;
float mStop;
float mLoopStart;
float mLoopStop;
protected: size_t mLoops;
GroupTimes()
: mStart(-1.0f), mStop(-1.0f), mLoopStart(-1.0f), mLoopStop(-1.0f),
mLoops(0)
{ }
};
protected:
Ogre::SceneNode* mInsert; Ogre::SceneNode* mInsert;
OEngine::Render::OgreRenderer &mRend; OEngine::Render::OgreRenderer &mRend;
std::map<Nif::NiSkinData::BoneInfoCopy*, PosAndRot> mVecRotPos;
static std::map<std::string, int> sUniqueIDs;
float mTime; float mTime;
float mStartTime; GroupTimes mCurGroup;
float mStopTime; GroupTimes mNextGroup;
int mAnimate;
//Represents a rotation index for each bone
std::vector<int>mRindexI;
//Represents a translation index for each bone
std::vector<int>mTindexI;
//Only shapes with morphing data will use a shape number bool mSkipFrame;
int mShapeNumber;
std::vector<std::vector<int> > mShapeIndexI;
//Ogre::SkeletonInstance* skel; NifOgre::EntityList mEntityList;
std::vector<Nif::NiTriShapeCopy>* mShapes; //All the NiTriShapeData for a creature NifOgre::TextKeyMap mTextKeys;
std::vector<Nif::NiKeyframeData>* mTransformations; bool findGroupTimes(const std::string &groupname, GroupTimes *times);
std::map<std::string,float>* mTextmappings;
Ogre::Entity* mBase;
void handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel);
void handleAnimationTransforms();
bool timeIndex( float time, const std::vector<float> & times, int & i, int & j, float & x );
std::string getUniqueID(std::string mesh);
public: public:
Animation(OEngine::Render::OgreRenderer& _rend); Animation(OEngine::Render::OgreRenderer& _rend);
virtual void runAnimation(float timepassed) = 0; virtual ~Animation();
void startScript(std::string groupname, int mode, int loops);
void stopScript();
virtual ~Animation();
void playGroup(std::string groupname, int mode, int loops);
void skipAnim();
virtual void runAnimation(float timepassed);
}; };
} }
#endif #endif

View file

@ -14,7 +14,7 @@ namespace MWRender{
CreatureAnimation::~CreatureAnimation() CreatureAnimation::~CreatureAnimation()
{ {
} }
CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend): Animation(_rend) CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend): Animation(_rend)
{ {
@ -24,75 +24,54 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::O
assert (ref->base != NULL); assert (ref->base != NULL);
if(!ref->base->model.empty()) if(!ref->base->model.empty())
{ {
const std::string &mesh = "meshes\\" + ref->base->model; std::string mesh = "meshes\\" + ref->base->model;
std::string meshNumbered = mesh + getUniqueID(mesh) + ">|";
NifOgre::NIFLoader::load(meshNumbered);
mBase = mRend.getScene()->createEntity(meshNumbered);
mBase->setVisibilityFlags(RV_Actors);
bool transparent = false; mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, mesh);
for (unsigned int i=0; i < mBase->getNumSubEntities(); ++i) for(size_t i = 0;i < mEntityList.mEntities.size();i++)
{ {
Ogre::MaterialPtr mat = mBase->getSubEntity(i)->getMaterial(); Ogre::Entity *ent = mEntityList.mEntities[i];
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); ent->setVisibilityFlags(RV_Actors);
while (techIt.hasMoreElements())
{
Ogre::Technique* tech = techIt.getNext();
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
while (passIt.hasMoreElements())
{
Ogre::Pass* pass = passIt.getNext();
if (pass->getDepthWriteEnabled() == false) bool transparent = false;
transparent = true; for (unsigned int j=0;j < ent->getNumSubEntities() && !transparent; ++j)
{
Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial();
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
while (techIt.hasMoreElements() && !transparent)
{
Ogre::Technique* tech = techIt.getNext();
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
while (passIt.hasMoreElements() && !transparent)
{
Ogre::Pass* pass = passIt.getNext();
if (pass->getDepthWriteEnabled() == false)
transparent = true;
}
} }
} }
ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
} }
mBase->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
std::string meshZero = mesh + "0000>|"; if(mEntityList.mSkelBase)
if((mTransformations = (NIFLoader::getSingletonPtr())->getAnim(meshZero)))
{ {
for(std::size_t init = 0; init < mTransformations->size(); init++) Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates();
Ogre::AnimationStateIterator as = aset->getAnimationStateIterator();
while(as.hasMoreElements())
{ {
mRindexI.push_back(0); Ogre::AnimationState *state = as.getNext();
mTindexI.push_back(0); state->setEnabled(true);
state->setLoop(false);
} }
mStopTime = mTransformations->begin()->getStopTime();
mStartTime = mTransformations->begin()->getStartTime();
mShapes = (NIFLoader::getSingletonPtr())->getShapes(meshZero);
} }
mTextmappings = NIFLoader::getSingletonPtr()->getTextIndices(meshZero);
mInsert->attachObject(mBase);
} }
} }
void CreatureAnimation::runAnimation(float timepassed) void CreatureAnimation::runAnimation(float timepassed)
{ {
mVecRotPos.clear(); // Placeholder
if(mAnimate > 0)
{
//Add the amount of time passed to time
//Handle the animation transforms dependent on time Animation::runAnimation(timepassed);
//Handle the shapes dependent on animation transforms
mTime += timepassed;
if(mTime >= mStopTime)
{
mAnimate--;
//std::cout << "Stopping the animation\n";
if(mAnimate == 0)
mTime = mStopTime;
else
mTime = mStartTime + (mTime - mStopTime);
}
handleAnimationTransforms();
handleShapes(mShapes, mBase, mBase->getSkeleton());
}
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -14,42 +14,37 @@ class NpcAnimation: public Animation{
private: private:
MWWorld::InventoryStore& mInv; MWWorld::InventoryStore& mInv;
int mStateID; int mStateID;
//Free Parts
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> mChest;
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> mSkirt;
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> mLhand;
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> mRhand;
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> mTail;
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> mLFreeFoot;
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> mRFreeFoot;
int mPartslots[27]; //Each part slot is taken by clothing, armor, or is empty int mPartslots[27]; //Each part slot is taken by clothing, armor, or is empty
int mPartPriorities[27]; int mPartPriorities[27];
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> mZero;
//Bounded Parts //Bounded Parts
Ogre::Entity* lclavicle; NifOgre::EntityList lclavicle;
Ogre::Entity* rclavicle; NifOgre::EntityList rclavicle;
Ogre::Entity* rupperArm; NifOgre::EntityList rupperArm;
Ogre::Entity* lupperArm; NifOgre::EntityList lupperArm;
Ogre::Entity* rUpperLeg; NifOgre::EntityList rUpperLeg;
Ogre::Entity* lUpperLeg; NifOgre::EntityList lUpperLeg;
Ogre::Entity* lForearm; NifOgre::EntityList lForearm;
Ogre::Entity* rForearm; NifOgre::EntityList rForearm;
Ogre::Entity* lWrist; NifOgre::EntityList lWrist;
Ogre::Entity* rWrist; NifOgre::EntityList rWrist;
Ogre::Entity* rKnee; NifOgre::EntityList rKnee;
Ogre::Entity* lKnee; NifOgre::EntityList lKnee;
Ogre::Entity* neck; NifOgre::EntityList neck;
Ogre::Entity* rAnkle; NifOgre::EntityList rAnkle;
Ogre::Entity* lAnkle; NifOgre::EntityList lAnkle;
Ogre::Entity* groin; NifOgre::EntityList groin;
Ogre::Entity* lfoot; NifOgre::EntityList skirt;
Ogre::Entity* rfoot; NifOgre::EntityList lfoot;
Ogre::Entity* hair; NifOgre::EntityList rfoot;
Ogre::Entity* head; NifOgre::EntityList hair;
NifOgre::EntityList rHand;
NifOgre::EntityList lHand;
NifOgre::EntityList head;
NifOgre::EntityList chest;
NifOgre::EntityList tail;
Ogre::SceneNode* insert;
bool isBeast; bool isBeast;
bool isFemale; bool isFemale;
std::string headModel; std::string headModel;
@ -73,18 +68,17 @@ private:
public: public:
NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv);
virtual ~NpcAnimation(); virtual ~NpcAnimation();
Ogre::Entity* insertBoundedPart(const std::string &mesh, std::string bonename); NifOgre::EntityList insertBoundedPart(const std::string &mesh, const std::string &bonename);
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> insertFreePart(const std::string &mesh, const std::string& suffix);
void insertFootPart(int type, const std::string &mesh);
virtual void runAnimation(float timepassed); virtual void runAnimation(float timepassed);
void updateParts(); void updateParts();
void removeEntities(NifOgre::EntityList &entities);
void removeIndividualPart(int type); void removeIndividualPart(int type);
void reserveIndividualPart(int type, int group, int priority); void reserveIndividualPart(int type, int group, int priority);
bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh); bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh);
void removePartGroup(int group); void removePartGroup(int group);
void addPartGroup(int group, int priority, std::vector<ESM::PartReference>& parts); void addPartGroup(int group, int priority, std::vector<ESM::PartReference>& parts);
}; };
} }
#endif #endif

View file

@ -92,11 +92,16 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
Ogre::SceneNode* insert = ptr.getRefData().getBaseNode(); Ogre::SceneNode* insert = ptr.getRefData().getBaseNode();
assert(insert); assert(insert);
NifOgre::NIFLoader::load(mesh); Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL;
Ogre::Entity *ent = mRenderer.getScene()->createEntity(mesh); NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(insert, NULL, mesh);
for(size_t i = 0;i < entities.mEntities.size();i++)
{
Ogre::Vector3 extents = ent->getBoundingBox().getSize(); const Ogre::AxisAlignedBox &tmp = entities.mEntities[i]->getBoundingBox();
bounds.merge(Ogre::AxisAlignedBox(insert->_getDerivedPosition() + tmp.getMinimum(),
insert->_getDerivedPosition() + tmp.getMaximum())
);
}
Ogre::Vector3 extents = bounds.getSize();
extents *= insert->getScale(); extents *= insert->getScale();
float size = std::max(std::max(extents.x, extents.y), extents.z); float size = std::max(std::max(extents.x, extents.y), extents.z);
@ -108,42 +113,41 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
if (mBounds.find(ptr.getCell()) == mBounds.end()) if (mBounds.find(ptr.getCell()) == mBounds.end())
mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL;
Ogre::AxisAlignedBox bounds = ent->getBoundingBox();
bounds = Ogre::AxisAlignedBox(
insert->_getDerivedPosition() + bounds.getMinimum(),
insert->_getDerivedPosition() + bounds.getMaximum()
);
bounds.scale(insert->getScale());
mBounds[ptr.getCell()].merge(bounds); mBounds[ptr.getCell()].merge(bounds);
bool transparent = false; bool transparent = false;
for (unsigned int i=0; i<ent->getNumSubEntities(); ++i) for(size_t i = 0;i < entities.mEntities.size();i++)
{ {
Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial(); Ogre::Entity *ent = entities.mEntities[i];
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); for (unsigned int i=0; i<ent->getNumSubEntities(); ++i)
while (techIt.hasMoreElements())
{ {
Ogre::Technique* tech = techIt.getNext(); Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial();
Ogre::Technique::PassIterator passIt = tech->getPassIterator(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
while (passIt.hasMoreElements()) while (techIt.hasMoreElements())
{ {
Ogre::Pass* pass = passIt.getNext(); Ogre::Technique* tech = techIt.getNext();
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
while (passIt.hasMoreElements())
{
Ogre::Pass* pass = passIt.getNext();
if (pass->getDepthWriteEnabled() == false) if (pass->getDepthWriteEnabled() == false)
transparent = true; transparent = true;
}
} }
} }
} }
if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || transparent) if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || transparent)
{ {
insert->attachObject(ent); for(size_t i = 0;i < entities.mEntities.size();i++)
{
Ogre::Entity *ent = entities.mEntities[i];
ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0);
ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc);
ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
}
} }
else else
{ {
@ -183,15 +187,20 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
// - there will be too many batches. // - there will be too many batches.
sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500)); sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500));
sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale());
sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics); sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics);
sg->setCastShadows(true); sg->setCastShadows(true);
sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
mRenderer.getScene()->destroyEntity(ent); for(size_t i = 0;i < entities.mEntities.size();i++)
{
Ogre::Entity *ent = entities.mEntities[i];
insert->detachObject(ent);
sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale());
mRenderer.getScene()->destroyEntity(ent);
}
} }
} }

View file

@ -287,6 +287,8 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera)
void SkyManager::create() void SkyManager::create()
{ {
assert(!mCreated);
sh::Factory::getInstance().setSharedParameter ("cloudBlendFactor", sh::Factory::getInstance().setSharedParameter ("cloudBlendFactor",
sh::makeProperty<sh::FloatValue>(new sh::FloatValue(0))); sh::makeProperty<sh::FloatValue>(new sh::FloatValue(0)));
sh::Factory::getInstance().setSharedParameter ("cloudOpacity", sh::Factory::getInstance().setSharedParameter ("cloudOpacity",
@ -302,7 +304,7 @@ void SkyManager::create()
sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", ""); sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", "");
sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", ""); sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", "");
// Create overlay used for thunderstorm // Create light used for thunderstorm
mLightning = mSceneMgr->createLight(); mLightning = mSceneMgr->createLight();
mLightning->setType (Ogre::Light::LT_DIRECTIONAL); mLightning->setType (Ogre::Light::LT_DIRECTIONAL);
mLightning->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); mLightning->setDirection (Ogre::Vector3(0.3, -0.7, 0.3));
@ -324,52 +326,57 @@ void SkyManager::create()
mSunGlare->setVisibilityFlags(RV_NoReflection); mSunGlare->setVisibilityFlags(RV_NoReflection);
// Stars // Stars
MeshPtr mesh = NifOgre::NIFLoader::load("meshes\\sky_night_01.nif");
Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif");
night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1);
night1_ent->setVisibilityFlags(RV_Sky);
night1_ent->setCastShadows(false);
mAtmosphereNight = mRootNode->createChildSceneNode(); mAtmosphereNight = mRootNode->createChildSceneNode();
mAtmosphereNight->attachObject(night1_ent); NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, NULL, "meshes\\sky_night_01.nif");
for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++)
for (unsigned int i=0; i<night1_ent->getNumSubEntities(); ++i)
{ {
std::string matName = "openmw_stars_" + boost::lexical_cast<std::string>(i); Entity* night1_ent = entities.mEntities[i];
sh::MaterialInstance* m = sh::Factory::getInstance ().createMaterialInstance (matName, "openmw_stars"); night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1);
night1_ent->setVisibilityFlags(RV_Sky);
night1_ent->setCastShadows(false);
std::string textureName = sh::retrieveValue<sh::StringValue>( for (unsigned int j=0; j<night1_ent->getNumSubEntities(); ++j)
sh::Factory::getInstance().getMaterialInstance(night1_ent->getSubEntity (i)->getMaterialName ())->getProperty("diffuseMap"), NULL).get(); {
std::string matName = "openmw_stars_" + boost::lexical_cast<std::string>(matidx++);
sh::MaterialInstance* m = sh::Factory::getInstance().createMaterialInstance(matName, "openmw_stars");
m->setProperty ("texture", sh::makeProperty<sh::StringValue>(new sh::StringValue(textureName))); std::string textureName = sh::retrieveValue<sh::StringValue>(
sh::Factory::getInstance().getMaterialInstance(night1_ent->getSubEntity(j)->getMaterialName())->getProperty("diffuseMap"), NULL).get();
night1_ent->getSubEntity(i)->setMaterialName (matName); m->setProperty("texture", sh::makeProperty<sh::StringValue>(new sh::StringValue(textureName)));
night1_ent->getSubEntity(j)->setMaterialName(matName);
}
} }
// Atmosphere (day) // Atmosphere (day)
mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif");
Entity* atmosphere_ent = mSceneMgr->createEntity("meshes\\sky_atmosphere.nif");
atmosphere_ent->setCastShadows(false);
ModVertexAlpha(atmosphere_ent, 0);
atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly);
atmosphere_ent->setVisibilityFlags(RV_Sky);
mAtmosphereDay = mRootNode->createChildSceneNode(); mAtmosphereDay = mRootNode->createChildSceneNode();
mAtmosphereDay->attachObject(atmosphere_ent); entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, NULL, "meshes\\sky_atmosphere.nif");
atmosphere_ent->getSubEntity (0)->setMaterialName ("openmw_atmosphere"); for(size_t i = 0;i < entities.mEntities.size();i++)
{
Entity* atmosphere_ent = entities.mEntities[i];
atmosphere_ent->setCastShadows(false);
atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly);
atmosphere_ent->setVisibilityFlags(RV_Sky);
atmosphere_ent->getSubEntity (0)->setMaterialName ("openmw_atmosphere");
ModVertexAlpha(atmosphere_ent, 0);
}
// Clouds // Clouds
NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif");
Entity* clouds_ent = mSceneMgr->createEntity("meshes\\sky_clouds_01.nif");
clouds_ent->setVisibilityFlags(RV_Sky);
clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5);
SceneNode* clouds_node = mRootNode->createChildSceneNode(); SceneNode* clouds_node = mRootNode->createChildSceneNode();
clouds_node->attachObject(clouds_ent); entities = NifOgre::NIFLoader::createEntities(clouds_node, NULL, "meshes\\sky_clouds_01.nif");
clouds_ent->getSubEntity(0)->setMaterialName ("openmw_clouds"); for(size_t i = 0;i < entities.mEntities.size();i++)
clouds_ent->setCastShadows(false); {
Entity* clouds_ent = entities.mEntities[i];
clouds_ent->setVisibilityFlags(RV_Sky);
clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5);
clouds_ent->getSubEntity(0)->setMaterialName ("openmw_clouds");
clouds_ent->setCastShadows(false);
ModVertexAlpha(clouds_ent, 1); ModVertexAlpha(clouds_ent, 1);
}
mCreated = true; mCreated = true;
} }

View file

@ -1,6 +1,8 @@
#ifndef _GAME_RENDER_SKY_H #ifndef _GAME_RENDER_SKY_H
#define _GAME_RENDER_SKY_H #define _GAME_RENDER_SKY_H
#include <vector>
#include <OgreVector3.h> #include <OgreVector3.h>
#include <OgreString.h> #include <OgreString.h>
#include <OgreMaterial.h> #include <OgreMaterial.h>
@ -9,7 +11,7 @@
#include <extern/shiny/Main/Factory.hpp> #include <extern/shiny/Main/Factory.hpp>
#include "sky.hpp"
#include "../mwworld/weather.hpp" #include "../mwworld/weather.hpp"
namespace Ogre namespace Ogre

View file

@ -62,28 +62,13 @@ static bool fsstrict = false;
/// An OGRE Archive wrapping a BSAFile archive /// An OGRE Archive wrapping a BSAFile archive
class DirArchive: public Ogre::FileSystemArchive class DirArchive: public Ogre::FileSystemArchive
{ {
boost::filesystem::path currentdir; boost::filesystem::path currentdir;
std::map<std::string, std::vector<std::string>, ciLessBoost> m; std::map<std::string, std::vector<std::string>, ciLessBoost> m;
unsigned int cutoff; unsigned int cutoff;
bool findFile(const String& filename, std::string& copy) const bool findFile(const String& filename, std::string& copy) const
{ {
{ copy = filename;
String passed = filename;
if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':')
passed = filename.substr(0, filename.length() - 6);
else if(filename.at(filename.length() - 2) == '"')
passed = filename.substr(0, filename.length() - 9);
else if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<'
|| filename.at(filename.length() - 1) == '"' || filename.at(filename.length() - 1) == '>' || filename.at(filename.length() - 1) == ':'
|| filename.at(filename.length() - 1) == '|')
passed = filename.substr(0, filename.length() - 2);
copy = passed;
}
std::replace(copy.begin(), copy.end(), '\\', '/'); std::replace(copy.begin(), copy.end(), '\\', '/');
if(copy.at(0) == '/') if(copy.at(0) == '/')
@ -223,43 +208,20 @@ public:
// OGRE's fault. You should NOT expect an open() command not to // OGRE's fault. You should NOT expect an open() command not to
// have any side effects on the archive, and hence this function // have any side effects on the archive, and hence this function
// should not have been declared const in the first place. // should not have been declared const in the first place.
BSAFile *narc = (BSAFile*)&arc; BSAFile *narc = const_cast<BSAFile*>(&arc);
String passed = filename;
if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':')
passed = filename.substr(0, filename.length() - 6);
else if(filename.at(filename.length() - 2) == '"')
passed = filename.substr(0, filename.length() - 9);
else if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<'
|| filename.at(filename.length() - 1) == '"' || filename.at(filename.length() - 1) == '>' || filename.at(filename.length() - 1) == ':'
|| filename.at(filename.length() - 1) == '|')
passed = filename.substr(0, filename.length() - 2);
// Open the file // Open the file
return narc->getFile(passed.c_str()); return narc->getFile(filename.c_str());
} }
bool exists(const String& filename) { bool exists(const String& filename) {
return cexists(filename); return arc.exists(filename.c_str());
} }
// Check if the file exists.
bool cexists(const String& filename) const { bool cexists(const String& filename) const {
String passed = filename; return arc.exists(filename.c_str());
if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':') }
passed = filename.substr(0, filename.length() - 6);
else if(filename.at(filename.length() - 2) == '"')
passed = filename.substr(0, filename.length() - 9);
else if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<'
|| filename.at(filename.length() - 1) == '"' || filename.at(filename.length() - 1) == '>' || filename.at(filename.length() - 1) == ':'
|| filename.at(filename.length() - 1) == '|')
passed = filename.substr(0, filename.length() - 2);
return arc.exists(passed.c_str());
}
time_t getModifiedTime(const String&) { return 0; } time_t getModifiedTime(const String&) { return 0; }
// This is never called as far as I can see. // This is never called as far as I can see.

View file

@ -96,7 +96,9 @@ public:
class ShapeData : public Record class ShapeData : public Record
{ {
public: public:
std::vector<float> vertices, normals, colors, uvlist; std::vector<Ogre::Vector3> vertices, normals;
std::vector<Ogre::Vector4> colors;
std::vector< std::vector<Ogre::Vector2> > uvlist;
Ogre::Vector3 center; Ogre::Vector3 center;
float radius; float radius;
@ -105,16 +107,16 @@ public:
int verts = nif->getUShort(); int verts = nif->getUShort();
if(nif->getInt()) if(nif->getInt())
nif->getFloats(vertices, verts*3); nif->getVector3s(vertices, verts);
if(nif->getInt()) if(nif->getInt())
nif->getFloats(normals, verts*3); nif->getVector3s(normals, verts);
center = nif->getVector3(); center = nif->getVector3();
radius = nif->getFloat(); radius = nif->getFloat();
if(nif->getInt()) if(nif->getInt())
nif->getFloats(colors, verts*4); nif->getVector4s(colors, verts);
// Only the first 6 bits are used as a count. I think the rest are // Only the first 6 bits are used as a count. I think the rest are
// flags of some sort. // flags of some sort.
@ -122,7 +124,11 @@ public:
uvs &= 0x3f; uvs &= 0x3f;
if(nif->getInt()) if(nif->getInt())
nif->getFloats(uvlist, uvs*verts*2); {
uvlist.resize(uvs);
for(int i = 0;i < uvs;i++)
nif->getVector2s(uvlist[i], verts);
}
} }
}; };
@ -202,61 +208,34 @@ public:
class NiPosData : public Record class NiPosData : public Record
{ {
public: public:
Vector3KeyList mKeyList;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
int count = nif->getInt(); mKeyList.read(nif);
int type = nif->getInt();
if(type != 1 && type != 2)
nif->fail("Cannot handle NiPosData type");
// TODO: Could make structs of these. Seems to be identical to
// translation in NiKeyframeData.
for(int i=0; i<count; i++)
{
/*float time =*/ nif->getFloat();
nif->getVector3(); // This isn't really shared between type 1
// and type 2, most likely
if(type == 2)
{
nif->getVector3();
nif->getVector3();
}
}
} }
}; };
class NiUVData : public Record class NiUVData : public Record
{ {
public: public:
FloatKeyList mKeyList[4];
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
// TODO: This is claimed to be a "float animation key", which is for(int i = 0;i < 4;i++)
// also used in FloatData and KeyframeData. We could probably mKeyList[i].read(nif);
// reuse and refactor a lot of this if we actually use it at some
// point.
for(int i=0; i<2; i++)
{
int count = nif->getInt();
if(count)
{
nif->getInt(); // always 2
nif->skip(count * (sizeof(float) + 3*sizeof(float))); // Really one time float + one vector
}
}
// Always 0
nif->getInt();
nif->getInt();
} }
}; };
class NiFloatData : public Record class NiFloatData : public Record
{ {
public: public:
FloatKeyList mKeyList;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
int count = nif->getInt(); mKeyList.read(nif);
nif->getInt(); // always 2
nif->skip(count * (sizeof(float) + 3*sizeof(float))); // Really one time float + one vector
} }
}; };
@ -302,19 +281,11 @@ public:
class NiColorData : public Record class NiColorData : public Record
{ {
public: public:
struct ColorData Vector4KeyList mKeyList;
{
float time;
Ogre::Vector4 rgba;
};
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
int count = nif->getInt(); mKeyList.read(nif);
nif->getInt(); // always 1
// Skip the data
nif->skip(count * 5*sizeof(float));
} }
}; };
@ -361,12 +332,6 @@ public:
Ogre::Vector3 trans; // Translation Ogre::Vector3 trans; // Translation
float scale; // Probably scale (always 1) float scale; // Probably scale (always 1)
}; };
struct BoneTrafoCopy
{
Ogre::Quaternion rotation;
Ogre::Vector3 trans;
float scale;
};
struct VertWeight struct VertWeight
{ {
@ -374,26 +339,12 @@ public:
float weight; float weight;
}; };
struct BoneInfo struct BoneInfo
{ {
BoneTrafo trafo; BoneTrafo trafo;
Ogre::Vector4 unknown; Ogre::Vector4 unknown;
std::vector<VertWeight> weights; std::vector<VertWeight> weights;
}; };
struct BoneInfoCopy
{
std::string bonename;
unsigned short bonehandle;
BoneTrafoCopy trafo;
Ogre::Vector4 unknown;
//std::vector<VertWeight> weights;
};
struct IndividualWeight
{
float weight;
unsigned int boneinfocopyindex;
};
BoneTrafo trafo; BoneTrafo trafo;
std::vector<BoneInfo> bones; std::vector<BoneInfo> bones;
@ -428,378 +379,45 @@ public:
} }
}; };
class NiMorphData : public Record struct NiMorphData : public Record
{ {
float startTime; struct MorphData {
float stopTime; FloatKeyList mData;
std::vector<Ogre::Vector3> initialVertices; std::vector<Ogre::Vector3> mVertices;
std::vector<std::vector<float> > relevantTimes; };
std::vector<std::vector<Ogre::Vector3> > relevantData; std::vector<MorphData> mMorphs;
std::vector<std::vector<Ogre::Vector3> > additionalVertices;
public:
float getStartTime() const
{ return startTime; }
float getStopTime() const
{ return stopTime; }
void setStartTime(float time)
{ startTime = time; }
void setStopTime(float time)
{ stopTime = time; }
const std::vector<Ogre::Vector3>& getInitialVertices() const
{ return initialVertices; }
const std::vector<std::vector<Ogre::Vector3> >& getRelevantData() const
{ return relevantData; }
const std::vector<std::vector<float> >& getRelevantTimes() const
{ return relevantTimes; }
const std::vector<std::vector<Ogre::Vector3> >& getAdditionalVertices() const
{ return additionalVertices; }
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
int morphCount = nif->getInt(); int morphCount = nif->getInt();
int vertCount = nif->getInt(); int vertCount = nif->getInt();
nif->getChar(); nif->getChar();
int magic = nif->getInt();
/*int type =*/ nif->getInt();
for(int i = 0; i < vertCount; i++) mMorphs.resize(morphCount);
for(int i = 0;i < morphCount;i++)
{ {
float x = nif->getFloat(); mMorphs[i].mData.read(nif, true);
float y = nif->getFloat();
float z = nif->getFloat();
initialVertices.push_back(Ogre::Vector3(x, y, z));
}
for(int i=1; i<morphCount; i++) mMorphs[i].mVertices.resize(vertCount);
{ for(int j = 0;j < vertCount;j++)
magic = nif->getInt(); mMorphs[i].mVertices[j] = nif->getVector3();
/*type =*/ nif->getInt();
std::vector<Ogre::Vector3> current;
std::vector<float> currentTime;
for(int i = 0; i < magic; i++)
{
// Time, data, forward, backward tangents
float time = nif->getFloat();
float x = nif->getFloat();
float y = nif->getFloat();
float z = nif->getFloat();
current.push_back(Ogre::Vector3(x,y,z));
currentTime.push_back(time);
//nif->getFloatLen(4*magic);
}
if(magic)
{
relevantData.push_back(current);
relevantTimes.push_back(currentTime);
}
std::vector<Ogre::Vector3> verts;
for(int i = 0; i < vertCount; i++)
{
float x = nif->getFloat();
float y = nif->getFloat();
float z = nif->getFloat();
verts.push_back(Ogre::Vector3(x, y, z));
}
additionalVertices.push_back(verts);
} }
} }
}; };
class NiKeyframeData : public Record struct NiKeyframeData : public Record
{ {
std::string bonename; QuaternionKeyList mRotations;
//Rotations Vector3KeyList mTranslations;
std::vector<Ogre::Quaternion> quats; FloatKeyList mScales;
std::vector<Ogre::Vector3> tbc;
std::vector<float> rottime;
float startTime;
float stopTime;
int rtype;
//Translations
std::vector<Ogre::Vector3> translist1;
std::vector<Ogre::Vector3> translist2;
std::vector<Ogre::Vector3> translist3;
std::vector<Ogre::Vector3> transtbc;
std::vector<float> transtime;
int ttype;
//Scalings
std::vector<float> scalefactor;
std::vector<float> scaletime;
std::vector<float> forwards;
std::vector<float> backwards;
std::vector<Ogre::Vector3> tbcscale;
int stype;
public:
void clone(const NiKeyframeData &c)
{
quats = c.getQuat();
tbc = c.getrTbc();
rottime = c.getrTime();
//types
ttype = c.getTtype();
rtype = c.getRtype();
stype = c.getStype();
translist1 = c.getTranslist1();
translist2 = c.getTranslist2();
translist3 = c.getTranslist3();
transtime = c.gettTime();
bonename = c.getBonename();
}
void setBonename(std::string bone)
{ bonename = bone; }
void setStartTime(float start)
{ startTime = start; }
void setStopTime(float end)
{ stopTime = end; }
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
// Rotations first mRotations.read(nif);
int count = nif->getInt(); mTranslations.read(nif);
//std::vector<Ogre::Quaternion> quat(count); mScales.read(nif);
//std::vector<float> rottime(count);
if(count)
{
//TYPE1 LINEAR_KEY
//TYPE2 QUADRATIC_KEY
//TYPE3 TBC_KEY
//TYPE4 XYZ_ROTATION_KEY
//TYPE5 UNKNOWN_KEY
rtype = nif->getInt();
//std::cout << "Count: " << count << "Type: " << type << "\n";
if(rtype == 1)
{
//We need to actually read in these values instead of skipping them
//nif->skip(count*4*5); // time + quaternion
for (int i = 0; i < count; i++)
{
float time = nif->getFloat();
float w = nif->getFloat();
float x = nif->getFloat();
float y = nif->getFloat();
float z = nif->getFloat();
Ogre::Quaternion quat = Ogre::Quaternion(Ogre::Real(w), Ogre::Real(x), Ogre::Real(y), Ogre::Real(z));
quats.push_back(quat);
rottime.push_back(time);
//if(time == 0.0 || time > 355.5)
// std::cout <<"Time:" << time << "W:" << w <<"X:" << x << "Y:" << y << "Z:" << z << "\n";
}
}
else if(rtype == 3)
{
//Example - node 116 in base_anim.nif
for (int i = 0; i < count; i++)
{
float time = nif->getFloat();
float w = nif->getFloat();
float x = nif->getFloat();
float y = nif->getFloat();
float z = nif->getFloat();
float tbcx = nif->getFloat();
float tbcy = nif->getFloat();
float tbcz = nif->getFloat();
Ogre::Quaternion quat = Ogre::Quaternion(Ogre::Real(w), Ogre::Real(x), Ogre::Real(y), Ogre::Real(z));
Ogre::Vector3 vec = Ogre::Vector3(tbcx, tbcy, tbcz);
quats.push_back(quat);
rottime.push_back(time);
tbc.push_back(vec);
//if(time == 0.0 || time > 355.5)
// std::cout <<"Time:" << time << "W:" << w <<"X:" << x << "Y:" << y << "Z:" << z << "\n";
}
}
else if(rtype == 4)
{
for(int j=0;j<count;j++)
{
nif->getFloat(); // time
for(int i=0; i<3; i++)
{
int cnt = nif->getInt();
int type = nif->getInt();
if(type == 1)
nif->skip(cnt*4*2); // time + unknown
else if(type == 2)
nif->skip(cnt*4*4); // time + unknown vector
else
nif->fail("Unknown sub-rotation type");
}
}
}
else
nif->fail("Unknown rotation type in NiKeyframeData");
}
//first = false;
// Then translation
count = nif->getInt();
if(count)
{
ttype = nif->getInt();
//std::cout << "TransCount:" << count << " Type: " << type << "\n";
if(ttype == 1)
{
for(int i = 0; i < count; i++)
{
float time = nif->getFloat();
float x = nif->getFloat();
float y = nif->getFloat();
float z = nif->getFloat();
Ogre::Vector3 trans = Ogre::Vector3(x, y, z);
translist1.push_back(trans);
transtime.push_back(time);
}
//nif->getFloatLen(count*4); // time + translation
}
else if(ttype == 2)
{
//Example - node 116 in base_anim.nif
for(int i = 0; i < count; i++)
{
float time = nif->getFloat();
float x = nif->getFloat();
float y = nif->getFloat();
float z = nif->getFloat();
float x2 = nif->getFloat();
float y2 = nif->getFloat();
float z2 = nif->getFloat();
float x3 = nif->getFloat();
float y3 = nif->getFloat();
float z3 = nif->getFloat();
Ogre::Vector3 trans = Ogre::Vector3(x, y, z);
Ogre::Vector3 trans2 = Ogre::Vector3(x2, y2, z2);
Ogre::Vector3 trans3 = Ogre::Vector3(x3, y3, z3);
transtime.push_back(time);
translist1.push_back(trans);
translist2.push_back(trans2);
translist3.push_back(trans3);
}
//nif->getFloatLen(count*10); // trans1 + forward + backward
}
else if(ttype == 3)
{
for(int i = 0; i < count; i++)
{
float time = nif->getFloat();
float x = nif->getFloat();
float y = nif->getFloat();
float z = nif->getFloat();
float t = nif->getFloat();
float b = nif->getFloat();
float c = nif->getFloat();
Ogre::Vector3 trans = Ogre::Vector3(x, y, z);
Ogre::Vector3 tbc = Ogre::Vector3(t, b, c);
translist1.push_back(trans);
transtbc.push_back(tbc);
transtime.push_back(time);
}
//nif->getFloatLen(count*7); // trans1 + tension,bias,continuity
}
else nif->fail("Unknown translation type");
}
// Finally, scalings
count = nif->getInt();
if(count)
{
stype = nif->getInt();
for(int i = 0; i < count; i++)
{
//int size = 0;
if(stype >= 1 && stype < 4)
{
float time = nif->getFloat();
float scale = nif->getFloat();
scaletime.push_back(time);
scalefactor.push_back(scale);
//size = 2; // time+scale
}
else
nif->fail("Unknown scaling type");
if(stype == 2)
{
//size = 4; // 1 + forward + backward (floats)
float forward = nif->getFloat();
float backward = nif->getFloat();
forwards.push_back(forward);
backwards.push_back(backward);
}
else if(stype == 3)
{
//size = 5; // 1 + tbc
float tbcx = nif->getFloat();
float tbcy = nif->getFloat();
float tbcz = nif->getFloat();
Ogre::Vector3 vec = Ogre::Vector3(tbcx, tbcy, tbcz);
tbcscale.push_back(vec);
}
}
}
else
stype = 0;
} }
int getRtype() const
{ return rtype; }
int getStype() const
{ return stype; }
int getTtype() const
{ return ttype; }
float getStartTime() const
{ return startTime; }
float getStopTime() const
{ return stopTime; }
const std::vector<Ogre::Quaternion>& getQuat() const
{ return quats; }
const std::vector<Ogre::Vector3>& getrTbc() const
{ return tbc; }
const std::vector<float>& getrTime() const
{ return rottime; }
const std::vector<Ogre::Vector3>& getTranslist1() const
{ return translist1; }
const std::vector<Ogre::Vector3>& getTranslist2() const
{ return translist2; }
const std::vector<Ogre::Vector3>& getTranslist3() const
{ return translist3; }
const std::vector<float>& gettTime() const
{ return transtime; }
const std::vector<float>& getScalefactor() const
{ return scalefactor; }
const std::vector<float>& getForwards() const
{ return forwards; }
const std::vector<float>& getBackwards() const
{ return backwards; }
const std::vector<Ogre::Vector3>& getScaleTbc() const
{ return tbcscale; }
const std::vector<float>& getsTime() const
{ return scaletime; }
const std::string& getBonename() const
{ return bonename; }
}; };
} // Namespace } // Namespace

View file

@ -205,8 +205,22 @@ void NiSkinInstance::post(NIFFile *nif)
for(size_t i=0; i<bnum; i++) for(size_t i=0; i<bnum; i++)
{ {
if(!bones.has(i)) if(bones[i].empty())
nif->fail("Oops: Missing bone! Don't know how to handle this."); nif->fail("Oops: Missing bone! Don't know how to handle this.");
bones[i].makeBone(i, data->bones[i]); bones[i]->makeBone(i, data->bones[i]);
} }
} }
Ogre::Matrix4 Node::getLocalTransform()
{
Ogre::Matrix4 mat4(Ogre::Matrix4::IDENTITY);
mat4.makeTransform(trafo.pos, Ogre::Vector3(trafo.scale), Ogre::Quaternion(trafo.rotation));
return mat4;
}
Ogre::Matrix4 Node::getWorldTransform()
{
if(parent != NULL)
return parent->getWorldTransform() * getLocalTransform();
return getLocalTransform();
}

View file

@ -26,9 +26,12 @@
#include <OgreResourceGroupManager.h> #include <OgreResourceGroupManager.h>
#include <OgreDataStream.h> #include <OgreDataStream.h>
#include <OgreVector2.h>
#include <OgreVector3.h> #include <OgreVector3.h>
#include <OgreVector4.h> #include <OgreVector4.h>
#include <OgreMatrix3.h> #include <OgreMatrix3.h>
#include <OgreQuaternion.h>
#include <OgreStringConverter.h>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
@ -97,6 +100,12 @@ public:
throw std::runtime_error(err); throw std::runtime_error(err);
} }
void warn(const std::string &msg)
{
std::cerr<< "NIFFile Warning: "<<msg <<std::endl
<< "File: "<<filename <<std::endl;
}
/// Open a NIF stream. The name is used for error messages. /// Open a NIF stream. The name is used for error messages.
NIFFile(const std::string &name) NIFFile(const std::string &name)
: filename(name) : filename(name)
@ -133,6 +142,13 @@ public:
unsigned short getUShort() { return read_le16(); } unsigned short getUShort() { return read_le16(); }
int getInt() { return read_le32(); } int getInt() { return read_le32(); }
float getFloat() { return read_le32f(); } float getFloat() { return read_le32f(); }
Ogre::Vector2 getVector2()
{
float a[2];
for(size_t i = 0;i < 2;i++)
a[i] = getFloat();
return Ogre::Vector2(a);
}
Ogre::Vector3 getVector3() Ogre::Vector3 getVector3()
{ {
float a[3]; float a[3];
@ -157,13 +173,19 @@ public:
} }
return Ogre::Matrix3(a); return Ogre::Matrix3(a);
} }
Ogre::Quaternion getQuaternion()
{
float a[4];
for(size_t i = 0;i < 4;i++)
a[i] = getFloat();
return Ogre::Quaternion(a);
}
Transformation getTrafo() Transformation getTrafo()
{ {
Transformation t; Transformation t;
t.pos = getVector3(); t.pos = getVector3();
t.rotation = getMatrix3(); t.rotation = getMatrix3();
t.scale = getFloat(); t.scale = getFloat();
t.velocity = getVector3();
return t; return t;
} }
@ -193,7 +215,101 @@ public:
for(size_t i = 0;i < vec.size();i++) for(size_t i = 0;i < vec.size();i++)
vec[i] = getFloat(); vec[i] = getFloat();
} }
void getVector2s(std::vector<Ogre::Vector2> &vec, size_t size)
{
vec.resize(size);
for(size_t i = 0;i < vec.size();i++)
vec[i] = getVector2();
}
void getVector3s(std::vector<Ogre::Vector3> &vec, size_t size)
{
vec.resize(size);
for(size_t i = 0;i < vec.size();i++)
vec[i] = getVector3();
}
void getVector4s(std::vector<Ogre::Vector4> &vec, size_t size)
{
vec.resize(size);
for(size_t i = 0;i < vec.size();i++)
vec[i] = getVector4();
}
}; };
template<typename T>
struct KeyT {
float mTime;
T mValue;
T mForwardValue; // Only for Quadratic interpolation
T mBackwardValue; // Only for Quadratic interpolation
float mTension; // Only for TBC interpolation
float mBias; // Only for TBC interpolation
float mContinuity; // Only for TBC interpolation
};
typedef KeyT<float> FloatKey;
typedef KeyT<Ogre::Vector3> Vector3Key;
typedef KeyT<Ogre::Vector4> Vector4Key;
typedef KeyT<Ogre::Quaternion> QuaternionKey;
template<typename T, T (NIFFile::*getValue)()>
struct KeyListT {
typedef std::vector< KeyT<T> > VecType;
static const int sLinearInterpolation = 1;
static const int sQuadraticInterpolation = 2;
static const int sTBCInterpolation = 3;
int mInterpolationType;
VecType mKeys;
void read(NIFFile *nif, bool force=false)
{
size_t count = nif->getInt();
if(count == 0 && !force)
return;
mInterpolationType = nif->getInt();
mKeys.resize(count);
if(mInterpolationType == sLinearInterpolation)
{
for(size_t i = 0;i < count;i++)
{
KeyT<T> &key = mKeys[i];
key.mTime = nif->getFloat();
key.mValue = (nif->*getValue)();
}
}
else if(mInterpolationType == sQuadraticInterpolation)
{
for(size_t i = 0;i < count;i++)
{
KeyT<T> &key = mKeys[i];
key.mTime = nif->getFloat();
key.mValue = (nif->*getValue)();
key.mForwardValue = (nif->*getValue)();
key.mBackwardValue = (nif->*getValue)();
}
}
else if(mInterpolationType == sTBCInterpolation)
{
for(size_t i = 0;i < count;i++)
{
KeyT<T> &key = mKeys[i];
key.mTime = nif->getFloat();
key.mValue = (nif->*getValue)();
key.mTension = nif->getFloat();
key.mBias = nif->getFloat();
key.mContinuity = nif->getFloat();
}
}
else
nif->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType));
}
};
typedef KeyListT<float,&NIFFile::getFloat> FloatKeyList;
typedef KeyListT<Ogre::Vector3,&NIFFile::getVector3> Vector3KeyList;
typedef KeyListT<Ogre::Vector4,&NIFFile::getVector4> Vector4KeyList;
typedef KeyListT<Ogre::Quaternion,&NIFFile::getQuaternion> QuaternionKeyList;
} // Namespace } // Namespace
#endif #endif

View file

@ -37,21 +37,12 @@ struct Transformation
Ogre::Vector3 pos; Ogre::Vector3 pos;
Ogre::Matrix3 rotation; Ogre::Matrix3 rotation;
float scale; float scale;
Ogre::Vector3 velocity;
static const Transformation& getIdentity() static const Transformation& getIdentity()
{ {
static Transformation identity; static const Transformation identity = {
static bool iset = false; Ogre::Vector3::ZERO, Ogre::Matrix3::IDENTITY, 1.0f
if (!iset) };
{
identity.scale = 1.0f;
identity.rotation[0][0] = 1.0f;
identity.rotation[1][1] = 1.0f;
identity.rotation[2][2] = 1.0f;
iset = true;
}
return identity; return identity;
} }
}; };

View file

@ -24,6 +24,8 @@
#ifndef _NIF_NODE_H_ #ifndef _NIF_NODE_H_
#define _NIF_NODE_H_ #define _NIF_NODE_H_
#include <OgreMatrix4.h>
#include "controlled.hpp" #include "controlled.hpp"
#include "data.hpp" #include "data.hpp"
#include "property.hpp" #include "property.hpp"
@ -43,6 +45,7 @@ public:
// Node flags. Interpretation depends somewhat on the type of node. // Node flags. Interpretation depends somewhat on the type of node.
int flags; int flags;
Transformation trafo; Transformation trafo;
Ogre::Vector3 velocity; // Unused? Might be a run-time game state
PropertyList props; PropertyList props;
// Bounding box info // Bounding box info
@ -57,6 +60,7 @@ public:
flags = nif->getUShort(); flags = nif->getUShort();
trafo = nif->getTrafo(); trafo = nif->getTrafo();
velocity = nif->getVector3();
props.read(nif); props.read(nif);
hasBounds = !!nif->getInt(); hasBounds = !!nif->getInt();
@ -106,20 +110,9 @@ public:
boneTrafo = &bi.trafo; boneTrafo = &bi.trafo;
boneIndex = ind; boneIndex = ind;
} }
};
struct NiTriShapeCopy Ogre::Matrix4 getLocalTransform();
{ Ogre::Matrix4 getWorldTransform();
std::string sname;
std::vector<std::string> boneSequence;
Nif::NiSkinData::BoneTrafoCopy trafo;
//Ogre::Quaternion initialBoneRotation;
//Ogre::Vector3 initialBoneTranslation;
std::vector<Ogre::Vector3> vertices;
std::vector<Ogre::Vector3> normals;
std::vector<Nif::NiSkinData::BoneInfoCopy> boneinfo;
std::map<int, std::vector<Nif::NiSkinData::IndividualWeight> > vertsToWeights;
Nif::NiMorphData morph;
}; };
struct NiNode : Node struct NiNode : Node
@ -151,8 +144,8 @@ struct NiNode : Node
for(size_t i = 0;i < children.length();i++) for(size_t i = 0;i < children.length();i++)
{ {
// Why would a unique list of children contain empty refs? // Why would a unique list of children contain empty refs?
if(children.has(i)) if(!children[i].empty())
children[i].parent = this; children[i]->parent = this;
} }
} }
}; };
@ -182,28 +175,6 @@ struct NiTriShape : Node
data.post(nif); data.post(nif);
skin.post(nif); skin.post(nif);
} }
NiTriShapeCopy clone()
{
NiTriShapeCopy copy;
copy.sname = name;
float *ptr = (float*)&data->vertices[0];
float *ptrNormals = (float*)&data->normals[0];
int numVerts = data->vertices.size() / 3;
for(int i = 0; i < numVerts; i++)
{
float *current = (float*) (ptr + i * 3);
copy.vertices.push_back(Ogre::Vector3(*current, *(current + 1), *(current + 2)));
if(ptrNormals)
{
float *currentNormals = (float*) (ptrNormals + i * 3);
copy.normals.push_back(Ogre::Vector3(*currentNormals, *(currentNormals + 1), *(currentNormals + 2)));
}
}
return copy;
}
}; };
struct NiCamera : Node struct NiCamera : Node

View file

@ -24,7 +24,7 @@
#ifndef _NIF_RECORD_H_ #ifndef _NIF_RECORD_H_
#define _NIF_RECORD_H_ #define _NIF_RECORD_H_
#include <components/misc/slice_array.hpp> #include <string>
namespace Nif namespace Nif
{ {

View file

@ -71,18 +71,21 @@ public:
} }
/// Look up the actual object from the index /// Look up the actual object from the index
X* getPtr() X* getPtr() const
{ {
assert(ptr != NULL); assert(ptr != NULL);
return ptr; return ptr;
} }
X& get() { return *getPtr(); } X& get() const
{ return *getPtr(); }
/// Syntactic sugar /// Syntactic sugar
X* operator->() { return getPtr(); } X* operator->() const
{ return getPtr(); }
/// Pointers are allowed to be empty /// Pointers are allowed to be empty
bool empty() { return ptr == NULL; } bool empty() const
{ return ptr == NULL; }
}; };
/** A list of references to other records. These are read as a list, /** A list of references to other records. These are read as a list,
@ -111,17 +114,10 @@ public:
list[i].post(nif); list[i].post(nif);
} }
X& operator[](size_t index) const Ptr& operator[](size_t index) const
{ { return list.at(index); }
return list.at(index).get();
}
bool has(size_t index) size_t length() const
{
return !list.at(index).empty();
}
size_t length()
{ return list.size(); } { return list.size(); }
}; };

View file

@ -79,7 +79,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
// of the early stages of development. Right now we WANT to catch // of the early stages of development. Right now we WANT to catch
// every error as early and intrusively as possible, as it's most // every error as early and intrusively as possible, as it's most
// likely a sign of incomplete code rather than faulty input. // likely a sign of incomplete code rather than faulty input.
Nif::NIFFile nif(resourceName); Nif::NIFFile nif(resourceName.substr(0, resourceName.length()-7));
if (nif.numRecords() < 1) if (nif.numRecords() < 1)
{ {
warn("Found no records in NIF."); warn("Found no records in NIF.");
@ -138,9 +138,9 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node* node)
int n = list.length(); int n = list.length();
for (int i=0; i<n; i++) for (int i=0; i<n; i++)
{ {
if (list.has(i)) if (!list[i].empty())
{ {
if(hasRootCollisionNode(&list[i])) return true;; if(hasRootCollisionNode(list[i].getPtr())) return true;;
} }
} }
} }
@ -204,7 +204,6 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags,
// For both position and rotation we have that: // For both position and rotation we have that:
// final_vector = old_vector + old_rotation*new_vector*old_scale // final_vector = old_vector + old_rotation*new_vector*old_scale
final.pos = trafo->pos + trafo->rotation*final.pos*trafo->scale; final.pos = trafo->pos + trafo->rotation*final.pos*trafo->scale;
final.velocity = trafo->velocity + trafo->rotation*final.velocity*trafo->scale;
// Merge the rotations together // Merge the rotations together
final.rotation = trafo->rotation * final.rotation; final.rotation = trafo->rotation * final.rotation;
@ -222,9 +221,9 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags,
int n = list.length(); int n = list.length();
for (int i=0; i<n; i++) for (int i=0; i<n; i++)
{ {
if (list.has(i)) if (!list[i].empty())
{ {
handleNode(&list[i], flags,&node->trafo,hasCollisionNode,isCollisionNode,raycastingOnly); handleNode(list[i].getPtr(), flags,&node->trafo,hasCollisionNode,isCollisionNode,raycastingOnly);
} }
} }
} }
@ -239,8 +238,8 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags,
int n = list.length(); int n = list.length();
for (int i=0; i<n; i++) for (int i=0; i<n; i++)
{ {
if (list.has(i)) if (!list[i].empty())
handleNode(&list[i], flags,&node->trafo, hasCollisionNode,true,raycastingOnly); handleNode(list[i].getPtr(), flags,&node->trafo, hasCollisionNode,true,raycastingOnly);
} }
} }
} }
@ -272,19 +271,16 @@ void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape *shape, int flags
Nif::NiTriShapeData *data = shape->data.getPtr(); Nif::NiTriShapeData *data = shape->data.getPtr();
float* vertices = &data->vertices[0]; const std::vector<Ogre::Vector3> &vertices = data->vertices;
short* triangles = &data->triangles[0];
const Ogre::Matrix3 &rot = shape->trafo.rotation; const Ogre::Matrix3 &rot = shape->trafo.rotation;
const Ogre::Vector3 &pos = shape->trafo.pos; const Ogre::Vector3 &pos = shape->trafo.pos;
float scale = shape->trafo.scale; float scale = shape->trafo.scale * parentScale;
for(unsigned int i=0; i < data->triangles.size(); i = i+3) short* triangles = &data->triangles[0];
for(size_t i = 0;i < data->triangles.size();i+=3)
{ {
Ogre::Vector3 b1(vertices[triangles[i+0]*3]*parentScale,vertices[triangles[i+0]*3+1]*parentScale,vertices[triangles[i+0]*3+2]*parentScale); Ogre::Vector3 b1 = pos + rot*vertices[triangles[i+0]]*scale;
Ogre::Vector3 b2(vertices[triangles[i+1]*3]*parentScale,vertices[triangles[i+1]*3+1]*parentScale,vertices[triangles[i+1]*3+2]*parentScale); Ogre::Vector3 b2 = pos + rot*vertices[triangles[i+1]]*scale;
Ogre::Vector3 b3(vertices[triangles[i+2]*3]*parentScale,vertices[triangles[i+2]*3+1]*parentScale,vertices[triangles[i+2]*3+2]*parentScale); Ogre::Vector3 b3 = pos + rot*vertices[triangles[i+2]]*scale;
b1 = pos + rot*b1*scale;
b2 = pos + rot*b2*scale;
b3 = pos + rot*b3*scale;
mTriMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); mTriMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z));
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -26,7 +26,10 @@
#include <OgreResource.h> #include <OgreResource.h>
#include <OgreMesh.h> #include <OgreMesh.h>
#include <OgreSkeleton.h>
#include <vector>
#include <string>
#include <cassert> #include <cassert>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
@ -55,112 +58,47 @@ namespace Nif
namespace NifOgre namespace NifOgre
{ {
// FIXME: These should not be in NifOgre, it works agnostic of what model format is used
typedef std::map<float,std::string> TextKeyMap;
struct EntityList {
std::vector<Ogre::Entity*> mEntities;
Ogre::Entity *mSkelBase;
EntityList() : mSkelBase(0)
{ }
};
/** This holds a list of meshes along with the names of their parent nodes
*/
typedef std::vector< std::pair<Ogre::MeshPtr,std::string> > MeshPairList;
/** Manual resource loader for NIF meshes. This is the main class /** Manual resource loader for NIF meshes. This is the main class
responsible for translating the internal NIF mesh structure into responsible for translating the internal NIF mesh structure into
something Ogre can use. Later it will also handle the insertion of something Ogre can use.
collision meshes into Bullet / OgreBullet.
You have to insert meshes manually into Ogre like this: You have to insert meshes manually into Ogre like this:
NIFLoader::load("somemesh.nif"); NIFLoader::load("somemesh.nif");
Afterwards, you can use the mesh name "somemesh.nif" normally to This returns a list of meshes used by the model, as well as the names of
create entities and so on. The mesh isn't loaded from disk until their parent nodes (as they pertain to the skeleton, which is optionally
OGRE needs it for rendering. Thus the above load() command is not returned in the second argument if it exists).
very resource intensive, and can safely be done for a large number
of meshes at load time.
*/ */
class NIFLoader : Ogre::ManualResourceLoader class NIFLoader
{ {
public: static MeshPairList load(std::string name, std::string skelName, TextKeyMap *textkeys, const std::string &group);
static int numberOfMeshes;
static NIFLoader& getSingleton();
static NIFLoader* getSingletonPtr();
virtual void loadResource(Ogre::Resource *resource);
static Ogre::MeshPtr load(const std::string &name,
const std::string &group="General");
//void insertMeshInsideBase(Ogre::Mesh* mesh);
std::vector<Nif::NiKeyframeData>* getAnim(std::string name);
std::vector<Nif::NiTriShapeCopy>* getShapes(std::string name);
std::map<std::string, float>* getTextIndices(std::string name);
void setOutputAnimFiles(bool output);
void setVerbosePath(std::string path);
private:
NIFLoader() : resourceName(""), resourceGroup("General"), flip(false), mNormaliseNormals(false),
mFlipVertexWinding(false), mOutputAnimFiles(false), inTheSkeletonTree(false) {}
NIFLoader(NIFLoader& n) {}
void calculateTransform();
void warn(std::string msg);
void fail(std::string msg);
void handleNode( Nif::Node *node, int flags,
const Nif::Transformation *trafo, BoundsFinder &bounds, Ogre::Bone *parentBone, std::vector<std::string> boneSequence);
void handleNiTriShape(Nif::NiTriShape *shape, int flags, BoundsFinder &bounds, Nif::Transformation original, std::vector<std::string> boneSequence);
void createOgreSubMesh(Nif::NiTriShape *shape, const Ogre::String &material, std::list<Ogre::VertexBoneAssignment> &vertexBoneAssignments);
void createMaterial(const Ogre::String &name,
const Ogre::Vector3 &ambient,
const Ogre::Vector3 &diffuse,
const Ogre::Vector3 &specular,
const Ogre::Vector3 &emissive,
float glossiness, float alpha,
int alphaFlags, float alphaTest,
const Ogre::String &texName,
bool vertexColor);
void findRealTexture(Ogre::String &texName);
Ogre::String getUniqueName(const Ogre::String &input);
//returns the skeleton name of this mesh
std::string getSkeletonName()
{
return resourceName + ".skel";
}
std::string verbosePath;
std::string resourceName;
std::string resourceGroup;
Ogre::Matrix4 mTransform;
Ogre::AxisAlignedBox mBoundingBox;
bool flip;
bool mNormaliseNormals;
bool mFlipVertexWinding;
bool bNiTri;
bool mOutputAnimFiles;
std::multimap<std::string,std::string> MaterialMap;
// pointer to the ogre mesh which is currently build
Ogre::Mesh *mesh;
Ogre::SkeletonPtr mSkel;
Ogre::Vector3 vector;
std::vector<Nif::NiTriShapeCopy> shapes;
std::string name;
std::string triname;
std::vector<Nif::NiKeyframeData> allanim;
std::map<std::string,float> textmappings;
std::map<std::string,std::map<std::string,float>,ciLessBoost> alltextmappings;
std::map<std::string,std::vector<Nif::NiKeyframeData>,ciLessBoost> allanimmap;
std::map<std::string,std::vector<Nif::NiTriShapeCopy>,ciLessBoost> allshapesmap;
std::vector<Nif::NiKeyframeData> mAnim;
std::vector<Nif::NiTriShapeCopy> mS;
std::vector<Ogre::SubMesh*> needBoneAssignments;
bool inTheSkeletonTree;
public:
static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename,
Ogre::SceneNode *parentNode,
const std::string &name,
const std::string &group="General");
static EntityList createEntities(Ogre::SceneNode *parent,
TextKeyMap *textkeys,
const std::string &name,
const std::string &group="General");
}; };
} }

View file

@ -336,7 +336,7 @@ namespace Physic
char uniqueID[8]; char uniqueID[8];
sprintf( uniqueID, "%07.3f", scale ); sprintf( uniqueID, "%07.3f", scale );
std::string sid = uniqueID; std::string sid = uniqueID;
std::string outputstring = mesh + uniqueID + "\"|"; std::string outputstring = mesh + uniqueID;
//std::cout << "The string" << outputstring << "\n"; //std::cout << "The string" << outputstring << "\n";
//get the shape from the .nif //get the shape from the .nif