Merge branch 'master' into shadersystem

Conflicts:
	components/nifogre/ogre_nif_loader.cpp
actorid
scrawl 13 years ago
commit 7d5b94709d

@ -20,6 +20,12 @@ set (OPENMW_VERSION_RELEASE 0)
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
# Debug suffix for plugins
set(DEBUG_SUFFIX "")
if (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
set(DEBUG_SUFFIX "_d")
endif()
# doxygen main page
configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp")

@ -39,7 +39,7 @@ add_openmw_dir (mwscript
locals scriptmanager compilercontext interpretercontext cellextensions miscextensions
guiextensions soundextensions skyextensions statsextensions containerextensions
aiextensions controlextensions extensions globalscripts ref dialogueextensions
animationextensions
animationextensions transformationextensions
)
add_openmw_dir (mwsound

@ -178,6 +178,10 @@ namespace MWBase
virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;
virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z) = 0;
virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)
const = 0;
///< Convert cell numbers to position.

@ -125,10 +125,14 @@ namespace MWClass
void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
{
MWWorld::LiveCellRef<ESM::NPC> *ref =
ptr.get<ESM::NPC>();
assert (ref->base != NULL);
std::string headID = ref->base->head;
std::string bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4);
bool beast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_";
@ -136,7 +140,8 @@ namespace MWClass
std::string smodel = "meshes\\base_anim.nif";
if(beast)
smodel = "meshes\\base_animkna.nif";
physics.insertActorPhysics(ptr, smodel);
physics.insertActorPhysics(ptr, smodel);
MWBase::Environment::get().getMechanicsManager()->addActor (ptr);
}
@ -342,4 +347,11 @@ namespace MWClass
return weight;
}
void Npc::adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const
{
y = 0;
x = 0;
std::cout << "dfdfdfdfnzdofnmqsldgnmqskdhblqkdbv lqksdf";
}
}

@ -76,6 +76,8 @@ namespace MWClass
///< Returns total weight of objects inside this object (including modifications from magic
/// effects). Throws an exception, if the object can't hold other objects.
virtual void adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const;
static void registerSelf();
};
}

@ -706,7 +706,7 @@ namespace MWDialogue
}
return false;
}
catch (const Compiler::SourceException& error)
catch (const Compiler::SourceException& /* error */)
{
// error has already been reported via error handler
}

@ -286,7 +286,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender)
{
object = MWBase::Environment::get().getWorld()->getPtrViaHandle(handle);
}
catch (std::exception& e)
catch (std::exception& /* e */)
{
return;
}

@ -310,6 +310,9 @@ namespace MWGui
&& (type != typeid(ESM::Potion).name()))
return;
if (MWWorld::Class::get(object).getName(object) == "") // objects without name presented to user can never be picked up
return;
// sound
std::string sound = MWWorld::Class::get(object).getUpSoundId(object);
MWBase::Environment::get().getSoundManager()->playSound(sound, 1, 1);

@ -12,6 +12,10 @@ namespace MWGui
{
}
ReferenceInterface::~ReferenceInterface()
{
}
void ReferenceInterface::checkReferenceAvailable()
{
if (mPtr.isEmpty())

@ -13,6 +13,7 @@ namespace MWGui
{
public:
ReferenceInterface();
virtual ~ReferenceInterface();
void checkReferenceAvailable(); ///< closes the window, if the MW-reference has become unavailable

@ -81,7 +81,7 @@ void ToolTips::onFrame(float frameDuration)
{
mFocusObject = MWBase::Environment::get().getWorld()->getPtrViaHandle(handle);
}
catch (std::exception& e)
catch (std::exception /* & e */)
{
return;
}

@ -165,4 +165,9 @@ op 0x2000160: SetFlee
op 0x2000161: SetFlee, explicit reference
op 0x2000162: SetAlarm
op 0x2000163: SetAlarm, explicit reference
opcodes 0x2000164-0x3ffffff unused
op 0x2000164: SetScale
op 0x2000165: SetScale, explicit reference
op 0x2000166: SetAngle
op 0x2000167: SetAngle, explicit reference
opcodes 0x2000168-0x3ffffff unused

@ -15,6 +15,7 @@
#include "controlextensions.hpp"
#include "dialogueextensions.hpp"
#include "animationextensions.hpp"
#include "transformationextensions.hpp"
namespace MWScript
{
@ -31,6 +32,7 @@ namespace MWScript
Control::registerExtensions (extensions);
Dialogue::registerExtensions (extensions);
Animation::registerExtensions (extensions);
Transformation::registerExtensions (extensions);
}
void installOpcodes (Interpreter::Interpreter& interpreter)
@ -47,5 +49,6 @@ namespace MWScript
Control::installOpcodes (interpreter);
Dialogue::installOpcodes (interpreter);
Animation::installOpcodes (interpreter);
Transformation::installOpcodes (interpreter);
}
}

@ -505,6 +505,7 @@ namespace MWScript
}
};
const int numberOfAttributes = 8;
const int opcodeGetAttribute = 0x2000027;

@ -0,0 +1,140 @@
#include <boost/algorithm/string.hpp>
#include <components/esm_store/store.hpp>
#include <components/compiler/extensions.hpp>
#include <components/interpreter/interpreter.hpp>
#include <components/interpreter/runtime.hpp>
#include <components/interpreter/opcodes.hpp>
#include "../mwbase/environment.hpp"
#include "../mwworld/class.hpp"
#include "interpretercontext.hpp"
#include "ref.hpp"
#include "OgreSceneNode.h"
namespace MWScript
{
namespace Transformation
{
template<class R>
class OpSetScale : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float scale = runtime[0].mFloat;
runtime.pop();
MWBase::Environment::get().getWorld()->scaleObject(ptr,scale);
}
};
template<class R>
class OpGetScale : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
runtime.push(ptr.getCellRef().scale);
}
};
template<class R>
class OpSetAngle : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
std::string axis = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
Interpreter::Type_Float angle = runtime[0].mFloat;
runtime.pop();
float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees();
float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees();
float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees();
if(axis == "X")
{
MWBase::Environment::get().getWorld()->rotateObject(ptr,angle,ay,az);
}
if(axis == "Y")
{
MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,angle,az);
}
if(axis == "Z")
{
MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,angle);
}
}
};
template<class R>
class OpGetAngle : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
std::string axis = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
if(axis == "X")
{
runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees());
}
if(axis == "Y")
{
runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees());
}
if(axis == "Z")
{
runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees());
}
}
};
const int opcodeSetScale = 0x2000164;
const int opcodeSetScaleExplicit = 0x2000165;
const int opcodeSetAngle = 0x2000166;
const int opcodeSetAngleExplicit = 0x2000167;
const int opcodeGetScale = 0x2000168;
const int opcodeGetScaleExplicit = 0x2000169;
const int opcodeGetAngle = 0x200016a;
const int opcodeGetAngleExplicit = 0x200016b;
void registerExtensions (Compiler::Extensions& extensions)
{
extensions.registerInstruction("setscale","f",opcodeSetScale,opcodeSetScaleExplicit);
extensions.registerFunction("getscale",'f',"",opcodeGetScale,opcodeGetScaleExplicit);
extensions.registerInstruction("setangle","Sf",opcodeSetAngle,opcodeSetAngleExplicit);
extensions.registerFunction("getangle",'f',"S",opcodeGetAngle,opcodeGetAngleExplicit);
}
void installOpcodes (Interpreter::Interpreter& interpreter)
{
interpreter.installSegment5(opcodeSetScale,new OpSetScale<ImplicitRef>);
interpreter.installSegment5(opcodeSetScaleExplicit,new OpSetScale<ExplicitRef>);
interpreter.installSegment5(opcodeSetAngle,new OpSetAngle<ImplicitRef>);
interpreter.installSegment5(opcodeSetAngleExplicit,new OpSetAngle<ExplicitRef>);
interpreter.installSegment5(opcodeGetScale,new OpGetScale<ImplicitRef>);
interpreter.installSegment5(opcodeGetScaleExplicit,new OpGetScale<ExplicitRef>);
interpreter.installSegment5(opcodeGetAngle,new OpGetAngle<ImplicitRef>);
interpreter.installSegment5(opcodeGetAngleExplicit,new OpGetAngle<ExplicitRef>);
}
}
}

@ -0,0 +1,25 @@
#ifndef GAME_SCRIPT_TRANSFORMATIONEXTENSIONS_H
#define GAME_SCRIPT_TRANSFORMATIONEXTENSIONS_H
namespace Compiler
{
class Extensions;
}
namespace Interpreter
{
class Interpreter;
}
namespace MWScript
{
/// \brief stats-related script functionality (creatures and NPCs)
namespace Transformation
{
void registerExtensions (Compiler::Extensions& extensions);
void installOpcodes (Interpreter::Interpreter& interpreter);
}
}
#endif

@ -90,7 +90,7 @@ namespace MWSound
{
if(devname.empty())
throw;
std::cout <<"Failed to open device \""<<devname<<"\", trying default"<< std::endl;
std::cout <<"Failed to open device \""<<devname<<"\", trying default."<< std::endl << "The error given was: " << e.what() << std::endl;
mOutput->init();
Settings::Manager::setString("device", "Sound", "");
}

@ -91,7 +91,7 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, Ptr::CellS
MWWorld::Cells::Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader)
: mStore (store), mReader (reader),
mIdCache (20, std::pair<std::string, Ptr::CellStore *> ("", 0)), /// \todo make cache size configurable
mIdCache (20, std::pair<std::string, Ptr::CellStore *> ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable
mIdCacheIndex (0)
{}

@ -194,4 +194,12 @@ namespace MWWorld
{
return "";
}
void Class::adjustScale(const MWWorld::Ptr& ptr,float& scale) const
{
}
void Class::adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const
{
}
}

@ -187,6 +187,10 @@ namespace MWWorld
virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const;
///< @return the enchantment ID if the object is enchanted, otherwise an empty string
/// (default implementation: return empty string)
virtual void adjustScale(const MWWorld::Ptr& ptr,float& scale) const;
virtual void adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const;
};
}

@ -165,9 +165,6 @@ namespace MWWorld
for (std::vector<std::pair<std::string, Ogre::Vector3> >::const_iterator iter (actors.begin());
iter!=actors.end(); ++iter)
{
OEngine::Physic::PhysicActor* act = mEngine->getCharacter(iter->first);
//if(iter->first == "player")
// std::cout << "This is player\n";
//dirty stuff to get the camera orientation. Must be changed!
Ogre::SceneNode *sceneNode = mRender.getScene()->getSceneNode (iter->first);
@ -177,46 +174,28 @@ namespace MWWorld
Ogre::Quaternion yawQuat = yawNode->getOrientation();
Ogre::Quaternion pitchQuat = pitchNode->getOrientation();
// unused
//Ogre::Quaternion both = yawQuat * pitchQuat;
playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees();
playerphysics->ps.viewangles.z = 0;
playerphysics->ps.viewangles.y = yawQuat.getYaw().valueDegrees() *-1 + 90;
if(mFreeFly)
{
Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y);
pm_ref.rightmove = -dir1.x;
pm_ref.forwardmove = dir1.z;
pm_ref.upmove = dir1.y;
playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees();
playerphysics->ps.viewangles.y = yawQuat.getYaw().valueDegrees() *-1 + 90;
//std::cout << "Current angle" << yawQuat.getYaw().valueDegrees() - 90<< "\n";
//playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees();
//std::cout << "Pitch: " << yawQuat.getPitch() << "Yaw:" << yawQuat.getYaw() << "Roll: " << yawQuat.getRoll() << "\n";
dir = 0.07*(yawQuat*pitchQuat*dir1);
}
else
{
Ogre::Quaternion quat = yawNode->getOrientation();
Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y);
pm_ref.rightmove = -dir1.x;
pm_ref.forwardmove = dir1.z;
pm_ref.upmove = dir1.y;
pm_ref.rightmove = -iter->second.x;
pm_ref.forwardmove = -iter->second.y;
pm_ref.upmove = iter->second.z;
dir = 0.025*(quat*dir1);
}
//set the walk direction
act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y));
}
mEngine->stepSimulation(dt);
}
@ -234,10 +213,6 @@ namespace MWWorld
if(it->first == "player"){
coord = playerphysics->ps.origin;
//std::cout << "ZCoord: " << coord.z << "\n";
//std::cout << "Coord" << coord << "\n";
//coord = Ogre::Vector3(coord.x, coord.z, coord.y); //x, z, -y
}
@ -262,6 +237,7 @@ namespace MWWorld
void PhysicsSystem::addObject (const std::string& handle, const std::string& mesh,
const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position)
{
handleToMesh[handle] = mesh;
OEngine::Physic::RigidBody* body = mEngine->createRigidBody(mesh,handle,scale);
mEngine->addRigidBody(body);
btTransform tr;
@ -314,17 +290,27 @@ namespace MWWorld
void PhysicsSystem::rotateObject (const std::string& handle, const Ogre::Quaternion& rotation)
{
if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle))
if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle))
{
// TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow
// start positions others than 0, 0, 0
act->setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w));
}
if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle))
{
body->getWorldTransform().setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w));
}
}
void PhysicsSystem::scaleObject (const std::string& handle, float scale)
{
if(handleToMesh.find(handle) != handleToMesh.end())
{
btTransform transform = mEngine->getRigidBody(handle)->getWorldTransform();
removeObject(handle);
Ogre::Quaternion quat = Ogre::Quaternion(transform.getRotation().getW(), transform.getRotation().getX(), transform.getRotation().getY(), transform.getRotation().getZ());
Ogre::Vector3 vec = Ogre::Vector3(transform.getOrigin().getX(), transform.getOrigin().getY(), transform.getOrigin().getZ());
addObject(handle, handleToMesh[handle], quat, scale, vec);
}
}
bool PhysicsSystem::toggleCollisionMode()

@ -72,6 +72,7 @@ namespace MWWorld
OEngine::Physic::PhysicEngine* mEngine;
bool mFreeFly;
playerMove* playerphysics;
std::map<std::string, std::string> handleToMesh;
PhysicsSystem (const PhysicsSystem&);
PhysicsSystem& operator= (const PhysicsSystem&);

@ -9,6 +9,9 @@
#include "../mwmechanics/drawstate.hpp"
#undef DrawState // How did this get defined again?
// Maybe it's defined by default in every file for windows?
namespace MWBase
{
class World;

@ -597,6 +597,31 @@ namespace MWWorld
mPhysics->moveObject (ptr.getRefData().getHandle(), Ogre::Vector3 (x, y, z));
}
void World::scaleObject (const Ptr& ptr, float scale)
{
MWWorld::Class::get(ptr).adjustScale(ptr,scale);
ptr.getCellRef().scale = scale;
//scale = scale/ptr.getRefData().getBaseNode()->getScale().x;
ptr.getRefData().getBaseNode()->setScale(scale,scale,scale);
mPhysics->scaleObject( ptr.getRefData().getHandle(), scale );
}
void World::rotateObject (const Ptr& ptr,float x,float y,float z)
{
MWWorld::Class::get(ptr).adjustRotation(ptr,x,y,z);
ptr.getRefData().getPosition().rot[0] = Ogre::Degree(x).valueRadians();
ptr.getRefData().getPosition().rot[1] = Ogre::Degree(y).valueRadians();
ptr.getRefData().getPosition().rot[2] = Ogre::Degree(z).valueRadians();
Ogre::Quaternion rotx(Ogre::Degree(x),Ogre::Vector3::UNIT_X);
Ogre::Quaternion roty(Ogre::Degree(y),Ogre::Vector3::UNIT_Y);
Ogre::Quaternion rotz(Ogre::Degree(z),Ogre::Vector3::UNIT_Z);
ptr.getRefData().getBaseNode()->setOrientation(rotz*roty*rotx);
mPhysics->rotateObject(ptr.getRefData().getHandle(),ptr.getRefData().getBaseNode()->getOrientation());
}
void World::indexToPosition (int cellX, int cellY, float &x, float &y, bool centre) const
{
const int cellSize = 8192;

@ -188,7 +188,7 @@ namespace MWWorld
virtual bool toggleSky();
///< \return Resulting mode
virtual void changeWeather (const std::string& region, const unsigned int id);
virtual void changeWeather (const std::string& region, unsigned int id);
virtual int getCurrentWeather() const;
@ -219,6 +219,10 @@ namespace MWWorld
virtual void moveObject (const Ptr& ptr, float x, float y, float z);
virtual void scaleObject (const Ptr& ptr, float scale);
virtual void rotateObject (const Ptr& ptr,float x,float y,float z);
virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)
const;
///< Convert cell numbers to position.

@ -73,14 +73,16 @@ class DirArchive: public Ogre::FileSystemArchive
{
{
String passed = filename;
if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<'
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);
}
if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':')
passed = filename.substr(0, filename.length() - 6);
copy = passed;
}
@ -226,14 +228,16 @@ public:
BSAFile *narc = (BSAFile*)&arc;
String passed = filename;
if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<'
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);
}
if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':')
passed = filename.substr(0, filename.length() - 6);
// Open the file
StreamPtr strm = narc->getFile(passed.c_str());
@ -248,14 +252,16 @@ bool exists(const String& filename) {
// Check if the file exists.
bool cexists(const String& filename) const {
String passed = filename;
if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<'
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);
}
if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':')
passed = filename.substr(0, filename.length() - 6);
return arc.exists(passed.c_str());
}

@ -25,6 +25,7 @@
#define _NIF_CONTROLLED_H_
#include "extra.hpp"
#include "controller.hpp"
namespace Nif
{
@ -33,92 +34,104 @@ namespace Nif
class Controlled : public Extra
{
public:
ControllerPtr controller;
void read(NIFFile *nif)
{
Extra::read(nif);
controller.read(nif);
}
ControllerPtr controller;
void read(NIFFile *nif)
{
Extra::read(nif);
controller.read(nif);
}
void post(NIFFile *nif)
{
Extra::post(nif);
controller.post(nif);
}
};
/// Has name, extra-data and controller
class Named : public Controlled
{
public:
Misc::SString name;
std::string name;
void read(NIFFile *nif)
{
name = nif->getString();
Controlled::read(nif);
}
void read(NIFFile *nif)
{
name = nif->getString();
Controlled::read(nif);
}
};
typedef Named NiSequenceStreamHelper;
class NiParticleGrowFade : public Controlled
{
public:
void read(NIFFile *nif)
{
Controlled::read(nif);
void read(NIFFile *nif)
{
Controlled::read(nif);
// Two floats.
nif->skip(8);
}
// Two floats.
nif->skip(8);
}
};
class NiParticleColorModifier : public Controlled
{
public:
NiColorDataPtr data;
void read(NIFFile *nif)
{
Controlled::read(nif);
data.read(nif);
}
NiColorDataPtr data;
void read(NIFFile *nif)
{
Controlled::read(nif);
data.read(nif);
}
void post(NIFFile *nif)
{
Controlled::post(nif);
data.post(nif);
}
};
class NiGravity : public Controlled
{
public:
void read(NIFFile *nif)
{
Controlled::read(nif);
void read(NIFFile *nif)
{
Controlled::read(nif);
// two floats, one int, six floats
nif->skip(9*4);
}
// two floats, one int, six floats
nif->skip(9*4);
}
};
// NiPinaColada
class NiPlanarCollider : public Controlled
{
public:
void read(NIFFile *nif)
{
Controlled::read(nif);
void read(NIFFile *nif)
{
Controlled::read(nif);
// (I think) 4 floats + 4 vectors
nif->skip(4*16);
}
// (I think) 4 floats + 4 vectors
nif->skip(4*16);
}
};
class NiParticleRotation : public Controlled
{
public:
void read(NIFFile *nif)
{
Controlled::read(nif);
/*
byte (0 or 1)
float (1)
float*3
*/
nif->skip(17);
}
void read(NIFFile *nif)
{
Controlled::read(nif);
/*
byte (0 or 1)
float (1)
float*3
*/
nif->skip(17);
}
};
} // Namespace

@ -34,136 +34,187 @@ namespace Nif
class Controller : public Record
{
public:
ControllerPtr next;
int flags;
float frequency, phase;
float timeStart, timeStop;
ControlledPtr target;
void read(NIFFile *nif)
{
next.read(nif);
flags = nif->getShort();
frequency = nif->getFloat();
phase = nif->getFloat();
timeStart = nif->getFloat();
timeStop = nif->getFloat();
target.read(nif);
}
ControllerPtr next;
int flags;
float frequency, phase;
float timeStart, timeStop;
ControlledPtr target;
void read(NIFFile *nif)
{
next.read(nif);
flags = nif->getUShort();
frequency = nif->getFloat();
phase = nif->getFloat();
timeStart = nif->getFloat();
timeStop = nif->getFloat();
target.read(nif);
}
void post(NIFFile *nif)
{
Record::post(nif);
next.post(nif);
target.post(nif);
}
};
class NiBSPArrayController : public Controller
{
public:
void read(NIFFile *nif)
{
Controller::read(nif);
// At the moment, just skip it all
nif->skip(111);
int s = nif->getShort();
nif->skip(15 + s*40);
}
void read(NIFFile *nif)
{
Controller::read(nif);
// At the moment, just skip it all
nif->skip(111);
int s = nif->getUShort();
nif->skip(15 + s*40);
}
};
typedef NiBSPArrayController NiParticleSystemController;
class NiMaterialColorController : public Controller
{
public:
NiPosDataPtr data;
void read(NIFFile *nif)
{
Controller::read(nif);
data.read(nif);
}
NiPosDataPtr data;
void read(NIFFile *nif)
{
Controller::read(nif);
data.read(nif);
}
void post(NIFFile *nif)
{
Controller::post(nif);
data.post(nif);
}
};
class NiPathController : public Controller
{
public:
NiPosDataPtr posData;
NiFloatDataPtr floatData;
void read(NIFFile *nif)
{
Controller::read(nif);
/*
int = 1
2xfloat
short = 0 or 1
*/
nif->skip(14);
posData.read(nif);
floatData.read(nif);
}
NiPosDataPtr posData;
NiFloatDataPtr floatData;
void read(NIFFile *nif)
{
Controller::read(nif);
/*
int = 1
2xfloat
short = 0 or 1
*/
nif->skip(14);
posData.read(nif);
floatData.read(nif);
}
void post(NIFFile *nif)
{
Controller::post(nif);
posData.post(nif);
floatData.post(nif);
}
};
class NiUVController : public Controller
{
public:
NiUVDataPtr data;
NiUVDataPtr data;
void read(NIFFile *nif)
{
Controller::read(nif);
void read(NIFFile *nif)
{
Controller::read(nif);
nif->getShort(); // always 0
data.read(nif);
}
nif->getUShort(); // always 0
data.read(nif);
}
void post(NIFFile *nif)
{
Controller::post(nif);
data.post(nif);
}
};
class NiKeyframeController : public Controller
{
public:
NiKeyframeDataPtr data;
void read(NIFFile *nif)
{
Controller::read(nif);
data.read(nif);
}
NiKeyframeDataPtr data;
void read(NIFFile *nif)
{
Controller::read(nif);
data.read(nif);
}
void post(NIFFile *nif)
{
Controller::post(nif);
data.post(nif);
}
};
class NiAlphaController : public Controller
{
public:
NiFloatDataPtr data;
void read(NIFFile *nif)
{
Controller::read(nif);
data.read(nif);
}
NiFloatDataPtr data;
void read(NIFFile *nif)
{
Controller::read(nif);
data.read(nif);
}
void post(NIFFile *nif)
{
Controller::post(nif);
data.post(nif);
}
};
class NiGeomMorpherController : public Controller
{
public:
NiMorphDataPtr data;
void read(NIFFile *nif)
{
Controller::read(nif);
data.read(nif);
nif->getByte(); // always 0
}
NiMorphDataPtr data;
void read(NIFFile *nif)
{
Controller::read(nif);
data.read(nif);
nif->getChar(); // always 0
}
void post(NIFFile *nif)
{
Controller::post(nif);
data.post(nif);
}
};
class NiVisController : public Controller
{
public:
NiVisDataPtr data;
void read(NIFFile *nif)
{
Controller::read(nif);
data.read(nif);
}
NiVisDataPtr data;
void read(NIFFile *nif)
{
Controller::read(nif);
data.read(nif);
}
void post(NIFFile *nif)
{
Controller::post(nif);
data.post(nif);
}
};
} // Namespace

File diff suppressed because it is too large Load Diff

@ -35,57 +35,70 @@ typedef Node Effect;
// NiPointLight and NiSpotLight?
struct NiLight : Effect
{
struct SLight
{
float dimmer;
Vector ambient;
Vector diffuse;
Vector specular;
};
const SLight *light;
void read(NIFFile *nif)
{
Effect::read(nif);
nif->getInt(); // 1
nif->getInt(); // 1?
light = nif->getPtr<SLight>();
}
struct SLight
{
float dimmer;
Ogre::Vector3 ambient;
Ogre::Vector3 diffuse;
Ogre::Vector3 specular;
void read(NIFFile *nif)
{
dimmer = nif->getFloat();
ambient = nif->getVector3();
diffuse = nif->getVector3();
specular = nif->getVector3();
}
};
SLight light;
void read(NIFFile *nif)
{
Effect::read(nif);
nif->getInt(); // 1
nif->getInt(); // 1?
light.read(nif);
}
};
struct NiTextureEffect : Effect
{
NiSourceTexturePtr texture;
void read(NIFFile *nif)
{
Effect::read(nif);
int tmp = nif->getInt();
if(tmp) nif->getInt(); // always 1?
/*
3 x Vector4 = [1,0,0,0]
int = 2
int = 0 or 3
int = 2
int = 2
*/
nif->skip(16*4);
texture.read(nif);
/*
byte = 0
vector4 = [1,0,0,0]
short = 0
short = -75
short = 0
*/
nif->skip(23);
}
NiSourceTexturePtr texture;
void read(NIFFile *nif)
{
Effect::read(nif);
int tmp = nif->getInt();
if(tmp) nif->getInt(); // always 1?
/*
3 x Vector4 = [1,0,0,0]
int = 2
int = 0 or 3
int = 2
int = 2
*/
nif->skip(16*4);
texture.read(nif);
/*
byte = 0
vector4 = [1,0,0,0]
short = 0
short = -75
short = 0
*/
nif->skip(23);
}
void post(NIFFile *nif)
{
Effect::post(nif);
texture.post(nif);
}
};
} // Namespace

@ -38,70 +38,70 @@ namespace Nif
class Extra : public Record
{
public:
ExtraPtr extra;
ExtraPtr extra;
void read(NIFFile *nif) { extra.read(nif); }
void read(NIFFile *nif) { extra.read(nif); }
void post(NIFFile *nif) { extra.post(nif); }
};
class NiVertWeightsExtraData : public Extra
{
public:
void read(NIFFile *nif)
{
Extra::read(nif);
void read(NIFFile *nif)
{
Extra::read(nif);
// We should have s*4+2 == i, for some reason. Might simply be the
// size of the rest of the record, unhelpful as that may be.
/*int i =*/ nif->getInt();
int s = nif->getShort(); // number of vertices
// We should have s*4+2 == i, for some reason. Might simply be the
// size of the rest of the record, unhelpful as that may be.
/*int i =*/ nif->getInt();
int s = nif->getUShort();
nif->getFloatLen(s); // vertex weights I guess
}
nif->skip(s * sizeof(float)); // vertex weights I guess
}
};
class NiTextKeyExtraData : public Extra
{
public:
struct TextKey
{
float time;
Misc::SString text;
};
std::vector<TextKey> list;
void read(NIFFile *nif)
{
Extra::read(nif);
nif->getInt(); // 0
int keynum = nif->getInt();
list.resize(keynum);
for(int i=0; i<keynum; i++)
{
list[i].time = nif->getFloat();
list[i].text = nif->getString();
}
}
struct TextKey
{
float time;
std::string text;
};
std::vector<TextKey> list;
void read(NIFFile *nif)
{
Extra::read(nif);
nif->getInt(); // 0
int keynum = nif->getInt();
list.resize(keynum);
for(int i=0; i<keynum; i++)
{
list[i].time = nif->getFloat();
list[i].text = nif->getString();
}
}
};
class NiStringExtraData : public Extra
{
public:
/* Two known meanings:
"MRK" - marker, only visible in the editor, not rendered in-game
"NCO" - no collision
*/
Misc::SString string;
void read(NIFFile *nif)
{
Extra::read(nif);
nif->getInt(); // size of string + 4. Really useful...
string = nif->getString();
}
/* Two known meanings:
"MRK" - marker, only visible in the editor, not rendered in-game
"NCO" - no collision
*/
std::string string;
void read(NIFFile *nif)
{
Extra::read(nif);
nif->getInt(); // size of string + 4. Really useful...
string = nif->getString();
}
};
} // Namespace

@ -46,8 +46,8 @@ using namespace Misc;
void NIFFile::parse()
{
// Check the header string
const char* head = getString(40);
if(!begins(head, "NetImmerse File Format"))
std::string head = getString(40);
if(head.compare(0, 22, "NetImmerse File Format") != 0)
fail("Invalid NIF header");
// Get BCD version
@ -70,7 +70,7 @@ void NIFFile::parse()
for(int i=0;i<recNum;i++)
{
SString rec = getString();
std::string rec = getString();
//cout << i << ": " << rec.toString() << endl;
Record *r = NULL;
@ -155,7 +155,7 @@ void NIFFile::parse()
// Failure
else
fail("Unknown record type " + rec.toString());
fail("Unknown record type " + rec);
assert(r != NULL);
assert(r->recType != RC_MISSING);
@ -190,17 +190,23 @@ void NIFFile::parse()
void NiSkinInstance::post(NIFFile *nif)
{
int bnum = bones.length();
if(bnum != static_cast<int> (data->bones.size()))
nif->fail("Mismatch in NiSkinData bone count");
data.post(nif);
root.post(nif);
bones.post(nif);
root->makeRootBone(data->trafo);
if(data.empty() || root.empty())
nif->fail("NiSkinInstance missing root or data");
for(int i=0; i<bnum; i++)
{
if(!bones.has(i))
nif->fail("Oops: Missing bone! Don't know how to handle this.");
size_t bnum = bones.length();
if(bnum != data->bones.size())
nif->fail("Mismatch in NiSkinData bone count");
root->makeRootBone(&data->trafo);
bones[i].makeBone(i, data->bones[i]);
for(size_t i=0; i<bnum; i++)
{
if(!bones.has(i))
nif->fail("Oops: Missing bone! Don't know how to handle this.");
bones[i].makeBone(i, data->bones[i]);
}
}

@ -24,9 +24,11 @@
#ifndef _NIF_FILE_H_
#define _NIF_FILE_H_
#include <libs/mangle/stream/stream.hpp>
#include <libs/mangle/stream/filters/buffer_stream.hpp>
#include <components/misc/slice_array.hpp>
#include <OgreResourceGroupManager.h>
#include <OgreDataStream.h>
#include <OgreVector3.h>
#include <OgreVector4.h>
#include <OgreMatrix3.h>
#include <stdexcept>
#include <vector>
@ -36,121 +38,162 @@
#include "record.hpp"
#include "nif_types.hpp"
using namespace Mangle::Stream;
namespace Nif
{
class NIFFile
{
enum NIFVersion
{
VER_MW = 0x04000002 // Morrowind NIFs
enum NIFVersion {
VER_MW = 0x04000002 // Morrowind NIFs
};
/// Nif file version
int ver;
/// Nif file version
int ver;
/// Input stream
StreamPtr inp;
/// Input stream
Ogre::DataStreamPtr inp;
/// File name, used for error messages
std::string filename;
/// File name, used for error messages
std::string filename;
/// Record list
std::vector<Record*> records;
/// Record list
std::vector<Record*> records;
/// Parse the file
void parse();
/// Parse the file
void parse();
public:
/// Used for error handling
void fail(const std::string &msg)
uint8_t read_byte()
{
std::string err = "NIFFile Error: " + msg;
err += "\nFile: " + filename;
throw std::runtime_error(err);
uint8_t byte;
if(inp->read(&byte, 1) != 1) return 0;
return byte;
}
/// Open a NIF stream. The name is used for error messages.
NIFFile(StreamPtr nif, const std::string &name)
: filename(name)
uint16_t read_le16()
{
/* Load the entire file into memory. This allows us to use
direct pointers to the data arrays in the NIF, instead of
individually allocating and copying each one.
The NIF data is only stored temporarily in memory, since once
the mesh data is loaded it is siphoned into OGRE and
deleted. For that reason, we might improve this further and
use a shared region/pool based allocation scheme in the
future, especially since only one NIFFile will ever be loaded
at any given time.
*/
inp = StreamPtr(new BufferStream(nif));
uint8_t buffer[2];
if(inp->read(buffer, 2) != 2) return 0;
return buffer[0] | (buffer[1]<<8);
}
uint32_t read_le32()
{
uint8_t buffer[4];
if(inp->read(buffer, 4) != 4) return 0;
return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24);
}
float read_le32f()
{
union {
int i;
float f;
} u = { read_le32() };
return u.f;
}
parse();
public:
/// Used for error handling
void fail(const std::string &msg)
{
std::string err = "NIFFile Error: " + msg;
err += "\nFile: " + filename;
throw std::runtime_error(err);
}
~NIFFile()
/// Open a NIF stream. The name is used for error messages.
NIFFile(const std::string &name)
: filename(name)
{
for(std::size_t i=0; i<records.size(); i++)
{
delete records[i];
}
inp = Ogre::ResourceGroupManager::getSingleton().openResource(name);
parse();
}
/// Get a given record
Record *getRecord(int index)
{
assert(index >= 0 && index < static_cast<int> (records.size()));
Record *res = records[index];
assert(res != NULL);
return res;
}
~NIFFile()
{
for(std::size_t i=0; i<records.size(); i++)
delete records[i];
}
/// Number of records
int numRecords() { return records.size(); }
/// Get a given record
Record *getRecord(size_t index)
{
Record *res = records.at(index);
assert(res != NULL);
return res;
}
/* ************************************************
/// Number of records
int numRecords() { return records.size(); }
/*************************************************
Parser functions
****************************************************/
****************************************************/
void skip(size_t size) { inp->getPtr(size); }
template<class X> const X* getPtr() { return (const X*)inp->getPtr(sizeof(X)); }
template<class X> X getType() { return *getPtr<X>(); }
unsigned short getShort() { return getType<unsigned short>(); }
int getInt() { return getType<int>(); }
float getFloat() { return getType<float>(); }
char getByte() { return getType<char>(); }
template<class X>
Misc::SliceArray<X> getArrayLen(int num)
{ return Misc::SliceArray<X>((const X*)inp->getPtr(num*sizeof(X)),num); }
void skip(size_t size) { inp->skip(size); }
template<class X>
Misc::SliceArray<X> getArray()
char getChar() { return read_byte(); }
short getShort() { return read_le16(); }
unsigned short getUShort() { return read_le16(); }
int getInt() { return read_le32(); }
float getFloat() { return read_le32f(); }
Ogre::Vector3 getVector3()
{
int len = getInt();
return getArrayLen<X>(len);
float a[3];
for(size_t i = 0;i < 3;i++)
a[i] = getFloat();
return Ogre::Vector3(a);
}
Ogre::Vector4 getVector4()
{
float a[4];
for(size_t i = 0;i < 4;i++)
a[i] = getFloat();
return Ogre::Vector4(a);
}
Ogre::Matrix3 getMatrix3()
{
Ogre::Real a[3][3];
for(size_t i = 0;i < 3;i++)
{
for(size_t j = 0;j < 3;j++)
a[i][j] = Ogre::Real(getFloat());
}
return Ogre::Matrix3(a);
}
Transformation getTrafo()
{
Transformation t;
t.pos = getVector3();
t.rotation = getMatrix3();
t.scale = getFloat();
t.velocity = getVector3();
return t;
}
Misc::SString getString() { return getArray<char>(); }
const Vector *getVector() { return getPtr<Vector>(); }
const Matrix *getMatrix() { return getPtr<Matrix>(); }
const Transformation *getTrafo() { return getPtr<Transformation>(); }
const Vector4 *getVector4() { return getPtr<Vector4>(); }
Misc::FloatArray getFloatLen(int num)
{ return getArrayLen<float>(num); }
std::string getString(size_t length)
{
std::string str;
str.resize(length);
if(inp->read(&str[0], length) != length)
return std::string();
return str.substr(0, str.find('\0'));
}
std::string getString()
{
size_t size = read_le32();
return getString(size);
}
// For fixed-size strings where you already know the size
const char *getString(int size)
{ return (const char*)inp->getPtr(size); }
void getShorts(std::vector<short> &vec, size_t size)
{
vec.resize(size);
for(size_t i = 0;i < vec.size();i++)
vec[i] = getShort();
}
void getFloats(std::vector<float> &vec, size_t size)
{
vec.resize(size);
for(size_t i = 0;i < vec.size();i++)
vec[i] = getFloat();
}
};
} // Namespace

@ -24,59 +24,37 @@
#ifndef _NIF_TYPES_H_
#define _NIF_TYPES_H_
#include <OgreVector3.h>
#include <OgreMatrix3.h>
// Common types used in NIF files
namespace Nif
{
/* These packing #pragmas aren't really necessary on 32 bit
machines. I haven't tested on 64 bit yet. In any case it doesn't
hurt to include them. We can't allow any compiler-generated padding
in any of these structs, since they are used to interface directly
with raw data from the NIF files.
*/
#pragma pack(push)
#pragma pack(1)
struct Vector
{
float array[3];
};
struct Vector4
{
float array[4];
};
struct Matrix
{
Vector v[3];
};
struct Transformation
{
Vector pos;
Matrix rotation;
Ogre::Vector3 pos;
Ogre::Matrix3 rotation;
float scale;
Vector velocity;
Ogre::Vector3 velocity;
static const Transformation* getIdentity()
static const Transformation& getIdentity()
{
static Transformation identity;
static bool iset = false;
if (!iset)
{
identity.scale = 1.0f;
identity.rotation.v[0].array[0] = 1.0f;
identity.rotation.v[1].array[1] = 1.0f;
identity.rotation.v[2].array[2] = 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;
}
};
#pragma pack(pop)
} // Namespace
#endif

@ -26,10 +26,13 @@
#include "controlled.hpp"
#include "data.hpp"
#include "property.hpp"
namespace Nif
{
class NiNode;
/** A Node is an object that's part of the main NIF tree. It has
parent node (unless it's the root), and transformation (location
and rotation) relative to it's parent.
@ -37,191 +40,250 @@ namespace Nif
class Node : public Named
{
public:
// Node flags. Interpretation depends somewhat on the type of node.
int flags;
const Transformation *trafo;
PropertyList props;
// Bounding box info
bool hasBounds;
const Vector *boundPos;
const Matrix *boundRot;
const Vector *boundXYZ; // Box size
void read(NIFFile *nif)
{
Named::read(nif);
flags = nif->getShort();
trafo = nif->getTrafo();
props.read(nif);
hasBounds = !!nif->getInt();
if(hasBounds)
{
nif->getInt(); // always 1
boundPos = nif->getVector();
boundRot = nif->getMatrix();
boundXYZ = nif->getVector();
}
boneTrafo = NULL;
boneIndex = -1;
}
// Bone transformation. If set, node is a part of a skeleton.
const NiSkinData::BoneTrafo *boneTrafo;
// Bone weight info, from NiSkinData
const NiSkinData::BoneInfo *boneInfo;
// Bone index. If -1, this node is either not a bone, or if
// boneTrafo is set it is the root bone in the skeleton.
short boneIndex;
void makeRootBone(const NiSkinData::BoneTrafo *tr)
{
boneTrafo = tr;
boneIndex = -1;
}
void makeBone(short ind, const NiSkinData::BoneInfo &bi)
{
boneInfo = &bi;
boneTrafo = bi.trafo;
boneIndex = ind;
}
// Node flags. Interpretation depends somewhat on the type of node.
int flags;
Transformation trafo;
PropertyList props;
// Bounding box info
bool hasBounds;
Ogre::Vector3 boundPos;
Ogre::Matrix3 boundRot;
Ogre::Vector3 boundXYZ; // Box size
void read(NIFFile *nif)
{
Named::read(nif);
flags = nif->getUShort();
trafo = nif->getTrafo();
props.read(nif);
hasBounds = !!nif->getInt();
if(hasBounds)
{
nif->getInt(); // always 1
boundPos = nif->getVector3();
boundRot = nif->getMatrix3();
boundXYZ = nif->getVector3();
}
parent = NULL;
boneTrafo = NULL;
boneIndex = -1;
}
void post(NIFFile *nif)
{
Named::post(nif);
props.post(nif);
}
// Parent node, or NULL for the root node. As far as I'm aware, only
// NiNodes (or types derived from NiNodes) can be parents.
NiNode *parent;
// Bone transformation. If set, node is a part of a skeleton.
const NiSkinData::BoneTrafo *boneTrafo;
// Bone weight info, from NiSkinData
const NiSkinData::BoneInfo *boneInfo;
// Bone index. If -1, this node is either not a bone, or if
// boneTrafo is set it is the root bone in the skeleton.
short boneIndex;
void makeRootBone(const NiSkinData::BoneTrafo *tr)
{
boneTrafo = tr;
boneIndex = -1;
}
void makeBone(short ind, const NiSkinData::BoneInfo &bi)
{
boneInfo = &bi;
boneTrafo = &bi.trafo;
boneIndex = ind;
}
};
struct NiTriShapeCopy
{
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;
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
{
NodeList children;
NodeList effects;
/* Known NiNode flags:
0x01 hidden
0x02 use mesh for collision
0x04 use bounding box for collision (?)
0x08 unknown, but common
0x20, 0x40, 0x80 unknown
*/
void read(NIFFile *nif)
{
Node::read(nif);
children.read(nif);
effects.read(nif);
}
NodeList children;
NodeList effects;
/* Known NiNode flags:
0x01 hidden
0x02 use mesh for collision
0x04 use bounding box for collision (?)
0x08 unknown, but common
0x20, 0x40, 0x80 unknown
*/
void read(NIFFile *nif)
{
Node::read(nif);
children.read(nif);
effects.read(nif);
}
void post(NIFFile *nif)
{
Node::post(nif);
children.post(nif);
effects.post(nif);
for(size_t i = 0;i < children.length();i++)
{
// Why would a unique list of children contain empty refs?
if(children.has(i))
children[i].parent = this;
}
}
};
struct NiTriShape : Node
{
/* Possible flags:
0x40 - mesh has no vertex normals ?
Only flags included in 0x47 (ie. 0x01, 0x02, 0x04 and 0x40) have
been observed so far.
*/
NiTriShapeDataPtr data;
NiSkinInstancePtr skin;
void read(NIFFile *nif)
{
Node::read(nif);
data.read(nif);
skin.read(nif);
}
NiTriShapeCopy clone(){
NiTriShapeCopy copy;
copy.sname = name.toString();
float *ptr = (float*)data->vertices.ptr;
float *ptrNormals = (float*)data->normals.ptr;
int numVerts = data->vertices.length / 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;
}
/* Possible flags:
0x40 - mesh has no vertex normals ?
Only flags included in 0x47 (ie. 0x01, 0x02, 0x04 and 0x40) have
been observed so far.
*/
NiTriShapeDataPtr data;
NiSkinInstancePtr skin;
void read(NIFFile *nif)
{
Node::read(nif);
data.read(nif);
skin.read(nif);
}
void post(NIFFile *nif)
{
Node::post(nif);
data.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 Camera
{
// Camera frustrum
float left, right, top, bottom, nearDist, farDist;
// Viewport
float vleft, vright, vtop, vbottom;
// Level of detail modifier
float LOD;
};
const Camera *cam;
void read(NIFFile *nif)
{
Node::read(nif);
nif->getPtr<Camera>();
nif->getInt(); // -1
nif->getInt(); // 0
}
struct Camera
{
// Camera frustrum
float left, right, top, bottom, nearDist, farDist;
// Viewport
float vleft, vright, vtop, vbottom;
// Level of detail modifier
float LOD;
void read(NIFFile *nif)
{
left = nif->getFloat();
right = nif->getFloat();
top = nif->getFloat();
bottom = nif->getFloat();
nearDist = nif->getFloat();
farDist = nif->getFloat();
vleft = nif->getFloat();
vright = nif->getFloat();
vtop = nif->getFloat();
vbottom = nif->getFloat();
LOD = nif->getFloat();
}
};
Camera cam;
void read(NIFFile *nif)
{
Node::read(nif);
cam.read(nif);
nif->getInt(); // -1
nif->getInt(); // 0
}
};
struct NiAutoNormalParticles : Node
{
NiAutoNormalParticlesDataPtr data;
void read(NIFFile *nif)
{
Node::read(nif);
data.read(nif);
nif->getInt(); // -1
}
NiAutoNormalParticlesDataPtr data;
void read(NIFFile *nif)
{
Node::read(nif);
data.read(nif);
nif->getInt(); // -1
}
void post(NIFFile *nif)
{
Node::post(nif);
data.post(nif);
}
};
struct NiRotatingParticles : Node
{
NiRotatingParticlesDataPtr data;
void read(NIFFile *nif)
{
Node::read(nif);
data.read(nif);
nif->getInt(); // -1
}
NiRotatingParticlesDataPtr data;
void read(NIFFile *nif)
{
Node::read(nif);
data.read(nif);
nif->getInt(); // -1
}
void post(NIFFile *nif)
{
Node::post(nif);
data.post(nif);
}
};
} // Namespace
#endif

@ -32,104 +32,116 @@ namespace Nif
class Property : public Named
{
public:
// The meaning of these depends on the actual property type.
int flags;
void read(NIFFile *nif)
{
Named::read(nif);
flags = nif->getShort();
}
// The meaning of these depends on the actual property type.
int flags;
void read(NIFFile *nif)
{
Named::read(nif);
flags = nif->getUShort();
}
};
class NiTexturingProperty : public Property
{
public:
// A sub-texture
struct Texture
{
/* Clamp mode
0 - clampS clampT
1 - clampS wrapT
2 - wrapS clampT
3 - wrapS wrapT
*/
/* Filter:
0 - nearest
1 - bilinear
2 - trilinear
3, 4, 5 - who knows
// A sub-texture
struct Texture
{
/* Clamp mode
0 - clampS clampT
1 - clampS wrapT
2 - wrapS clampT
3 - wrapS wrapT
*/
/* Filter:
0 - nearest
1 - bilinear
2 - trilinear
3, 4, 5 - who knows
*/
bool inUse;
NiSourceTexturePtr texture;
int clamp, set, filter;
short unknown2;
void read(NIFFile *nif)
{
inUse = !!nif->getInt();
if(!inUse) return;
texture.read(nif);
clamp = nif->getInt();
filter = nif->getInt();
set = nif->getInt();
// I have no idea, but I think these are actually two
// PS2-specific shorts (ps2L and ps2K), followed by an unknown
// short.
nif->skip(6);
}
void post(NIFFile *nif)
{
texture.post(nif);
}
};
/* Apply mode:
0 - replace
1 - decal
2 - modulate
3 - hilight // These two are for PS2 only?
4 - hilight2
*/
bool inUse;
NiSourceTexturePtr texture;
int clamp, set, filter;
short unknown2;
int apply;
/*
* The textures in this list are as follows:
*
* 0 - Base texture
* 1 - Dark texture
* 2 - Detail texture
* 3 - Gloss texture (never used?)
* 4 - Glow texture
* 5 - Bump map texture
* 6 - Decal texture
*/
Texture textures[7];
void read(NIFFile *nif)
{
inUse = !!nif->getInt();
if(!inUse) return;
texture.read(nif);
clamp = nif->getInt();
filter = nif->getInt();
set = nif->getInt();
// I have no idea, but I think these are actually two
// PS2-specific shorts (ps2L and ps2K), followed by an unknown
// short.
nif->skip(6);
Property::read(nif);
apply = nif->getInt();
// Unknown, always 7. Probably the number of textures to read
// below
nif->getInt();
textures[0].read(nif); // Base
textures[1].read(nif); // Dark
textures[2].read(nif); // Detail
textures[3].read(nif); // Gloss (never present)
textures[4].read(nif); // Glow
textures[5].read(nif); // Bump map
if(textures[5].inUse)
{
// Ignore these at the moment
/*float lumaScale =*/ nif->getFloat();
/*float lumaOffset =*/ nif->getFloat();
/*const Vector4 *lumaMatrix =*/ nif->getVector4();
}
textures[6].read(nif); // Decal
}
void post(NIFFile *nif)
{
Property::post(nif);
for(int i = 0;i < 7;i++)
textures[i].post(nif);
}
};
/* Apply mode:
0 - replace
1 - decal
2 - modulate
3 - hilight // These two are for PS2 only?
4 - hilight2
*/
int apply;
/*
* The textures in this list are as follows:
*
* 0 - Base texture
* 1 - Dark texture
* 2 - Detail texture
* 3 - Gloss texture (never used?)
* 4 - Glow texture
* 5 - Bump map texture
* 6 - Decal texture
*/
Texture textures[7];
void read(NIFFile *nif)
{
Property::read(nif);
apply = nif->getInt();
// Unknown, always 7. Probably the number of textures to read
// below
nif->getInt();
textures[0].read(nif); // Base
textures[1].read(nif); // Dark
textures[2].read(nif); // Detail
textures[3].read(nif); // Gloss (never present)
textures[4].read(nif); // Glow
textures[5].read(nif); // Bump map
if(textures[5].inUse)
{
// Ignore these at the moment
/*float lumaScale =*/ nif->getFloat();
/*float lumaOffset =*/ nif->getFloat();
/*const Vector4 *lumaMatrix =*/ nif->getVector4();
}
textures[6].read(nif); // Decal
}
};
// These contain no other data than the 'flags' field in Property
@ -140,88 +152,109 @@ typedef Property NiSpecularProperty;
typedef Property NiWireframeProperty;
// The rest are all struct-based
template <typename Struct>
template <typename T>
struct StructPropT : Property
{
const Struct* data;
T data;
void read(NIFFile *nif)
{
Property::read(nif);
data = nif->getPtr<Struct>();
}
void read(NIFFile *nif)
{
Property::read(nif);
data.read(nif);
}
};
struct S_MaterialProperty
{
// The vector components are R,G,B
Vector ambient, diffuse, specular, emissive;
float glossiness, alpha;
// The vector components are R,G,B
Ogre::Vector3 ambient, diffuse, specular, emissive;
float glossiness, alpha;
void read(NIFFile *nif)
{
ambient = nif->getVector3();
diffuse = nif->getVector3();
specular = nif->getVector3();
emissive = nif->getVector3();
glossiness = nif->getFloat();
alpha = nif->getFloat();
}
};
struct S_VertexColorProperty
{
/* Vertex mode:
0 - source ignore
1 - source emmisive
2 - source amb diff
Lighting mode
0 - lighting emmisive
1 - lighting emmisive ambient/diffuse
*/
int vertmode, lightmode;
/* Vertex mode:
0 - source ignore
1 - source emmisive
2 - source amb diff
Lighting mode
0 - lighting emmisive
1 - lighting emmisive ambient/diffuse
*/
int vertmode, lightmode;
void read(NIFFile *nif)
{
vertmode = nif->getInt();
lightmode = nif->getInt();
}
};
struct S_AlphaProperty
{
/*
In NiAlphaProperty, the flags have the following meaning:
Bit 0 : alpha blending enable
Bits 1-4 : source blend mode
Bits 5-8 : destination blend mode
Bit 9 : alpha test enable
Bit 10-12 : alpha test mode
Bit 13 : no sorter flag ( disables triangle sorting )
blend modes (glBlendFunc):
0000 GL_ONE
0001 GL_ZERO
0010 GL_SRC_COLOR
0011 GL_ONE_MINUS_SRC_COLOR
0100 GL_DST_COLOR
0101 GL_ONE_MINUS_DST_COLOR
0110 GL_SRC_ALPHA
0111 GL_ONE_MINUS_SRC_ALPHA
1000 GL_DST_ALPHA
1001 GL_ONE_MINUS_DST_ALPHA
1010 GL_SRC_ALPHA_SATURATE
test modes (glAlphaFunc):
000 GL_ALWAYS
001 GL_LESS
010 GL_EQUAL
011 GL_LEQUAL
100 GL_GREATER
101 GL_NOTEQUAL
110 GL_GEQUAL
111 GL_NEVER
Taken from:
http://niftools.sourceforge.net/doc/nif/NiAlphaProperty.html
Right now we only use standard alpha blending (see the Ogre code
that sets it up) and it appears that this is the only blending
used in the original game. Bloodmoon (along with several mods) do
however use other settings, such as discarding pixel values with
alpha < 1.0. This is faster because we don't have to mess with the
depth stuff like we did for blending. And OGRE has settings for
this too.
*/
// Tested against when certain flags are set (see above.)
unsigned char threshold;
/*
In NiAlphaProperty, the flags have the following meaning:
Bit 0 : alpha blending enable
Bits 1-4 : source blend mode
Bits 5-8 : destination blend mode
Bit 9 : alpha test enable
Bit 10-12 : alpha test mode
Bit 13 : no sorter flag ( disables triangle sorting )
blend modes (glBlendFunc):
0000 GL_ONE
0001 GL_ZERO
0010 GL_SRC_COLOR
0011 GL_ONE_MINUS_SRC_COLOR
0100 GL_DST_COLOR
0101 GL_ONE_MINUS_DST_COLOR
0110 GL_SRC_ALPHA
0111 GL_ONE_MINUS_SRC_ALPHA
1000 GL_DST_ALPHA
1001 GL_ONE_MINUS_DST_ALPHA
1010 GL_SRC_ALPHA_SATURATE
test modes (glAlphaFunc):
000 GL_ALWAYS
001 GL_LESS
010 GL_EQUAL
011 GL_LEQUAL
100 GL_GREATER
101 GL_NOTEQUAL
110 GL_GEQUAL
111 GL_NEVER
Taken from:
http://niftools.sourceforge.net/doc/nif/NiAlphaProperty.html
Right now we only use standard alpha blending (see the Ogre code
that sets it up) and it appears that this is the only blending
used in the original game. Bloodmoon (along with several mods) do
however use other settings, such as discarding pixel values with
alpha < 1.0. This is faster because we don't have to mess with the
depth stuff like we did for blending. And OGRE has settings for
this too.
*/
// Tested against when certain flags are set (see above.)
unsigned char threshold;
void read(NIFFile *nif)
{
threshold = nif->getChar();
}
};
typedef StructPropT<S_AlphaProperty> NiAlphaProperty;

@ -88,26 +88,25 @@ enum RecordType
/// Base class for all records
struct Record
{
// Record type and type name
int recType;
Misc::SString recName;
// Record type and type name
int recType;
std::string recName;
Record() : recType(RC_MISSING) {}
Record() : recType(RC_MISSING) {}
/// Parses the record from file
virtual void read(NIFFile *nif) = 0;
/// Parses the record from file
virtual void read(NIFFile *nif) = 0;
/// Does post-processing, after the entire tree is loaded
virtual void post(NIFFile *nif) {}
/// Does post-processing, after the entire tree is loaded
virtual void post(NIFFile *nif) {}
virtual ~Record() {}
/*
Use these later if you want custom allocation of all NIF objects
static void* operator new(size_t size);
static void operator delete(void *p);
*/
/*
Use these later if you want custom allocation of all NIF objects
static void* operator new(size_t size);
static void operator delete(void *p);
*/
};
} // Namespace

@ -37,61 +37,52 @@ namespace Nif
template <class X>
class RecordPtrT
{
int index;
X* ptr;
NIFFile *nif;
public:
RecordPtrT() : index(-2), ptr(NULL) {}
/// Read the index from the nif
void read(NIFFile *_nif)
{
// Can only read the index once
assert(index == -2);
// Store the NIFFile pointer for later
nif = _nif;
// And the index, of course
index = nif->getInt();
}
/** Set the pointer explicitly. May be used when you are pointing to
records in another file, eg. when you have a .nif / .kf pair.
*/
void set(X *p)
{
ptr = p;
index = -1;
}
/// Look up the actual object from the index
X* getPtr()
{
// Have we found the pointer already?
if(ptr == NULL)
{
// Get the record
assert(index >= 0);
Record *r = nif->getRecord(index);
// And cast it
ptr = dynamic_cast<X*>(r);
assert(ptr != NULL);
}
return ptr;
}
union {
intptr_t index;
X* ptr;
};
/// Syntactic sugar
X* operator->() { return getPtr(); }
X& get() { return *getPtr(); }
public:
RecordPtrT() : index(-2) {}
/// Pointers are allowed to be empty
bool empty() { return index == -1 && ptr == NULL; }
/// Read the index from the nif
void read(NIFFile *nif)
{
// Can only read the index once
assert(index == -2);
int getIndex() { return index; }
// Store the index for later
index = nif->getInt();
assert(index >= -1);
}
/// Resolve index to pointer
void post(NIFFile *nif)
{
if(index < 0)
ptr = NULL;
else
{
Record *r = nif->getRecord(index);
// And cast it
ptr = dynamic_cast<X*>(r);
assert(ptr != NULL);
}
}
/// Look up the actual object from the index
X* getPtr()
{
assert(ptr != NULL);
return ptr;
}
X& get() { return *getPtr(); }
/// Syntactic sugar
X* operator->() { return getPtr(); }
/// Pointers are allowed to be empty
bool empty() { return ptr == NULL; }
};
/** A list of references to other records. These are read as a list,
@ -101,40 +92,37 @@ class RecordPtrT
template <class X>
class RecordListT
{
typedef RecordPtrT<X> Ptr;
std::vector<Ptr> list;
public:
typedef RecordPtrT<X> Ptr;
std::vector<Ptr> list;
void read(NIFFile *nif)
{
int len = nif->getInt();
list.resize(len);
public:
void read(NIFFile *nif)
{
int len = nif->getInt();
list.resize(len);
assert(len >= 0 && len < 1000);
for(int i=0;i<len;i++)
list[i].read(nif);
}
for(size_t i=0;i < list.size();i++)
list[i].read(nif);
}
X& operator[](int index)
void post(NIFFile *nif)
{
assert(index >= 0 && index < static_cast<int> (list.size()));
return list[index].get();
for(size_t i=0;i < list.size();i++)
list[i].post(nif);
}
bool has(int index)
{
assert(index >= 0 && index < static_cast<int> (list.size()));
return !list[index].empty();
}
X& operator[](size_t index)
{
return list.at(index).get();
}
int getIndex(int index)
bool has(size_t index)
{
if(has(index)) return list[index].getIndex();
else return -1;
return !list.at(index).empty();
}
int length() { return list.size(); }
size_t length()
{ return list.size(); }
};

@ -1,4 +1,4 @@
/*
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008-2010 Nicolay Korslund
Email: < korslund@gmail.com >
@ -25,7 +25,6 @@ http://www.gnu.org/licenses/ .
#include <Ogre.h>
#include <stdio.h>
#include <libs/mangle/vfs/servers/ogre_vfs.hpp>
#include "../nif/nif_file.hpp"
#include "../nif/node.hpp"
#include "../nif/data.hpp"
@ -44,32 +43,15 @@ http://www.gnu.org/licenses/ .
typedef unsigned char ubyte;
using namespace std;
using namespace Ogre;
using namespace Nif;
using namespace Mangle::VFS;
using namespace NifBullet;
ManualBulletShapeLoader::~ManualBulletShapeLoader()
{
delete vfs;
}
Ogre::Matrix3 ManualBulletShapeLoader::getMatrix(Nif::Transformation* tr)
{
Ogre::Matrix3 rot(tr->rotation.v[0].array[0],tr->rotation.v[0].array[1],tr->rotation.v[0].array[2],
tr->rotation.v[1].array[0],tr->rotation.v[1].array[1],tr->rotation.v[1].array[2],
tr->rotation.v[2].array[0],tr->rotation.v[2].array[1],tr->rotation.v[2].array[2]);
return rot;
}
Ogre::Vector3 ManualBulletShapeLoader::getVector(Nif::Transformation* tr)
{
Ogre::Vector3 vect3(tr->pos.array[0],tr->pos.array[1],tr->pos.array[2]);
return vect3;
}
btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 m)
btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 &m)
{
Ogre::Quaternion oquat(m);
btQuaternion quat;
@ -80,10 +62,9 @@ btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 m)
return quat;
}
btVector3 ManualBulletShapeLoader::getbtVector(Nif::Vector v)
btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 &v)
{
btVector3 a(v.array[0],v.array[1],v.array[2]);
return a;
return btVector3(v[0], v[1], v[2]);
}
void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
@ -94,20 +75,11 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
mTriMesh = new btTriangleMesh();
if (!vfs) vfs = new OgreVFS(resourceGroup);
if (!vfs->isFile(resourceName))
{
warn("File not found.");
return;
}
// Load the NIF. TODO: Wrap this in a try-catch block once we're out
// of the early stages of development. Right now we WANT to catch
// every error as early and intrusively as possible, as it's most
// likely a sign of incomplete code rather than faulty input.
Nif::NIFFile nif(vfs->open(resourceName), resourceName);
Nif::NIFFile nif(resourceName);
if (nif.numRecords() < 1)
{
warn("Found no records in NIF.");
@ -120,26 +92,25 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
assert(r != NULL);
Nif::Node *node = dynamic_cast<Nif::Node*>(r);
if (node == NULL)
{
warn("First record in file was not a node, but a " +
r->recName.toString() + ". Skipping file.");
r->recName + ". Skipping file.");
return;
}
bool hasCollisionNode = hasRootCollisionNode(node);
//do a first pass
handleNode(node,0,Ogre::Matrix3::IDENTITY,Ogre::Vector3::ZERO,1,hasCollisionNode,false,false);
handleNode(node,0,NULL,hasCollisionNode,false,false);
//if collide = false, then it does a second pass which create a shape for raycasting.
if(cShape->collide == false)
{
handleNode(node,0,Ogre::Matrix3::IDENTITY,Ogre::Vector3::ZERO,1,hasCollisionNode,false,true);
handleNode(node,0,NULL,hasCollisionNode,false,true);
}
cShape->collide = hasCollisionNode&&cShape->collide;
//cShape->collide = hasCollisionNode&&cShape->collide;
struct TriangleMeshShape : public btBvhTriangleMeshShape
{
@ -186,8 +157,9 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node* node)
}
void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags,
Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly)
const Nif::Transformation *trafo,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly)
{
// Accumulate the flags from all the child nodes. This works for all
// the flags we currently use, at least.
flags |= node->flags;
@ -221,18 +193,26 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags,
}
}
//transfo of parents node + curent node
Ogre::Matrix3 finalRot;
Ogre::Vector3 finalPos;
float finalScale;
Nif::Transformation &final = *((Nif::Transformation*)node->trafo);
Ogre::Vector3 nodePos = getVector(&final);
Ogre::Matrix3 nodeRot = getMatrix(&final);
if (trafo)
{
// Get a non-const reference to the node's data, since we're
// overwriting it. TODO: Is this necessary?
Nif::Transformation &final = node->trafo;
// For both position and rotation we have that:
// final_vector = old_vector + old_rotation*new_vector*old_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
final.rotation = trafo->rotation * final.rotation;
finalPos = nodePos + parentPos;
finalRot = parentRot*nodeRot;
finalScale = final.scale*parentScale;
// Scale
final.scale *= trafo->scale;
}
// For NiNodes, loop through children
@ -244,14 +224,14 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags,
{
if (list.has(i))
{
handleNode(&list[i], flags,finalRot,finalPos,finalScale,hasCollisionNode,isCollisionNode,raycastingOnly);
handleNode(&list[i], flags,&node->trafo,hasCollisionNode,isCollisionNode,raycastingOnly);
}
}
}
else if (node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode))
else if (node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode))
{
cShape->collide = true;
handleNiTriShape(dynamic_cast<Nif::NiTriShape*>(node), flags,finalRot,finalPos,parentScale,raycastingOnly);
handleNiTriShape(dynamic_cast<Nif::NiTriShape*>(node), flags,node->trafo.rotation,node->trafo.pos,node->trafo.scale,raycastingOnly);
}
else if(node->recType == Nif::RC_RootCollisionNode)
{
@ -260,7 +240,7 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags,
for (int i=0; i<n; i++)
{
if (list.has(i))
handleNode(&list[i], flags,finalRot,finalPos,finalScale,hasCollisionNode,true,raycastingOnly);
handleNode(&list[i], flags,&node->trafo, hasCollisionNode,true,raycastingOnly);
}
}
}
@ -292,17 +272,19 @@ void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape *shape, int flags
Nif::NiTriShapeData *data = shape->data.getPtr();
float* vertices = (float*)data->vertices.ptr;
unsigned short* triangles = (unsigned short*)data->triangles.ptr;
for(unsigned int i=0; i < data->triangles.length; i = i+3)
float* vertices = &data->vertices[0];
short* triangles = &data->triangles[0];
const Ogre::Matrix3 &rot = shape->trafo.rotation;
const Ogre::Vector3 &pos = shape->trafo.pos;
float scale = shape->trafo.scale;
for(unsigned int i=0; i < data->triangles.size(); i = 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 b2(vertices[triangles[i+1]*3]*parentScale,vertices[triangles[i+1]*3+1]*parentScale,vertices[triangles[i+1]*3+2]*parentScale);
Ogre::Vector3 b3(vertices[triangles[i+2]*3]*parentScale,vertices[triangles[i+2]*3+1]*parentScale,vertices[triangles[i+2]*3+2]*parentScale);
b1 = parentRot * b1 + parentPos;
b2 = parentRot * b2 + parentPos;
b3 = parentRot * b3 + parentPos;
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));
}
}

@ -46,16 +46,6 @@ namespace Nif
class Node;
class Transformation;
class NiTriShape;
class Vector;
class Matrix;
}
namespace Mangle
{
namespace VFS
{
class OgreVFS;
}
}
namespace NifBullet
@ -68,7 +58,7 @@ class ManualBulletShapeLoader : public BulletShapeLoader
{
public:
ManualBulletShapeLoader():resourceGroup("General"){vfs = 0;}
ManualBulletShapeLoader():resourceGroup("General"){}
virtual ~ManualBulletShapeLoader();
void warn(std::string msg)
@ -95,22 +85,18 @@ public:
void load(const std::string &name,const std::string &group);
private:
Ogre::Matrix3 getMatrix(Nif::Transformation* tr);
Ogre::Vector3 getVector(Nif::Transformation* tr);
btQuaternion getbtQuat(Ogre::Matrix3 &m);
btQuaternion getbtQuat(Ogre::Matrix3 m);
btVector3 getbtVector(Nif::Vector v);
btVector3 getbtVector(Ogre::Vector3 &v);
/**
*Parse a node.
*/
void handleNode(Nif::Node *node, int flags,
Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly);
const Nif::Transformation *trafo, bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly);
/**
*Helpler function
*Helper function
*/
bool hasRootCollisionNode(Nif::Node* node);
@ -119,8 +105,6 @@ private:
*/
void handleNiTriShape(Nif::NiTriShape *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScales,bool raycastingOnly);
Mangle::VFS::OgreVFS *vfs;
std::string resourceName;
std::string resourceGroup;

@ -44,9 +44,7 @@
typedef unsigned char ubyte;
using namespace std;
using namespace Ogre;
using namespace Nif;
using namespace Mangle::VFS;
using namespace Misc;
using namespace NifOgre;
@ -72,21 +70,6 @@ void NIFLoader::fail(string msg)
assert(1);
}
Vector3 NIFLoader::convertVector3(const Nif::Vector& vec)
{
return Ogre::Vector3(vec.array);
}
Quaternion NIFLoader::convertRotation(const Nif::Matrix& rot)
{
Real matrix[3][3];
for (int i=0; i<3; i++)
for (int j=0; j<3; j++)
matrix[i][j] = rot.v[i].array[j];
return Quaternion(Matrix3(matrix));
}
// Helper class that computes the bounding box and of a mesh
class BoundsFinder
@ -222,11 +205,11 @@ void NIFLoader::setOutputAnimFiles(bool output){
void NIFLoader::setVerbosePath(std::string path){
verbosePath = path;
}
void NIFLoader::createMaterial(const String &name,
const Vector &ambient,
const Vector &diffuse,
const Vector &specular,
const Vector &emissive,
void NIFLoader::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 String &texName, bool vertexColor)
@ -309,7 +292,7 @@ void NIFLoader::createMaterial(const String &name,
// Takes a name and adds a unique part to it. This is just used to
// make sure that all materials are given unique names.
String NIFLoader::getUniqueName(const String &input)
Ogre::String NIFLoader::getUniqueName(const Ogre::String &input)
{
static int addon = 0;
static char buf[8];
@ -325,29 +308,25 @@ String NIFLoader::getUniqueName(const String &input)
// does not, change the string IN PLACE to say .dds instead and try
// that. The texture may still not exist, but no information of value
// is lost in that case.
void NIFLoader::findRealTexture(String &texName)
void NIFLoader::findRealTexture(Ogre::String &texName)
{
assert(vfs);
if (vfs->isFile(texName)) return;
int len = texName.size();
if (len < 4) return;
if(Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName))
return;
// Change texture extension to .dds
texName[len-3] = 'd';
texName[len-2] = 'd';
texName[len-1] = 's';
Ogre::String::size_type pos = texName.rfind('.');
texName.replace(pos, texName.length(), ".dds");
}
//Handle node at top
// Convert Nif::NiTriShape to Ogre::SubMesh, attached to the given
// mesh.
void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material, std::list<VertexBoneAssignment> &vertexBoneAssignments)
void NIFLoader::createOgreSubMesh(NiTriShape *shape, const Ogre::String &material, std::list<Ogre::VertexBoneAssignment> &vertexBoneAssignments)
{
// cout << "s:" << shape << "\n";
NiTriShapeData *data = shape->data.getPtr();
SubMesh *sub = mesh->createSubMesh(shape->name.toString());
Ogre::SubMesh *sub = mesh->createSubMesh(shape->name);
int nextBuf = 0;
@ -355,27 +334,27 @@ void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material, std
// great.
// Add vertices
int numVerts = data->vertices.length / 3;
sub->vertexData = new VertexData();
int numVerts = data->vertices.size() / 3;
sub->vertexData = new Ogre::VertexData();
sub->vertexData->vertexCount = numVerts;
sub->useSharedVertices = false;
VertexDeclaration *decl = sub->vertexData->vertexDeclaration;
decl->addElement(nextBuf, 0, VET_FLOAT3, VES_POSITION);
Ogre::VertexDeclaration *decl = sub->vertexData->vertexDeclaration;
decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
HardwareVertexBufferSharedPtr vbuf =
HardwareBufferManager::getSingleton().createVertexBuffer(
VertexElement::getTypeSize(VET_FLOAT3),
numVerts, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false);
Ogre::HardwareVertexBufferSharedPtr vbuf =
Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3),
numVerts, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false);
if(flip)
{
float *datamod = new float[data->vertices.length];
float *datamod = new float[data->vertices.size()];
//std::cout << "Shape" << shape->name.toString() << "\n";
for(int i = 0; i < numVerts; i++)
{
int index = i * 3;
const float *pos = data->vertices.ptr + index;
const float *pos = &data->vertices[index];
Ogre::Vector3 original = Ogre::Vector3(*pos ,*(pos+1), *(pos+2));
original = mTransform * original;
mBoundingBox.merge(original);
@ -388,30 +367,30 @@ void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material, std
}
else
{
vbuf->writeData(0, vbuf->getSizeInBytes(), data->vertices.ptr, false);
vbuf->writeData(0, vbuf->getSizeInBytes(), &data->vertices[0], false);
}
VertexBufferBinding* bind = sub->vertexData->vertexBufferBinding;
Ogre::VertexBufferBinding* bind = sub->vertexData->vertexBufferBinding;
bind->setBinding(nextBuf++, vbuf);
if (data->normals.length)
if (data->normals.size())
{
decl->addElement(nextBuf, 0, VET_FLOAT3, VES_NORMAL);
vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
VertexElement::getTypeSize(VET_FLOAT3),
numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3),
numVerts, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
if(flip)
{
Quaternion rotation = mTransform.extractQuaternion();
Ogre::Quaternion rotation = mTransform.extractQuaternion();
rotation.normalise();
float *datamod = new float[data->normals.length];
float *datamod = new float[data->normals.size()];
for(int i = 0; i < numVerts; i++)
{
int index = i * 3;
const float *pos = data->normals.ptr + index;
const float *pos = &data->normals[index];
Ogre::Vector3 original = Ogre::Vector3(*pos ,*(pos+1), *(pos+2));
original = rotation * original;
if (mNormaliseNormals)
@ -429,49 +408,49 @@ void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material, std
}
else
{
vbuf->writeData(0, vbuf->getSizeInBytes(), data->normals.ptr, false);
vbuf->writeData(0, vbuf->getSizeInBytes(), &data->normals[0], false);
}
bind->setBinding(nextBuf++, vbuf);
}
// Vertex colors
if (data->colors.length)
if (data->colors.size())
{
const float *colors = data->colors.ptr;
RenderSystem* rs = Root::getSingleton().getRenderSystem();
std::vector<RGBA> colorsRGB(numVerts);
RGBA *pColour = &colorsRGB.front();
const float *colors = &data->colors[0];
Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem();
std::vector<Ogre::RGBA> colorsRGB(numVerts);
Ogre::RGBA *pColour = &colorsRGB.front();
for (int i=0; i<numVerts; i++)
{
rs->convertColourValue(ColourValue(colors[0],colors[1],colors[2],
colors[3]),pColour++);
rs->convertColourValue(Ogre::ColourValue(colors[0],colors[1],colors[2],
colors[3]),pColour++);
colors += 4;
}
decl->addElement(nextBuf, 0, VET_COLOUR, VES_DIFFUSE);
vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
VertexElement::getTypeSize(VET_COLOUR),
numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR),
numVerts, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB.front(), true);
bind->setBinding(nextBuf++, vbuf);
}
if (data->uvlist.length)
if (data->uvlist.size())
{
decl->addElement(nextBuf, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES);
vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
VertexElement::getTypeSize(VET_FLOAT2),
numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY,false);
decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2),
numVerts, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,false);
if(flip)
{
float *datamod = new float[data->uvlist.length];
float *datamod = new float[data->uvlist.size()];
for(unsigned int i = 0; i < data->uvlist.length; i+=2){
float x = *(data->uvlist.ptr + i);
for(unsigned int i = 0; i < data->uvlist.size(); i+=2){
float x = data->uvlist[i];
float y = *(data->uvlist.ptr + i + 1);
float y = data->uvlist[i + 1];
datamod[i] =x;
datamod[i + 1] =y;
@ -480,36 +459,34 @@ void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material, std
delete [] datamod;
}
else
vbuf->writeData(0, vbuf->getSizeInBytes(), data->uvlist.ptr, false);
vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[0], false);
bind->setBinding(nextBuf++, vbuf);
}
// Triangle faces - The total number of triangle points
int numFaces = data->triangles.length;
int numFaces = data->triangles.size();
if (numFaces)
{
sub->indexData->indexCount = numFaces;
sub->indexData->indexStart = 0;
HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton().
createIndexBuffer(HardwareIndexBuffer::IT_16BIT,
numFaces,
HardwareBuffer::HBU_STATIC_WRITE_ONLY, true);
Ogre::HardwareIndexBufferSharedPtr ibuf = Ogre::HardwareBufferManager::getSingleton().
createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, numFaces,
Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, true);
if(flip && mFlipVertexWinding && sub->indexData->indexCount % 3 == 0){
sub->indexData->indexBuffer = ibuf;
uint16 *datamod = new uint16[numFaces];
uint16_t *datamod = new uint16_t[numFaces];
int index = 0;
for (size_t i = 0; i < sub->indexData->indexCount; i+=3)
{
const short *pos = data->triangles.ptr + index;
uint16 i0 = (uint16) *(pos+0);
uint16 i1 = (uint16) *(pos+1);
uint16 i2 = (uint16) *(pos+2);
const short *pos = &data->triangles[index];
uint16_t i0 = (uint16_t) *(pos+0);
uint16_t i1 = (uint16_t) *(pos+1);
uint16_t i2 = (uint16_t) *(pos+2);
//std::cout << "i0: " << i0 << "i1: " << i1 << "i2: " << i2 << "\n";
@ -526,7 +503,7 @@ void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material, std
}
else
ibuf->writeData(0, ibuf->getSizeInBytes(), data->triangles.ptr, false);
ibuf->writeData(0, ibuf->getSizeInBytes(), &data->triangles[0], false);
sub->indexData->indexBuffer = ibuf;
}
@ -535,7 +512,7 @@ void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material, std
//add vertex bone assignments
for (std::list<VertexBoneAssignment>::iterator it = vertexBoneAssignments.begin();
for (std::list<Ogre::VertexBoneAssignment>::iterator it = vertexBoneAssignments.begin();
it != vertexBoneAssignments.end(); it++)
{
sub->addBoneAssignment(*it);
@ -546,23 +523,8 @@ void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material, std
// Helper math functions. Reinventing linear algebra for the win!
// Computes B = AxB (matrix*matrix)
static void matrixMul(const Matrix &A, Matrix &B)
{
for (int i=0;i<3;i++)
{
float a = B.v[0].array[i];
float b = B.v[1].array[i];
float c = B.v[2].array[i];
B.v[0].array[i] = a*A.v[0].array[0] + b*A.v[0].array[1] + c*A.v[0].array[2];
B.v[1].array[i] = a*A.v[1].array[0] + b*A.v[1].array[1] + c*A.v[1].array[2];
B.v[2].array[i] = a*A.v[2].array[0] + b*A.v[2].array[1] + c*A.v[2].array[2];
}
}
// Computes C = B + AxC*scale
static void vectorMulAdd(const Matrix &A, const Vector &B, float *C, float scale)
static void vectorMulAdd(const Ogre::Matrix3 &A, const Ogre::Vector3 &B, float *C, float scale)
{
// Keep the original values
float a = C[0];
@ -571,11 +533,11 @@ static void vectorMulAdd(const Matrix &A, const Vector &B, float *C, float scale
// Perform matrix multiplication, scaling and addition
for (int i=0;i<3;i++)
C[i] = B.array[i] + (a*A.v[i].array[0] + b*A.v[i].array[1] + c*A.v[i].array[2])*scale;
C[i] = B[i] + (a*A[i][0] + b*A[i][1] + c*A[i][2])*scale;
}
// Computes B = AxB (matrix*vector)
static void vectorMul(const Matrix &A, float *C)
static void vectorMul(const Ogre::Matrix3 &A, float *C)
{
// Keep the original values
float a = C[0];
@ -584,7 +546,7 @@ static void vectorMul(const Matrix &A, float *C)
// Perform matrix multiplication, scaling and addition
for (int i=0;i<3;i++)
C[i] = a*A.v[i].array[0] + b*A.v[i].array[1] + c*A.v[i].array[2];
C[i] = a*A[i][0] + b*A[i][1] + c*A[i][2];
}
@ -619,7 +581,7 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
return;
// Material name for this submesh, if any
String material;
Ogre::String material;
// Skip the entire material phase for hidden nodes
if (!hidden)
@ -652,14 +614,12 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
}
// Texture
String texName;
Ogre::String texName;
if (t && t->textures[0].inUse)
{
NiSourceTexture *st = t->textures[0].texture.getPtr();
if (st->external)
{
SString tname = st->filename;
/* findRealTexture checks if the file actually
exists. If it doesn't, and the name ends in .tga, it
will try replacing the extension with .dds instead
@ -673,7 +633,7 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
problem since all the nif data is stored in a local
throwaway buffer.
*/
texName = "textures\\" + tname.toString();
texName = "textures\\" + st->filename;
findRealTexture(texName);
}
else warn("Found internal texture, ignoring.");
@ -685,7 +645,7 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
if (a)
{
alphaFlags = a->flags;
alphaTest = a->data->threshold;
alphaTest = a->data.threshold;
}
// Material
@ -700,7 +660,7 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
if (m)
{
// Use NiMaterialProperty data to create the data
const S_MaterialProperty *d = m->data;
const S_MaterialProperty *d = &m->data;
std::multimap<std::string,std::string>::iterator itr = MaterialMap.find(texName);
std::multimap<std::string,std::string>::iterator lastElement;
@ -727,14 +687,8 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
{
// We only have a texture name. Create a default
// material for it.
Vector zero, one;
for (int i=0; i<3;i++)
{
zero.array[i] = 0.0;
one.array[i] = 1.0;
}
createMaterial(material, one, one, zero, zero, 0.0, 1.0,
const Ogre::Vector3 zero(0.0f), one(1.0f);
createMaterial(material, one, one, zero, zero, 0.0f, 1.0f,
alphaFlags, alphaTest, texName, shape->data->colors.length != 0);
}
}
@ -747,12 +701,12 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
level.
*/
NiTriShapeData *data = shape->data.getPtr();
int numVerts = data->vertices.length / 3;
int numVerts = data->vertices.size() / 3;
float *ptr = (float*)data->vertices.ptr;
float *ptr = (float*)&data->vertices[0];
float *optr = ptr;
std::list<VertexBoneAssignment> vertexBoneAssignments;
std::list<Ogre::VertexBoneAssignment> vertexBoneAssignments;
Nif::NiTriShapeCopy copy = shape->clone();
@ -780,14 +734,14 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
std::vector<Ogre::Vector3> vertexPosOriginal(numVerts, Ogre::Vector3::ZERO);
std::vector<Ogre::Vector3> vertexNormalOriginal(numVerts, Ogre::Vector3::ZERO);
float *ptrNormals = (float*)data->normals.ptr;
float *ptrNormals = (float*)&data->normals[0];
//the bone from skin->bones[boneIndex] is linked to skin->data->bones[boneIndex]
//the first one contains a link to the bone, the second vertex transformation
//relative to the bone
int boneIndex = 0;
Bone *bonePtr;
Vector3 vecPos;
Quaternion vecRot;
Ogre::Bone *bonePtr;
Ogre::Vector3 vecPos;
Ogre::Quaternion vecRot;
std::vector<NiSkinData::BoneInfo> boneList = shape->skin->data->bones;
@ -801,33 +755,33 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
{
if(mSkel.isNull())
{
std::cout << "No skeleton for :" << shape->skin->bones[boneIndex].name.toString() << std::endl;
std::cout << "No skeleton for :" << shape->skin->bones[boneIndex].name << std::endl;
break;
}
//get the bone from bones array of skindata
if(!mSkel->hasBone(shape->skin->bones[boneIndex].name.toString()))
if(!mSkel->hasBone(shape->skin->bones[boneIndex].name))
std::cout << "We don't have this bone";
bonePtr = mSkel->getBone(shape->skin->bones[boneIndex].name.toString());
bonePtr = mSkel->getBone(shape->skin->bones[boneIndex].name);
// final_vector = old_vector + old_rotation*new_vector*old_scale
Nif::NiSkinData::BoneInfoCopy boneinfocopy;
boneinfocopy.trafo.rotation = convertRotation(it->trafo->rotation);
boneinfocopy.trafo.trans = convertVector3(it->trafo->trans);
boneinfocopy.bonename = shape->skin->bones[boneIndex].name.toString();
boneinfocopy.trafo.rotation = it->trafo.rotation;
boneinfocopy.trafo.trans = it->trafo.trans;
boneinfocopy.bonename = shape->skin->bones[boneIndex].name;
boneinfocopy.bonehandle = bonePtr->getHandle();
copy.boneinfo.push_back(boneinfocopy);
for (unsigned int i=0; i<it->weights.length; i++)
for (unsigned int i=0; i<it->weights.size(); i++)
{
vecPos = bonePtr->_getDerivedPosition() +
bonePtr->_getDerivedOrientation() * convertVector3(it->trafo->trans);
bonePtr->_getDerivedOrientation() * it->trafo.trans;
vecRot = bonePtr->_getDerivedOrientation() * convertRotation(it->trafo->rotation);
unsigned int verIndex = (it->weights.ptr + i)->vertex;
vecRot = bonePtr->_getDerivedOrientation() * it->trafo.rotation;
unsigned int verIndex = it->weights[i].vertex;
//boneinfo.weights.push_back(*(it->weights.ptr + i));
Nif::NiSkinData::IndividualWeight ind;
ind.weight = (it->weights.ptr + i)->weight;
ind.weight = it->weights[i].weight;
ind.boneinfocopyindex = copy.boneinfo.size() - 1;
if(copy.vertsToWeights.find(verIndex) == copy.vertsToWeights.end())
{
@ -844,9 +798,9 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
if (vertexPosAbsolut[verIndex] == false)
{
//apply transformation to the vertices
Vector3 absVertPos = vecPos + vecRot * Vector3(ptr + verIndex *3);
absVertPos = absVertPos * (it->weights.ptr + i)->weight;
vertexPosOriginal[verIndex] = Vector3(ptr + verIndex *3);
Ogre::Vector3 absVertPos = vecPos + vecRot * Ogre::Vector3(ptr + verIndex *3);
absVertPos = absVertPos * it->weights[i].weight;
vertexPosOriginal[verIndex] = Ogre::Vector3(ptr + verIndex *3);
mBoundingBox.merge(absVertPos);
//convert it back to float *
@ -855,11 +809,11 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
//apply rotation to the normals (not every vertex has a normal)
//FIXME: I guessed that vertex[i] = normal[i], is that true?
if (verIndex < data->normals.length)
if (verIndex < data->normals.size())
{
Vector3 absNormalsPos = vecRot * Vector3(ptrNormals + verIndex *3);
absNormalsPos = absNormalsPos * (it->weights.ptr + i)->weight;
vertexNormalOriginal[verIndex] = Vector3(ptrNormals + verIndex *3);
Ogre::Vector3 absNormalsPos = vecRot * Ogre::Vector3(ptrNormals + verIndex *3);
absNormalsPos = absNormalsPos * it->weights[i].weight;
vertexNormalOriginal[verIndex] = Ogre::Vector3(ptrNormals + verIndex *3);
for (int j=0; j<3; j++)
(ptrNormals + verIndex*3)[j] = absNormalsPos[j];
@ -869,9 +823,9 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
}
else
{
Vector3 absVertPos = vecPos + vecRot * vertexPosOriginal[verIndex];
absVertPos = absVertPos * (it->weights.ptr + i)->weight;
Vector3 old = Vector3(ptr + verIndex *3);
Ogre::Vector3 absVertPos = vecPos + vecRot * vertexPosOriginal[verIndex];
absVertPos = absVertPos * it->weights[i].weight;
Ogre::Vector3 old = Ogre::Vector3(ptr + verIndex *3);
absVertPos = absVertPos + old;
mBoundingBox.merge(absVertPos);
@ -881,11 +835,11 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
//apply rotation to the normals (not every vertex has a normal)
//FIXME: I guessed that vertex[i] = normal[i], is that true?
if (verIndex < data->normals.length)
if (verIndex < data->normals.size())
{
Vector3 absNormalsPos = vecRot * vertexNormalOriginal[verIndex];
absNormalsPos = absNormalsPos * (it->weights.ptr + i)->weight;
Vector3 oldNormal = Vector3(ptrNormals + verIndex *3);
Ogre::Vector3 absNormalsPos = vecRot * vertexNormalOriginal[verIndex];
absNormalsPos = absNormalsPos * it->weights[i].weight;
Ogre::Vector3 oldNormal = Ogre::Vector3(ptrNormals + verIndex *3);
absNormalsPos = absNormalsPos + oldNormal;
for (int j=0; j<3; j++)
@ -894,10 +848,10 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
}
VertexBoneAssignment vba;
Ogre::VertexBoneAssignment vba;
vba.boneIndex = bonePtr->getHandle();
vba.vertexIndex = verIndex;
vba.weight = (it->weights.ptr + i)->weight;
vba.weight = it->weights[i].weight;
vertexBoneAssignments.push_back(vba);
@ -914,12 +868,12 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
copy.boneSequence = boneSequence;
// Rotate, scale and translate all the vertices,
const Matrix &rot = shape->trafo->rotation;
const Vector &pos = shape->trafo->pos;
float scale = shape->trafo->scale;
const Ogre::Matrix3 &rot = shape->trafo.rotation;
const Ogre::Vector3 &pos = shape->trafo.pos;
float scale = shape->trafo.scale;
copy.trafo.trans = convertVector3(original.pos);
copy.trafo.rotation = convertRotation(original.rotation);
copy.trafo.trans = original.pos;
copy.trafo.rotation = original.rotation;
copy.trafo.scale = original.scale;
//We don't use velocity for anything yet, so it does not need to be saved
@ -927,15 +881,15 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
for (int i=0; i<numVerts; i++)
{
vectorMulAdd(rot, pos, ptr, scale);
Ogre::Vector3 absVertPos = Ogre::Vector3(*(ptr + 3 * i), *(ptr + 3 * i + 1), *(ptr + 3 * i + 2));
Ogre::Vector3 absVertPos = Ogre::Vector3(ptr);
mBoundingBox.merge(absVertPos);
ptr += 3;
}
// Remember to rotate all the vertex normals as well
if (data->normals.length)
if (data->normals.size())
{
ptr = (float*)data->normals.ptr;
ptr = (float*)&data->normals[0];
for (int i=0; i<numVerts; i++)
{
vectorMul(rot, ptr);
@ -947,7 +901,7 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
boneIndex = mSkel->getNumBones() - 1;
for(int i = 0; i < numVerts; i++){
VertexBoneAssignment vba;
Ogre::VertexBoneAssignment vba;
vba.boneIndex = boneIndex;
vba.vertexIndex = i;
vba.weight = 1;
@ -971,15 +925,15 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
void NIFLoader::calculateTransform()
{
// Calculate transform
Matrix4 transform = Matrix4::IDENTITY;
transform = Matrix4::getScale(vector) * transform;
Ogre::Matrix4 transform = Ogre::Matrix4::IDENTITY;
transform = Ogre::Matrix4::getScale(vector) * transform;
// Check whether we have to flip vertex winding.
// We do have to, if we changed our right hand base.
// We can test it by using the cross product from X and Y and see, if it is a non-negative
// projection on Z. Actually it should be exactly Z, as we don't do non-uniform scaling yet,
// but the test is cheap either way.
Matrix3 m3;
Ogre::Matrix3 m3;
transform.extract3x3Matrix(m3);
if (m3.GetColumn(0).crossProduct(m3.GetColumn(1)).dotProduct(m3.GetColumn(2)) < 0)
@ -1042,7 +996,7 @@ void NIFLoader::handleNode(Nif::Node *node, int flags,
for(std::vector<Nif::NiTextKeyExtraData::TextKey>::iterator textiter = extra->list.begin(); textiter != extra->list.end(); textiter++)
{
std::string text = textiter->text.toString();
std::string text = textiter->text;
replace(text.begin(), text.end(), '\n', '/');
@ -1073,7 +1027,7 @@ void NIFLoader::handleNode(Nif::Node *node, int flags,
}
}
Bone *bone = 0;
Ogre::Bone *bone = 0;
// create skeleton or add bones
if (node->recType == RC_NiNode)
@ -1083,14 +1037,14 @@ void NIFLoader::handleNode(Nif::Node *node, int flags,
{
inTheSkeletonTree = true;
mSkel = SkeletonManager::getSingleton().create(getSkeletonName(), resourceGroup, true);
mSkel = Ogre::SkeletonManager::getSingleton().create(getSkeletonName(), resourceGroup, true);
}
else if (!mSkel.isNull() && !parentBone)
inTheSkeletonTree = false;
if (!mSkel.isNull()) //if there is a skeleton
{
std::string name = node->name.toString();
std::string name = node->name;
// Quick-n-dirty workaround for the fact that several
// bones may have the same name.
@ -1103,30 +1057,29 @@ void NIFLoader::handleNode(Nif::Node *node, int flags,
parentBone->addChild(bone);
bone->setInheritOrientation(true);
bone->setPosition(convertVector3(node->trafo->pos));
bone->setOrientation(convertRotation(node->trafo->rotation));
bone->setPosition(node->trafo.pos);
bone->setOrientation(node->trafo.rotation);
}
}
}
Transformation original = *(node->trafo);
Transformation original = node->trafo;
// Apply the parent transformation to this node. We overwrite the
// existing data with the final transformation.
if (trafo)
{
// Get a non-const reference to the node's data, since we're
// overwriting it. TODO: Is this necessary?
Transformation &final = *((Transformation*)node->trafo);
Transformation &final = node->trafo;
// For both position and rotation we have that:
// final_vector = old_vector + old_rotation*new_vector*old_scale
vectorMulAdd(trafo->rotation, trafo->pos, final.pos.array, trafo->scale);
vectorMulAdd(trafo->rotation, trafo->velocity, final.velocity.array, 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
matrixMul(trafo->rotation, final.rotation);
final.rotation = trafo->rotation * final.rotation;
// Scalar values are so nice to deal with. Why can't everything
// just be scalar?
// Scale
final.scale *= trafo->scale;
}
@ -1139,12 +1092,12 @@ void NIFLoader::handleNode(Nif::Node *node, int flags,
{
if (list.has(i))
handleNode(&list[i], flags, node->trafo, bounds, bone, boneSequence);
handleNode(&list[i], flags, &node->trafo, bounds, bone, boneSequence);
}
}
else if (node->recType == RC_NiTriShape && bNiTri)
{
std::string nodename = node->name.toString();
std::string nodename = node->name;
if (triname == "")
{
@ -1159,7 +1112,7 @@ void NIFLoader::handleNode(Nif::Node *node, int flags,
}
}
void NIFLoader::loadResource(Resource *resource)
void NIFLoader::loadResource(Ogre::Resource *resource)
{
inTheSkeletonTree = false;
allanim.clear();
@ -1245,22 +1198,13 @@ void NIFLoader::loadResource(Resource *resource)
{
calculateTransform();
}
// Set up the VFS if it hasn't been done already
if (!vfs) vfs = new OgreVFS(resourceGroup);
// Get the mesh
mesh = dynamic_cast<Mesh*>(resource);
mesh = dynamic_cast<Ogre::Mesh*>(resource);
assert(mesh);
// Look it up
resourceName = mesh->getName();
//std::cout << resourceName << "\n";
if (!vfs->isFile(resourceName))
{
warn("File "+resourceName+" not found.");
return;
}
// Helper that computes bounding boxes for us.
BoundsFinder bounds;
@ -1269,8 +1213,7 @@ void NIFLoader::loadResource(Resource *resource)
// of the early stages of development. Right now we WANT to catch
// every error as early and intrusively as possible, as it's most
// likely a sign of incomplete code rather than faulty input.
NIFFile nif(vfs->open(resourceName), resourceName);
NIFFile nif(resourceName);
if (nif.numRecords() < 1)
{
warn("Found no records in NIF.");
@ -1286,7 +1229,7 @@ void NIFLoader::loadResource(Resource *resource)
if (node == NULL)
{
warn("First record in file was not a node, but a " +
r->recName.toString() + ". Skipping file.");
r->recName + ". Skipping file.");
return;
}
@ -1310,7 +1253,7 @@ void NIFLoader::loadResource(Resource *resource)
if (f->timeStart >= 10000000000000000.0f)
continue;
data->setBonename(o->name.toString());
data->setBonename(o->name);
data->setStartTime(f->timeStart);
data->setStopTime(f->timeStop);
@ -1321,8 +1264,8 @@ void NIFLoader::loadResource(Resource *resource)
// set the bounding value.
if (bounds.isValid())
{
mesh->_setBounds(AxisAlignedBox(bounds.minX(), bounds.minY(), bounds.minZ(),
bounds.maxX(), bounds.maxY(), bounds.maxZ()));
mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX(), bounds.minY(), bounds.minZ(),
bounds.maxX(), bounds.maxY(), bounds.maxZ()));
mesh->_setBoundingSphereRadius(bounds.getRadius());
}
if(hasAnim && addAnim){
@ -1344,7 +1287,7 @@ void NIFLoader::loadResource(Resource *resource)
for(std::vector<Ogre::SubMesh*>::iterator iter = needBoneAssignments.begin(); iter != needBoneAssignments.end(); iter++)
{
int boneIndex = mSkel->getNumBones() - 1;
VertexBoneAssignment vba;
Ogre::VertexBoneAssignment vba;
vba.boneIndex = boneIndex;
vba.vertexIndex = 0;
vba.weight = 1;
@ -1363,20 +1306,19 @@ void NIFLoader::loadResource(Resource *resource)
MeshPtr NIFLoader::load(const std::string &name,
const std::string &group)
Ogre::MeshPtr NIFLoader::load(const std::string &name, const std::string &group)
{
MeshManager *m = MeshManager::getSingletonPtr();
Ogre::MeshManager *m = Ogre::MeshManager::getSingletonPtr();
// Check if the resource already exists
ResourcePtr ptr = m->getByName(name, group);
MeshPtr themesh;
Ogre::ResourcePtr ptr = m->getByName(name, group);
Ogre::MeshPtr themesh;
if (!ptr.isNull()){
themesh = MeshPtr(ptr);
themesh = Ogre::MeshPtr(ptr);
}
else // Nope, create a new one.
{
themesh = MeshManager::getSingleton().createManual(name, group, NIFLoader::getSingletonPtr());
themesh = Ogre::MeshManager::getSingleton().createManual(name, group, NIFLoader::getSingletonPtr());
}
return themesh;
}

@ -62,17 +62,8 @@ namespace Nif
class Node;
class Transformation;
class NiTriShape;
class Vector;
class Matrix;
}
namespace Mangle
{
namespace VFS
{
class OgreVFS;
}
}
namespace NifOgre
{
@ -110,9 +101,6 @@ class NIFLoader : Ogre::ManualResourceLoader
std::map<std::string, float>* getTextIndices(std::string name);
Ogre::Vector3 convertVector3(const Nif::Vector& vec);
Ogre::Quaternion convertRotation(const Nif::Matrix& rot);
void setOutputAnimFiles(bool output);
void setVerbosePath(std::string path);
@ -136,10 +124,10 @@ class NIFLoader : Ogre::ManualResourceLoader
void createOgreSubMesh(Nif::NiTriShape *shape, const Ogre::String &material, std::list<Ogre::VertexBoneAssignment> &vertexBoneAssignments);
void createMaterial(const Ogre::String &name,
const Nif::Vector &ambient,
const Nif::Vector &diffuse,
const Nif::Vector &specular,
const Nif::Vector &emissive,
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,
@ -155,13 +143,6 @@ class NIFLoader : Ogre::ManualResourceLoader
return resourceName + ".skel";
}
// This is the interface to the Ogre resource system. It allows us to
// load NIFs from BSAs, in the file system and in any other place we
// tell Ogre to look (eg. in zip or rar files.) It's also used to
// check for the existence of texture files, so we can exchange the
// extension from .tga to .dds if the texture is missing.
Mangle::VFS::OgreVFS *vfs;
std::string verbosePath;
std::string resourceName;
std::string resourceGroup;

@ -0,0 +1,58 @@
CREDITS
Current Developers:
Aleksandar Jovanov
Alexander “Ace” Olofsson
athile
BrotherBrick
Cris “Mirceam” Mihalache
gugus / gus
Jacob “Yacoby” Essex
Jannik “scrawl” Heller
Jason “jhooks” Hooks
Karl-Felix “k1ll” Glatzer
Lukasz “lgro” Gromanowski
Marc “Zini” Zinnschlag
Michael “werdanith” Papageorgiou
Nikolay “corristo” Kasyanov
Pieter “pvdk” van der Kloet
Roman "Kromgart" Melnik
Sebastian “swick” Wick
Sylvain "Garvek" T.
Retired Developers:
Ardekantur
Armin Preiml
Diggory Hardy
Jan Borsodi
Jan-Peter “peppe” Nilsson
Josua Grawitter
Nicolay Korslund
sergoz
Star-Demon
Yuri Krupenin
PR team and Translators:
Julien (jvoisin/ap0) Voisin
sirherrbatka
ElderTroll
spyboot
corristo
Okulo
penguinroad
Kingpix
Reverser and Research:
natirips
Sadler
fragonard
Greendogo
Myckel
modred11
HiPhish
OpenMW:
Thanks to DokterDume for kindly providing us with the Moon and Star logo used as the application icon and project logo.
Launcher:
Thanks to Kevin Ryan for kindly providing us with the icon used for the Data Files tab.

@ -4,9 +4,8 @@
PluginFolder=${OGRE_PLUGIN_DIR_REL}
# Define plugins
Plugin=RenderSystem_GL
Plugin=Plugin_ParticleFX
Plugin=Plugin_OctreeSceneManager
Plugin=Plugin_CgProgramManager
Plugin=RenderSystem_GL${DEBUG_SUFFIX}
Plugin=Plugin_ParticleFX${DEBUG_SUFFIX}
Plugin=Plugin_OctreeSceneManager${DEBUG_SUFFIX}
Plugin=Plugin_CgProgramManager${DEBUG_SUFFIX}

@ -4,9 +4,9 @@
PluginFolder=${OGRE_PLUGIN_DIR}
# Define plugins
Plugin=RenderSystem_GL.1.8.0
Plugin=Plugin_ParticleFX.1.8.0
Plugin=Plugin_OctreeSceneManager.1.8.0
Plugin=Plugin_CgProgramManager.1.8.0
Plugin=RenderSystem_GL${DEBUG_SUFFIX}.1.8.0
Plugin=Plugin_ParticleFX${DEBUG_SUFFIX}.1.8.0
Plugin=Plugin_OctreeSceneManager${DEBUG_SUFFIX}.1.8.0
Plugin=Plugin_CgProgramManager${DEBUG_SUFFIX}.1.8.0

@ -4,10 +4,10 @@
PluginFolder=.\
# Define plugins
Plugin=RenderSystem_Direct3D9
Plugin=RenderSystem_GL
Plugin=Plugin_ParticleFX
Plugin=Plugin_OctreeSceneManager
Plugin=Plugin_CgProgramManager
Plugin=RenderSystem_Direct3D9${DEBUG_SUFFIX}
Plugin=RenderSystem_GL${DEBUG_SUFFIX}
Plugin=Plugin_ParticleFX${DEBUG_SUFFIX}
Plugin=Plugin_OctreeSceneManager${DEBUG_SUFFIX}
Plugin=Plugin_CgProgramManager${DEBUG_SUFFIX}

@ -333,11 +333,18 @@ namespace Physic
RigidBody* PhysicEngine::createRigidBody(std::string mesh,std::string name,float scale)
{
char uniqueID[8];
sprintf( uniqueID, "%07.3f", scale );
std::string sid = uniqueID;
std::string outputstring = mesh + uniqueID + "\"|";
//std::cout << "The string" << outputstring << "\n";
//get the shape from the .nif
mShapeLoader->load(mesh,"General");
BulletShapeManager::getSingletonPtr()->load(mesh,"General");
BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(mesh,"General");
shape->Shape->setLocalScaling(btVector3(scale,scale,scale));
mShapeLoader->load(outputstring,"General");
BulletShapeManager::getSingletonPtr()->load(outputstring,"General");
BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General");
shape->Shape->setLocalScaling( btVector3(scale,scale,scale));
//btScaledBvhTriangleMeshShape* scaled = new btScaledBvhTriangleMeshShape(dynamic_cast<btBvhTriangleMeshShape*> (shape->Shape), btVector3(scale,scale,scale));
//create the motionState
CMotionState* newMotionState = new CMotionState(this,name);
@ -400,18 +407,32 @@ namespace Physic
if (it != RigidBodyMap.end() )
{
RigidBody* body = it->second;
//btScaledBvhTriangleMeshShape* scaled = dynamic_cast<btScaledBvhTriangleMeshShape*> (body->getCollisionShape());
if(body != NULL)
{
delete body;
}
/*if(scaled != NULL)
{
delete scaled;
}*/
RigidBodyMap.erase(it);
}
}
RigidBody* PhysicEngine::getRigidBody(std::string name)
{
RigidBody* body = RigidBodyMap[name];
return body;
RigidBodyContainer::iterator it = RigidBodyMap.find(name);
if (it != RigidBodyMap.end() )
{
RigidBody* body = RigidBodyMap[name];
return body;
}
else
{
return 0;
}
}
void PhysicEngine::stepSimulation(double deltaT)
@ -468,8 +489,16 @@ namespace Physic
PhysicActor* PhysicEngine::getCharacter(std::string name)
{
PhysicActor* act = PhysicActorMap[name];
return act;
PhysicActorContainer::iterator it = PhysicActorMap.find(name);
if (it != PhysicActorMap.end() )
{
PhysicActor* act = PhysicActorMap[name];
return act;
}
else
{
return 0;
}
}
void PhysicEngine::emptyEventLists(void)

@ -7,6 +7,7 @@
#include <list>
#include <map>
#include "BulletShapeLoader.h"
#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h"
class btRigidBody;
class btBroadphaseInterface;

@ -229,7 +229,7 @@ bool PM_SlideMove( bool gravity )
end = pm->ps.origin + pm->ps.velocity * time_left;
// see if we can make it there
//pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask);
//pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemaskg);
//tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&(end), *(const D3DXVECTOR3* const)&(pm->ps.velocity), 0, pml.traceObj);
newtrace(&trace, pm->ps.origin, end, halfExtents, Ogre::Math::DegreesToRadians (pm->ps.viewangles.y), pm->isInterior, pm->mEngine);
@ -274,7 +274,7 @@ bool PM_SlideMove( bool gravity )
{
// pm->ps->velocity += (trace.plane.normal + pm->ps->velocity)
//VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity );
pm->ps.velocity = (trace.planenormal + pm->ps.velocity);
pm->ps.velocity = trace.planenormal + pm->ps.velocity;
break;
}
}
@ -298,6 +298,12 @@ bool PM_SlideMove( bool gravity )
if ( into >= 0.1 )
continue; // move doesn't interact with the plane
if(planes[i].x >= .70)
{
pm->ps.velocity = Ogre::Vector3(0,0,0);
return true;
}
// see how hard we are hitting things
if ( -into > pml.impactSpeed )
pml.impactSpeed = -into;
@ -318,6 +324,13 @@ bool PM_SlideMove( bool gravity )
if (clipVelocity.dotProduct(planes[j]) >= 0.1)
//if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 )
continue; // move doesn't interact with the plane
//pm->ps.velocity = Ogre::Vector3(0,0,0);
//return true;
// try clipping the move to the plane
PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
@ -327,8 +340,8 @@ bool PM_SlideMove( bool gravity )
if (clipVelocity.dotProduct(planes[i]) >= 0)
//if ( DotProduct( clipVelocity, planes[i] ) >= 0 )
continue;
// slide the original velocity along the crease
//dProduct (planes[i], planes[j], dir);
dir = planes[i].crossProduct(planes[j]) ;
@ -360,6 +373,7 @@ bool PM_SlideMove( bool gravity )
// see if there is a third plane the the new move enters
for ( k = 0 ; k < numplanes ; k++ )
{
if ( k == i || k == j )
continue;
@ -513,7 +527,7 @@ int PM_StepSlideMove( bool gravity )
delta = pm->ps.origin.z - start_o.z;
if ( delta > 2 )
{
pm->ps.counter = 10;
pm->ps.counter = 5;
/*
if (gravity)
@ -844,6 +858,8 @@ static void PM_WalkMove( playerMove* const pmove )
float accelerate;
float vel;
//pm->ps.gravity = 4000;
//std::cout << "Player is walking\n";
if ( pm->ps.waterlevel > 2 && //DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 )
pml.forward.dotProduct(pml.groundTrace.planenormal) > 0.0f)
@ -1145,6 +1161,10 @@ void PM_GroundTraceMissed()
{
traceResults trace;
Ogre::Vector3 point;
//We should not have significant upwards velocity when in the air, unless we jumped.
//This code protects against flying into the air when moving at high speeds.
//Z velocity is set to 50, instead of 0, to help move up certain steps.
//std::cout << "Ground trace missed\n";
// we just transitioned into freefall
//if ( pm->debugLevel )
@ -1407,10 +1427,13 @@ static void PM_GroundTrace( void )
// if the trace didn't hit anything, we are in free fall
if ( trace.fraction == 1.0)
{
if(pm->ps.velocity.z > 50.0f && pm->ps.bSnap && pm->ps.speed > 1000.0f)
pm->ps.velocity.z = 50.0f;
if(pm->ps.snappingImplemented){
if(pm->ps.bSnap && pm->ps.counter <= 0)
PM_GroundTraceMissed();
}
return;
@ -1457,6 +1480,7 @@ static void PM_GroundTrace( void )
// slopes that are too steep will not be considered onground
//if ( trace.plane.normal[2] < MIN_WALK_NORMAL )
//std::cout << "MinWalkNormal" << trace.planenormal.z;
if (trace.planenormal.z < MIN_WALK_NORMAL)
{
//if ( pm->debugLevel )
@ -1569,8 +1593,11 @@ void PM_AirMove()
else
PM_SlideMove ( qtrue );
#endif*/
//std::cout << "Moving in the air" << pm->ps.velocity << "\n";
/*bprintf("%i ", */PM_StepSlideMove ( true )/* )*/;
}
static void PM_NoclipMove( void )

@ -28,7 +28,7 @@ static const Ogre::Vector3 halfExtents(14.64f * 2, 14.24f * 2, 33.25f * 2);
#define MAX_CLIP_PLANES 5
#define OVERCLIP 1.001f
//#define STEPSIZE 18 // 18 is way too much
#define STEPSIZE (18 / 2)
#define STEPSIZE (9)
#ifndef M_PI
#define M_PI 3.14159265358979323846f
#endif
@ -41,7 +41,7 @@ static const Ogre::Vector3 halfExtents(14.64f * 2, 14.24f * 2, 33.25f * 2);
#define MAX_GENTITIES (1 << GENTITYNUM_BITS)
#define ENTITYNUM_NONE (MAX_GENTITIES - 1)
#define ENTITYNUM_WORLD (MAX_GENTITIES - 2)
#define MIN_WALK_NORMAL 0.7f // can't walk on very steep slopes
#define MIN_WALK_NORMAL .7f // can't walk on very steep slopes
#define JUMP_VELOCITY (270)
#define PS_PMOVEFRAMECOUNTBITS 6
#define MINS_Z -24

@ -12,8 +12,6 @@ EBGaramond-Regular.ttf: OFL (see OFL.txt for more information)
VeraMono.ttf: custom (see Bitstream Vera License.txt for more information)
THIS IS A WORK IN PROGRESS
INSTALLATION
@ -90,47 +88,6 @@ Allowed options:
--fallback arg fallback values
CREDITS
Current Developers:
Aleksandar Jovanov
Alexander “Ace” Olofsson
athile
BrotherBrick
Cris “Mirceam” Mihalache
gugus / gus
Jacob “Yacoby” Essex
Jannik “scrawl” Heller
Jason “jhooks” Hooks
Karl-Felix “k1ll” Glatzer
Lukasz “lgro” Gromanowski
Marc “Zini” Zinnschlag
Michael “werdanith” Papageorgiou
Nikolay “corristo” Kasyanov
Pieter “pvdk” van der Kloet
Roman "Kromgart" Melnik
Sebastian “swick” Wick
Sylvain "Garvek" T.
Retired Developers:
Ardekantur
Armin Preiml
Diggory Hardy
Jan Borsodi
Jan-Peter “peppe” Nilsson
Josua Grawitter
Nicolay Korslund
sergoz
Star-Demon
Yuri Krupenin
OpenMW:
Thanks to DokterDume for kindly providing us with the Moon and Star logo used as the application icon and project logo.
Launcher:
Thanks to Kevin Ryan for kindly providing us with the icon used for the Data Files tab.
CHANGELOG
0.16.0
@ -215,7 +172,6 @@ Task #113: Morrowind.ini Importer
Task #215: Refactor the sound code
Task #216: Update MyGUI
0.13.0
Bug #145: Fixed sound problems after cell change
@ -273,7 +229,6 @@ Task #131: NPC Activation doesn't work properly
Task #144: MWRender cleanup
Task #155: cmake cleanup
0.11.1
Bug #2: Resources loading doesn't work outside of bsa files
@ -300,4 +255,95 @@ Task #14: Replace tabs with 4 spaces
Task #18: Move components from global namespace into their own namespace
Task #123: refactor header files in components/esm
TODO add old changelog (take pre 0.11.1 changelog from wiki)
0.10.0
* NPC dialogue window (not functional yet)
* Collisions with objects
* Refactor the PlayerPos class
* Adjust file locations
* CMake files and test linking for Bullet
* Replace Ogre raycasting test for activation with something more precise
* Adjust player movement according to collision results
* FPS display
* Various Portability Improvements
* Mac OS X support is back!
0.9.0
* Exterior cells loading, unloading and management
* Character Creation GUI
* Character creation
* Make cell names case insensitive when doing internal lookups
* Music player
* NPCs rendering
0.8.0
* GUI
* Complete and working script engine
* In game console
* Sky rendering
* Sound and music
* Tons of smaller stuff
0.7.0
* This release is a complete rewrite in C++.
* All D code has been culled, and all modules have been rewritten.
* The game is now back up to the level of rendering interior cells and moving around, but physics, sound, GUI, and scripting still remain to be ported from the old codebase.
0.6.0
* Coded a GUI system using MyGUI
* Skinned MyGUI to look like Morrowind (work in progress)
* Integrated the Monster script engine
* Rewrote some functions into script code
* Very early MyGUI < > Monster binding
* Fixed Windows sound problems (replaced old openal32.dll)
0.5.0
* Collision detection with Bullet
* Experimental walk & fall character physics
* New key bindings:
* t toggle physics mode (walking, flying, ghost),
* n night eye, brightens the scene
* Fixed incompatability with DMD 1.032 and newer compilers
* * (thanks to tomqyp)
* Various minor changes and updates
0.4.0
* Switched from Audiere to OpenAL
* * (BIG thanks to Chris Robinson)
* Added complete Makefile (again) as a alternative build tool
* More realistic lighting (thanks again to Chris Robinson)
* Various localization fixes tested with Russian and French versions
* Temporary workaround for the Unicode issue: invalid UTF displayed as '?'
* Added ns option to disable sound, for debugging
* Various bug fixes
* Cosmetic changes to placate gdc Wall
0.3.0
* Built and tested on Windows XP
* Partial support for FreeBSD (exceptions do not work)
* You no longer have to download Monster separately
* Made an alternative for building without DSSS (but DSSS still works)
* Renamed main program from 'morro' to 'openmw'
* Made the config system more robust
* Added oc switch for showing Ogre config window on startup
* Removed some config files, these are auto generated when missing.
* Separated plugins.cfg into linux and windows versions.
* Updated Makefile and sources for increased portability
* confirmed to work against OIS 1.0.0 (Ubuntu repository package)
0.2.0
* Compiles with gdc
* Switched to DSSS for building D code
* Includes the program esmtool
0.1.0
first release

Loading…
Cancel
Save