mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-30 13:57:59 +03:00
Imported Upstream version 0.26.0
This commit is contained in:
commit
9a2b6c69b6
1398 changed files with 212217 additions and 0 deletions
12
libs/openengine/README
Normal file
12
libs/openengine/README
Normal file
|
@ -0,0 +1,12 @@
|
|||
OpenEngine README
|
||||
=================
|
||||
|
||||
OpenEngine is a bunch of stand-alone game engine modules collected from the OpenMW project (see http://github.com/korslund/openmw or http://openmw.com ) and from certain other projects.
|
||||
|
||||
It is currently a very early work in progress, and development will follow OpenMW closely for a while forward.
|
||||
|
||||
OpenEngine will depend heavily on Mangle ( http://github.com/korslund/mangle/ ) and will thus aim to be backend agnostic. When finished it should work with a variety for free and commercial middleware libraries as backends for graphics, sound, physics, input and so on.
|
||||
|
||||
All questions can be directed to Nicolay Korslund at korslund@gmail.com
|
||||
|
||||
- Nicolay
|
1094
libs/openengine/bullet/BtOgre.cpp
Normal file
1094
libs/openengine/bullet/BtOgre.cpp
Normal file
File diff suppressed because it is too large
Load diff
282
libs/openengine/bullet/BtOgreExtras.h
Normal file
282
libs/openengine/bullet/BtOgreExtras.h
Normal file
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: BtOgreExtras.h
|
||||
*
|
||||
* Description: Contains the Ogre Mesh to Bullet Shape converters.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 27/12/2008 01:45:56 PM
|
||||
*
|
||||
* Author: Nikhilesh (nikki)
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef _BtOgreShapes_H_
|
||||
#define _BtOgreShapes_H_
|
||||
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
#include "OgreSimpleRenderable.h"
|
||||
#include "OgreCamera.h"
|
||||
#include "OgreHardwareBufferManager.h"
|
||||
#include "OgreMaterialManager.h"
|
||||
#include "OgreTechnique.h"
|
||||
#include "OgrePass.h"
|
||||
|
||||
#include "OgreLogManager.h"
|
||||
|
||||
namespace BtOgre
|
||||
{
|
||||
|
||||
typedef std::vector<Ogre::Vector3> Vector3Array;
|
||||
|
||||
//Converts from and to Bullet and Ogre stuff. Pretty self-explanatory.
|
||||
class Convert
|
||||
{
|
||||
public:
|
||||
Convert() {};
|
||||
~Convert() {};
|
||||
|
||||
static btQuaternion toBullet(const Ogre::Quaternion &q)
|
||||
{
|
||||
return btQuaternion(q.x, q.y, q.z, q.w);
|
||||
}
|
||||
static btVector3 toBullet(const Ogre::Vector3 &v)
|
||||
{
|
||||
return btVector3(v.x, v.y, v.z);
|
||||
}
|
||||
|
||||
static Ogre::Quaternion toOgre(const btQuaternion &q)
|
||||
{
|
||||
return Ogre::Quaternion(q.w(), q.x(), q.y(), q.z());
|
||||
}
|
||||
static Ogre::Vector3 toOgre(const btVector3 &v)
|
||||
{
|
||||
return Ogre::Vector3(v.x(), v.y(), v.z());
|
||||
}
|
||||
};
|
||||
|
||||
//From here on its debug-drawing stuff. ------------------------------------------------------------------
|
||||
|
||||
class DynamicRenderable : public Ogre::SimpleRenderable
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
DynamicRenderable();
|
||||
/// Virtual destructor
|
||||
virtual ~DynamicRenderable();
|
||||
|
||||
/** Initializes the dynamic renderable.
|
||||
@remarks
|
||||
This function should only be called once. It initializes the
|
||||
render operation, and calls the abstract function
|
||||
createVertexDeclaration().
|
||||
@param operationType The type of render operation to perform.
|
||||
@param useIndices Specifies whether to use indices to determine the
|
||||
vertices to use as input. */
|
||||
void initialize(Ogre::RenderOperation::OperationType operationType,
|
||||
bool useIndices);
|
||||
|
||||
/// Implementation of Ogre::SimpleRenderable
|
||||
virtual Ogre::Real getBoundingRadius(void) const;
|
||||
/// Implementation of Ogre::SimpleRenderable
|
||||
virtual Ogre::Real getSquaredViewDepth(const Ogre::Camera* cam) const;
|
||||
|
||||
protected:
|
||||
/// Maximum capacity of the currently allocated vertex buffer.
|
||||
size_t mVertexBufferCapacity;
|
||||
/// Maximum capacity of the currently allocated index buffer.
|
||||
size_t mIndexBufferCapacity;
|
||||
|
||||
/** Creates the vertex declaration.
|
||||
@remarks
|
||||
Override and set mRenderOp.vertexData->vertexDeclaration here.
|
||||
mRenderOp.vertexData will be created for you before this method
|
||||
is called. */
|
||||
virtual void createVertexDeclaration() = 0;
|
||||
|
||||
/** Prepares the hardware buffers for the requested vertex and index counts.
|
||||
@remarks
|
||||
This function must be called before locking the buffers in
|
||||
fillHardwareBuffers(). It guarantees that the hardware buffers
|
||||
are large enough to hold at least the requested number of
|
||||
vertices and indices (if using indices). The buffers are
|
||||
possibly reallocated to achieve this.
|
||||
@par
|
||||
The vertex and index count in the render operation are set to
|
||||
the values of vertexCount and indexCount respectively.
|
||||
@param vertexCount The number of vertices the buffer must hold.
|
||||
|
||||
@param indexCount The number of indices the buffer must hold. This
|
||||
parameter is ignored if not using indices. */
|
||||
void prepareHardwareBuffers(size_t vertexCount, size_t indexCount);
|
||||
|
||||
/** Fills the hardware vertex and index buffers with data.
|
||||
@remarks
|
||||
This function must call prepareHardwareBuffers() before locking
|
||||
the buffers to ensure the they are large enough for the data to
|
||||
be written. Afterwards the vertex and index buffers (if using
|
||||
indices) can be locked, and data can be written to them. */
|
||||
virtual void fillHardwareBuffers() = 0;
|
||||
};
|
||||
|
||||
class DynamicLines : public DynamicRenderable
|
||||
{
|
||||
typedef Ogre::Vector3 Vector3;
|
||||
typedef Ogre::Quaternion Quaternion;
|
||||
typedef Ogre::Camera Camera;
|
||||
typedef Ogre::Real Real;
|
||||
typedef Ogre::RenderOperation::OperationType OperationType;
|
||||
|
||||
public:
|
||||
/// Constructor - see setOperationType() for description of argument.
|
||||
DynamicLines(OperationType opType=Ogre::RenderOperation::OT_LINE_STRIP);
|
||||
virtual ~DynamicLines();
|
||||
|
||||
/// Add a point to the point list
|
||||
void addPoint(const Ogre::Vector3 &p);
|
||||
/// Add a point to the point list
|
||||
void addPoint(Real x, Real y, Real z);
|
||||
|
||||
/// Change the location of an existing point in the point list
|
||||
void setPoint(unsigned short index, const Vector3 &value);
|
||||
|
||||
/// Return the location of an existing point in the point list
|
||||
const Vector3& getPoint(unsigned short index) const;
|
||||
|
||||
/// Return the total number of points in the point list
|
||||
unsigned short getNumPoints(void) const;
|
||||
|
||||
/// Remove all points from the point list
|
||||
void clear();
|
||||
|
||||
/// Call this to update the hardware buffer after making changes.
|
||||
void update();
|
||||
|
||||
/** Set the type of operation to draw with.
|
||||
* @param opType Can be one of
|
||||
* - RenderOperation::OT_LINE_STRIP
|
||||
* - RenderOperation::OT_LINE_LIST
|
||||
* - RenderOperation::OT_POINT_LIST
|
||||
* - RenderOperation::OT_TRIANGLE_LIST
|
||||
* - RenderOperation::OT_TRIANGLE_STRIP
|
||||
* - RenderOperation::OT_TRIANGLE_FAN
|
||||
* The default is OT_LINE_STRIP.
|
||||
*/
|
||||
void setOperationType(OperationType opType);
|
||||
OperationType getOperationType() const;
|
||||
|
||||
protected:
|
||||
/// Implementation DynamicRenderable, creates a simple vertex-only decl
|
||||
virtual void createVertexDeclaration();
|
||||
/// Implementation DynamicRenderable, pushes point list out to hardware memory
|
||||
virtual void fillHardwareBuffers();
|
||||
|
||||
private:
|
||||
std::vector<Vector3> mPoints;
|
||||
bool mDirty;
|
||||
};
|
||||
|
||||
class DebugDrawer : public btIDebugDraw
|
||||
{
|
||||
protected:
|
||||
Ogre::SceneNode *mNode;
|
||||
btDynamicsWorld *mWorld;
|
||||
DynamicLines *mLineDrawer;
|
||||
bool mDebugOn;
|
||||
|
||||
public:
|
||||
|
||||
DebugDrawer(Ogre::SceneNode *node, btDynamicsWorld *world)
|
||||
: mNode(node),
|
||||
mWorld(world),
|
||||
mDebugOn(true)
|
||||
{
|
||||
mLineDrawer = new DynamicLines(Ogre::RenderOperation::OT_LINE_LIST);
|
||||
mNode->attachObject(mLineDrawer);
|
||||
|
||||
if (!Ogre::ResourceGroupManager::getSingleton().resourceGroupExists("BtOgre"))
|
||||
Ogre::ResourceGroupManager::getSingleton().createResourceGroup("BtOgre");
|
||||
if (!Ogre::MaterialManager::getSingleton().resourceExists("BtOgre/DebugLines"))
|
||||
{
|
||||
Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create("BtOgre/DebugLines", "BtOgre");
|
||||
mat->setReceiveShadows(false);
|
||||
mat->setSelfIllumination(1,1,1);
|
||||
}
|
||||
|
||||
mLineDrawer->setMaterial("BtOgre/DebugLines");
|
||||
|
||||
//mLineDrawer->setVisibilityFlags (1024);
|
||||
}
|
||||
|
||||
~DebugDrawer()
|
||||
{
|
||||
Ogre::MaterialManager::getSingleton().remove("BtOgre/DebugLines");
|
||||
Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup("BtOgre");
|
||||
delete mLineDrawer;
|
||||
}
|
||||
|
||||
void step()
|
||||
{
|
||||
if (mDebugOn)
|
||||
{
|
||||
mWorld->debugDrawWorld();
|
||||
mLineDrawer->update();
|
||||
mNode->needUpdate();
|
||||
mLineDrawer->clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
mLineDrawer->clear();
|
||||
mLineDrawer->update();
|
||||
mNode->needUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void drawLine(const btVector3& from,const btVector3& to,const btVector3& color)
|
||||
{
|
||||
mLineDrawer->addPoint(Convert::toOgre(from));
|
||||
mLineDrawer->addPoint(Convert::toOgre(to));
|
||||
}
|
||||
|
||||
void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color)
|
||||
{
|
||||
mLineDrawer->addPoint(Convert::toOgre(PointOnB));
|
||||
mLineDrawer->addPoint(Convert::toOgre(PointOnB) + (Convert::toOgre(normalOnB) * distance * 20));
|
||||
}
|
||||
|
||||
void reportErrorWarning(const char* warningString)
|
||||
{
|
||||
Ogre::LogManager::getSingleton().logMessage(warningString);
|
||||
}
|
||||
|
||||
void draw3dText(const btVector3& location,const char* textString)
|
||||
{
|
||||
}
|
||||
|
||||
//0 for off, anything else for on.
|
||||
void setDebugMode(int isOn)
|
||||
{
|
||||
mDebugOn = (isOn == 0) ? false : true;
|
||||
|
||||
if (!mDebugOn)
|
||||
mLineDrawer->clear();
|
||||
}
|
||||
|
||||
//0 for off, anything else for on.
|
||||
int getDebugMode() const
|
||||
{
|
||||
return mDebugOn;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
145
libs/openengine/bullet/BtOgreGP.h
Normal file
145
libs/openengine/bullet/BtOgreGP.h
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: BtOgreGP.h
|
||||
*
|
||||
* Description: The part of BtOgre that handles information transfer from Ogre to
|
||||
* Bullet (like mesh data for making trimeshes).
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 27/12/2008 03:29:56 AM
|
||||
*
|
||||
* Author: Nikhilesh (nikki)
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef _BtOgrePG_H_
|
||||
#define _BtOgrePG_H_
|
||||
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
#include "BtOgreExtras.h"
|
||||
|
||||
#include <OgreMatrix4.h>
|
||||
#include <OgreMesh.h>
|
||||
#include <OgreVector3.h>
|
||||
|
||||
namespace BtOgre {
|
||||
|
||||
typedef std::map<unsigned char, Vector3Array*> BoneIndex;
|
||||
typedef std::pair<unsigned short, Vector3Array*> BoneKeyIndex;
|
||||
|
||||
class VertexIndexToShape
|
||||
{
|
||||
public:
|
||||
VertexIndexToShape(const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY);
|
||||
~VertexIndexToShape();
|
||||
|
||||
Ogre::Real getRadius();
|
||||
Ogre::Vector3 getSize();
|
||||
|
||||
|
||||
btSphereShape* createSphere();
|
||||
btBoxShape* createBox();
|
||||
btBvhTriangleMeshShape* createTrimesh();
|
||||
btCylinderShape* createCylinder();
|
||||
btConvexHullShape* createConvex();
|
||||
|
||||
const Ogre::Vector3* getVertices();
|
||||
unsigned int getVertexCount();
|
||||
const unsigned int* getIndices();
|
||||
unsigned int getIndexCount();
|
||||
|
||||
protected:
|
||||
|
||||
void addStaticVertexData(const Ogre::VertexData *vertex_data);
|
||||
|
||||
void addAnimatedVertexData(const Ogre::VertexData *vertex_data,
|
||||
const Ogre::VertexData *blended_data,
|
||||
const Ogre::Mesh::IndexMap *indexMap);
|
||||
|
||||
void addIndexData(Ogre::IndexData *data, const unsigned int offset = 0);
|
||||
|
||||
|
||||
protected:
|
||||
Ogre::Vector3* mVertexBuffer;
|
||||
unsigned int* mIndexBuffer;
|
||||
unsigned int mVertexCount;
|
||||
unsigned int mIndexCount;
|
||||
|
||||
Ogre::Matrix4 mTransform;
|
||||
|
||||
Ogre::Real mBoundRadius;
|
||||
Ogre::Vector3 mBounds;
|
||||
|
||||
BoneIndex *mBoneIndex;
|
||||
|
||||
Ogre::Vector3 mScale;
|
||||
};
|
||||
|
||||
//For static (non-animated) meshes.
|
||||
class StaticMeshToShapeConverter : public VertexIndexToShape
|
||||
{
|
||||
public:
|
||||
|
||||
StaticMeshToShapeConverter(Ogre::Renderable *rend, const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY);
|
||||
StaticMeshToShapeConverter(Ogre::Entity *entity, const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY);
|
||||
StaticMeshToShapeConverter();
|
||||
|
||||
~StaticMeshToShapeConverter();
|
||||
|
||||
void addEntity(Ogre::Entity *entity,const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY);
|
||||
|
||||
void addMesh(const Ogre::MeshPtr &mesh, const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
Ogre::Entity* mEntity;
|
||||
Ogre::SceneNode* mNode;
|
||||
};
|
||||
|
||||
//For animated meshes.
|
||||
class AnimatedMeshToShapeConverter : public VertexIndexToShape
|
||||
{
|
||||
public:
|
||||
|
||||
AnimatedMeshToShapeConverter(Ogre::Entity *entity, const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY);
|
||||
AnimatedMeshToShapeConverter();
|
||||
~AnimatedMeshToShapeConverter();
|
||||
|
||||
void addEntity(Ogre::Entity *entity,const Ogre::Matrix4 &transform = Ogre::Matrix4::IDENTITY);
|
||||
void addMesh(const Ogre::MeshPtr &mesh, const Ogre::Matrix4 &transform);
|
||||
|
||||
btBoxShape* createAlignedBox(unsigned char bone,
|
||||
const Ogre::Vector3 &bonePosition,
|
||||
const Ogre::Quaternion &boneOrientation);
|
||||
|
||||
btBoxShape* createOrientedBox(unsigned char bone,
|
||||
const Ogre::Vector3 &bonePosition,
|
||||
const Ogre::Quaternion &boneOrientation);
|
||||
|
||||
protected:
|
||||
|
||||
bool getBoneVertices(unsigned char bone,
|
||||
unsigned int &vertex_count,
|
||||
Ogre::Vector3* &vertices,
|
||||
const Ogre::Vector3 &bonePosition);
|
||||
|
||||
bool getOrientedBox(unsigned char bone,
|
||||
const Ogre::Vector3 &bonePosition,
|
||||
const Ogre::Quaternion &boneOrientation,
|
||||
Ogre::Vector3 &extents,
|
||||
Ogre::Vector3 *axis,
|
||||
Ogre::Vector3 ¢er);
|
||||
|
||||
Ogre::Entity* mEntity;
|
||||
Ogre::SceneNode* mNode;
|
||||
|
||||
Ogre::Vector3 *mTransformedVerticesTemp;
|
||||
size_t mTransformedVerticesTempSize;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
81
libs/openengine/bullet/BtOgrePG.h
Normal file
81
libs/openengine/bullet/BtOgrePG.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: BtOgrePG.h
|
||||
*
|
||||
* Description: The part of BtOgre that handles information transfer from Bullet to
|
||||
* Ogre (like updating graphics object positions).
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 27/12/2008 03:40:56 AM
|
||||
*
|
||||
* Author: Nikhilesh (nikki)
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef _BtOgreGP_H_
|
||||
#define _BtOgreGP_H_
|
||||
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
#include "OgreSceneNode.h"
|
||||
#include "BtOgreExtras.h"
|
||||
|
||||
namespace BtOgre {
|
||||
|
||||
//A MotionState is Bullet's way of informing you about updates to an object.
|
||||
//Pass this MotionState to a btRigidBody to have your SceneNode updated automaticaly.
|
||||
class RigidBodyState : public btMotionState
|
||||
{
|
||||
protected:
|
||||
btTransform mTransform;
|
||||
btTransform mCenterOfMassOffset;
|
||||
|
||||
Ogre::SceneNode *mNode;
|
||||
|
||||
public:
|
||||
RigidBodyState(Ogre::SceneNode *node, const btTransform &transform, const btTransform &offset = btTransform::getIdentity())
|
||||
: mTransform(transform),
|
||||
mCenterOfMassOffset(offset),
|
||||
mNode(node)
|
||||
{
|
||||
}
|
||||
|
||||
RigidBodyState(Ogre::SceneNode *node)
|
||||
: mTransform(((node != NULL) ? BtOgre::Convert::toBullet(node->getOrientation()) : btQuaternion(0,0,0,1)),
|
||||
((node != NULL) ? BtOgre::Convert::toBullet(node->getPosition()) : btVector3(0,0,0))),
|
||||
mCenterOfMassOffset(btTransform::getIdentity()),
|
||||
mNode(node)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void getWorldTransform(btTransform &ret) const
|
||||
{
|
||||
ret = mCenterOfMassOffset.inverse() * mTransform;
|
||||
}
|
||||
|
||||
virtual void setWorldTransform(const btTransform &in)
|
||||
{
|
||||
if (mNode == NULL)
|
||||
return;
|
||||
|
||||
mTransform = in;
|
||||
btTransform transform = in * mCenterOfMassOffset;
|
||||
|
||||
btQuaternion rot = transform.getRotation();
|
||||
btVector3 pos = transform.getOrigin();
|
||||
mNode->setOrientation(rot.w(), rot.x(), rot.y(), rot.z());
|
||||
mNode->setPosition(pos.x(), pos.y(), pos.z());
|
||||
}
|
||||
|
||||
void setNode(Ogre::SceneNode *node)
|
||||
{
|
||||
mNode = node;
|
||||
}
|
||||
};
|
||||
|
||||
//Softbody-Ogre connection goes here!
|
||||
|
||||
}
|
||||
|
||||
#endif
|
153
libs/openengine/bullet/BulletShapeLoader.cpp
Normal file
153
libs/openengine/bullet/BulletShapeLoader.cpp
Normal file
|
@ -0,0 +1,153 @@
|
|||
#include "BulletShapeLoader.h"
|
||||
|
||||
namespace OEngine {
|
||||
namespace Physic
|
||||
{
|
||||
|
||||
BulletShape::BulletShape(Ogre::ResourceManager* creator, const Ogre::String &name,
|
||||
Ogre::ResourceHandle handle, const Ogre::String &group, bool isManual,
|
||||
Ogre::ManualResourceLoader *loader) :
|
||||
Ogre::Resource(creator, name, handle, group, isManual, loader)
|
||||
{
|
||||
/* If you were storing a pointer to an object, then you would set that pointer to NULL here.
|
||||
*/
|
||||
|
||||
/* For consistency with StringInterface, but we don't add any parameters here
|
||||
That's because the Resource implementation of StringInterface is to
|
||||
list all the options that need to be set before loading, of which
|
||||
we have none as such. Full details can be set through scripts.
|
||||
*/
|
||||
mCollisionShape = NULL;
|
||||
mRaycastingShape = NULL;
|
||||
mHasCollisionNode = false;
|
||||
mCollide = true;
|
||||
createParamDictionary("BulletShape");
|
||||
}
|
||||
|
||||
BulletShape::~BulletShape()
|
||||
{
|
||||
deleteShape(mCollisionShape);
|
||||
deleteShape(mRaycastingShape);
|
||||
}
|
||||
|
||||
// farm out to BulletShapeLoader
|
||||
void BulletShape::loadImpl()
|
||||
{
|
||||
mLoader->loadResource(this);
|
||||
}
|
||||
|
||||
void BulletShape::deleteShape(btCollisionShape* shape)
|
||||
{
|
||||
if(shape!=NULL)
|
||||
{
|
||||
if(shape->isCompound())
|
||||
{
|
||||
btCompoundShape* ms = static_cast<btCompoundShape*>(mCollisionShape);
|
||||
int a = ms->getNumChildShapes();
|
||||
for(int i=0; i <a;i++)
|
||||
{
|
||||
deleteShape(ms->getChildShape(i));
|
||||
}
|
||||
}
|
||||
delete shape;
|
||||
}
|
||||
shape = NULL;
|
||||
}
|
||||
|
||||
void BulletShape::unloadImpl()
|
||||
{
|
||||
deleteShape(mCollisionShape);
|
||||
deleteShape(mRaycastingShape);
|
||||
}
|
||||
|
||||
//TODO:change this?
|
||||
size_t BulletShape::calculateSize() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================================================
|
||||
BulletShapeManager *BulletShapeManager::sThis = 0;
|
||||
|
||||
BulletShapeManager *BulletShapeManager::getSingletonPtr()
|
||||
{
|
||||
return sThis;
|
||||
}
|
||||
|
||||
BulletShapeManager &BulletShapeManager::getSingleton()
|
||||
{
|
||||
assert(sThis);
|
||||
return(*sThis);
|
||||
}
|
||||
|
||||
BulletShapeManager::BulletShapeManager()
|
||||
{
|
||||
assert(!sThis);
|
||||
sThis = this;
|
||||
|
||||
mResourceType = "BulletShape";
|
||||
|
||||
// low, because it will likely reference other resources
|
||||
mLoadOrder = 30.0f;
|
||||
|
||||
// this is how we register the ResourceManager with OGRE
|
||||
Ogre::ResourceGroupManager::getSingleton()._registerResourceManager(mResourceType, this);
|
||||
}
|
||||
|
||||
BulletShapeManager::~BulletShapeManager()
|
||||
{
|
||||
// and this is how we unregister it
|
||||
Ogre::ResourceGroupManager::getSingleton()._unregisterResourceManager(mResourceType);
|
||||
|
||||
sThis = 0;
|
||||
}
|
||||
|
||||
#if (OGRE_VERSION >= ((1 << 16) | (9 << 8) | 0))
|
||||
BulletShapePtr BulletShapeManager::getByName(const Ogre::String& name, const Ogre::String& groupName)
|
||||
{
|
||||
return getResourceByName(name, groupName).staticCast<BulletShape>();
|
||||
}
|
||||
|
||||
BulletShapePtr BulletShapeManager::create (const Ogre::String& name, const Ogre::String& group,
|
||||
bool isManual, Ogre::ManualResourceLoader* loader,
|
||||
const Ogre::NameValuePairList* createParams)
|
||||
{
|
||||
return createResource(name,group,isManual,loader,createParams).staticCast<BulletShape>();
|
||||
}
|
||||
#endif
|
||||
|
||||
BulletShapePtr BulletShapeManager::load(const Ogre::String &name, const Ogre::String &group)
|
||||
{
|
||||
BulletShapePtr textf = getByName(name);
|
||||
|
||||
if (textf.isNull())
|
||||
textf = create(name, group);
|
||||
|
||||
textf->load();
|
||||
return textf;
|
||||
}
|
||||
|
||||
Ogre::Resource *BulletShapeManager::createImpl(const Ogre::String &name, Ogre::ResourceHandle handle,
|
||||
const Ogre::String &group, bool isManual, Ogre::ManualResourceLoader *loader,
|
||||
const Ogre::NameValuePairList *createParams)
|
||||
{
|
||||
BulletShape* res = new BulletShape(this, name, handle, group, isManual, loader);
|
||||
//if(isManual)
|
||||
//{
|
||||
//loader->loadResource(res);
|
||||
//}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
void BulletShapeLoader::loadResource(Ogre::Resource *resource)
|
||||
{}
|
||||
|
||||
void BulletShapeLoader::load(const std::string &name,const std::string &group)
|
||||
{}
|
||||
|
||||
}
|
||||
}
|
176
libs/openengine/bullet/BulletShapeLoader.h
Normal file
176
libs/openengine/bullet/BulletShapeLoader.h
Normal file
|
@ -0,0 +1,176 @@
|
|||
#ifndef _BULLET_SHAPE_LOADER_H_
|
||||
#define _BULLET_SHAPE_LOADER_H_
|
||||
|
||||
#include <OgreResource.h>
|
||||
#include <OgreResourceManager.h>
|
||||
#include <btBulletCollisionCommon.h>
|
||||
#include <OgreVector3.h>
|
||||
|
||||
namespace OEngine {
|
||||
namespace Physic
|
||||
{
|
||||
|
||||
/**
|
||||
*Define a new resource which describe a Shape usable by bullet.See BulletShapeManager for how to get/use them.
|
||||
*/
|
||||
class BulletShape : public Ogre::Resource
|
||||
{
|
||||
Ogre::String mString;
|
||||
|
||||
protected:
|
||||
void loadImpl();
|
||||
void unloadImpl();
|
||||
size_t calculateSize() const;
|
||||
|
||||
void deleteShape(btCollisionShape* shape);
|
||||
|
||||
public:
|
||||
|
||||
BulletShape(Ogre::ResourceManager *creator, const Ogre::String &name,
|
||||
Ogre::ResourceHandle handle, const Ogre::String &group, bool isManual = false,
|
||||
Ogre::ManualResourceLoader *loader = 0);
|
||||
|
||||
virtual ~BulletShape();
|
||||
|
||||
btCollisionShape* mCollisionShape;
|
||||
btCollisionShape* mRaycastingShape;
|
||||
|
||||
// Whether or not a NiRootCollisionNode was present in the .nif. If there is none, the collision behaviour
|
||||
// depends on object type, so we need to expose this variable.
|
||||
bool mHasCollisionNode;
|
||||
|
||||
Ogre::Vector3 mBoxTranslation;
|
||||
Ogre::Quaternion mBoxRotation;
|
||||
//this flag indicate if the shape is used for collision or if it's for raycasting only.
|
||||
bool mCollide;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
#if (OGRE_VERSION < ((1 << 16) | (9 << 8) | 0))
|
||||
class BulletShapePtr : public Ogre::SharedPtr<BulletShape>
|
||||
{
|
||||
public:
|
||||
BulletShapePtr() : Ogre::SharedPtr<BulletShape>() {}
|
||||
explicit BulletShapePtr(BulletShape *rep) : Ogre::SharedPtr<BulletShape>(rep) {}
|
||||
BulletShapePtr(const BulletShapePtr &r) : Ogre::SharedPtr<BulletShape>(r) {}
|
||||
BulletShapePtr(const Ogre::ResourcePtr &r) : Ogre::SharedPtr<BulletShape>()
|
||||
{
|
||||
if( r.isNull() )
|
||||
return;
|
||||
// lock & copy other mutex pointer
|
||||
OGRE_LOCK_MUTEX(*r.OGRE_AUTO_MUTEX_NAME)
|
||||
OGRE_COPY_AUTO_SHARED_MUTEX(r.OGRE_AUTO_MUTEX_NAME)
|
||||
pRep = static_cast<BulletShape*>(r.getPointer());
|
||||
pUseCount = r.useCountPointer();
|
||||
useFreeMethod = r.freeMethod();
|
||||
if (pUseCount)
|
||||
{
|
||||
++(*pUseCount);
|
||||
}
|
||||
}
|
||||
|
||||
/// Operator used to convert a ResourcePtr to a BulletShapePtr
|
||||
BulletShapePtr& operator=(const Ogre::ResourcePtr& r)
|
||||
{
|
||||
if(pRep == static_cast<BulletShape*>(r.getPointer()))
|
||||
return *this;
|
||||
release();
|
||||
if( r.isNull() )
|
||||
return *this; // resource ptr is null, so the call to release above has done all we need to do.
|
||||
// lock & copy other mutex pointer
|
||||
OGRE_LOCK_MUTEX(*r.OGRE_AUTO_MUTEX_NAME)
|
||||
OGRE_COPY_AUTO_SHARED_MUTEX(r.OGRE_AUTO_MUTEX_NAME)
|
||||
pRep = static_cast<BulletShape*>(r.getPointer());
|
||||
pUseCount = r.useCountPointer();
|
||||
useFreeMethod = r.freeMethod();
|
||||
if (pUseCount)
|
||||
{
|
||||
++(*pUseCount);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
#else
|
||||
typedef Ogre::SharedPtr<BulletShape> BulletShapePtr;
|
||||
#endif
|
||||
|
||||
/**
|
||||
*Hold any BulletShape that was created by the ManualBulletShapeLoader.
|
||||
*
|
||||
*To get a bulletShape, you must load it first.
|
||||
*First, create a manualBulletShapeLoader. Then call ManualBulletShapeManager->load(). This create an "empty" resource.
|
||||
*Then use BulletShapeManager->load(). This will fill the resource with the required info.
|
||||
*To get the resource,use BulletShapeManager::getByName.
|
||||
*When you use the resource no more, just use BulletShapeManager->unload(). It won't completly delete the resource, but it will
|
||||
*"empty" it.This allow a better management of memory: when you are leaving a cell, just unload every useless shape.
|
||||
*
|
||||
*Alternatively, you can call BulletShape->load() in order to actually load the resource.
|
||||
*When you are finished with it, just call BulletShape->unload().
|
||||
*
|
||||
*IMO: prefere the first methode, i am not completly sure about the 2nd.
|
||||
*
|
||||
*Important Note: i have no idea of what happen if you try to load two time the same resource without unloading.
|
||||
*It won't crash, but it might lead to memory leaks(I don't know how Ogre handle this). So don't do it!
|
||||
*/
|
||||
class BulletShapeManager : public Ogre::ResourceManager
|
||||
{
|
||||
protected:
|
||||
|
||||
// must implement this from ResourceManager's interface
|
||||
Ogre::Resource *createImpl(const Ogre::String &name, Ogre::ResourceHandle handle,
|
||||
const Ogre::String &group, bool isManual, Ogre::ManualResourceLoader *loader,
|
||||
const Ogre::NameValuePairList *createParams);
|
||||
|
||||
static BulletShapeManager *sThis;
|
||||
|
||||
private:
|
||||
/** \brief Explicit private copy constructor. This is a forbidden operation.*/
|
||||
BulletShapeManager(const BulletShapeManager &);
|
||||
|
||||
/** \brief Private operator= . This is a forbidden operation. */
|
||||
BulletShapeManager& operator=(const BulletShapeManager &);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
BulletShapeManager();
|
||||
virtual ~BulletShapeManager();
|
||||
|
||||
|
||||
#if (OGRE_VERSION >= ((1 << 16) | (9 << 8) | 0))
|
||||
/// Get a resource by name
|
||||
/// @see ResourceManager::getByName
|
||||
BulletShapePtr getByName(const Ogre::String& name, const Ogre::String& groupName = Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME);
|
||||
|
||||
/// Create a new shape
|
||||
/// @see ResourceManager::createResource
|
||||
BulletShapePtr create (const Ogre::String& name, const Ogre::String& group,
|
||||
bool isManual = false, Ogre::ManualResourceLoader* loader = 0,
|
||||
const Ogre::NameValuePairList* createParams = 0);
|
||||
#endif
|
||||
|
||||
virtual BulletShapePtr load(const Ogre::String &name, const Ogre::String &group);
|
||||
|
||||
static BulletShapeManager &getSingleton();
|
||||
static BulletShapeManager *getSingletonPtr();
|
||||
};
|
||||
|
||||
class BulletShapeLoader : public Ogre::ManualResourceLoader
|
||||
{
|
||||
public:
|
||||
|
||||
BulletShapeLoader(){};
|
||||
virtual ~BulletShapeLoader() {}
|
||||
|
||||
virtual void loadResource(Ogre::Resource *resource);
|
||||
|
||||
virtual void load(const std::string &name,const std::string &group);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
46
libs/openengine/bullet/CMotionState.cpp
Normal file
46
libs/openengine/bullet/CMotionState.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
#include "CMotionState.h"
|
||||
#include "physic.hpp"
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <btBulletCollisionCommon.h>
|
||||
#include <components/nifbullet/bulletnifloader.hpp>
|
||||
|
||||
namespace OEngine {
|
||||
namespace Physic
|
||||
{
|
||||
|
||||
CMotionState::CMotionState(PhysicEngine* eng,std::string name)
|
||||
: isPC(false)
|
||||
, isNPC(true)
|
||||
{
|
||||
pEng = eng;
|
||||
tr.setIdentity();
|
||||
pName = name;
|
||||
}
|
||||
|
||||
void CMotionState::getWorldTransform(btTransform &worldTrans) const
|
||||
{
|
||||
worldTrans = tr;
|
||||
}
|
||||
|
||||
void CMotionState::setWorldTransform(const btTransform &worldTrans)
|
||||
{
|
||||
tr = worldTrans;
|
||||
|
||||
PhysicEvent evt;
|
||||
evt.isNPC = isNPC;
|
||||
evt.isPC = isPC;
|
||||
evt.newTransform = tr;
|
||||
evt.RigidBodyName = pName;
|
||||
|
||||
if(isPC)
|
||||
{
|
||||
pEng->PEventList.push_back(evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
pEng->NPEventList.push_back(evt);
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
52
libs/openengine/bullet/CMotionState.h
Normal file
52
libs/openengine/bullet/CMotionState.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#ifndef OENGINE_CMOTIONSTATE_H
|
||||
#define OENGINE_CMOTIONSTATE_H
|
||||
|
||||
#include <BulletDynamics/Dynamics/btRigidBody.h>
|
||||
#include <string>
|
||||
|
||||
namespace OEngine {
|
||||
namespace Physic
|
||||
{
|
||||
class PhysicEngine;
|
||||
|
||||
/**
|
||||
* A CMotionState is associated with a single RigidBody.
|
||||
* When the RigidBody is moved by bullet, bullet will call the function setWorldTransform.
|
||||
* for more info, see the bullet Wiki at btMotionState.
|
||||
*/
|
||||
class CMotionState:public btMotionState
|
||||
{
|
||||
public:
|
||||
|
||||
CMotionState(PhysicEngine* eng,std::string name);
|
||||
|
||||
/**
|
||||
* Return the position of the RigidBody.
|
||||
*/
|
||||
virtual void getWorldTransform(btTransform &worldTrans) const;
|
||||
|
||||
/**
|
||||
* Function called by bullet when the RigidBody is moved.
|
||||
* It add an event to the EventList of the PhysicEngine class.
|
||||
*/
|
||||
virtual void setWorldTransform(const btTransform &worldTrans);
|
||||
|
||||
protected:
|
||||
PhysicEngine* pEng;
|
||||
btTransform tr;
|
||||
bool isNPC;
|
||||
bool isPC;
|
||||
|
||||
std::string pName;
|
||||
};
|
||||
|
||||
struct PhysicEvent
|
||||
{
|
||||
bool isNPC;
|
||||
bool isPC;
|
||||
btTransform newTransform;
|
||||
std::string RigidBodyName;
|
||||
};
|
||||
|
||||
}}
|
||||
#endif
|
643
libs/openengine/bullet/btKinematicCharacterController.cpp
Normal file
643
libs/openengine/bullet/btKinematicCharacterController.cpp
Normal file
|
@ -0,0 +1,643 @@
|
|||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "LinearMath/btIDebugDraw.h"
|
||||
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
|
||||
#include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
|
||||
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
|
||||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
|
||||
#include "LinearMath/btDefaultMotionState.h"
|
||||
#include "btKinematicCharacterController.h"
|
||||
|
||||
///@todo Interact with dynamic objects,
|
||||
///Ride kinematicly animated platforms properly
|
||||
///Support ducking
|
||||
class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
|
||||
{
|
||||
public:
|
||||
btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
|
||||
{
|
||||
m_me[0] = me;
|
||||
count = 1;
|
||||
}
|
||||
|
||||
btKinematicClosestNotMeRayResultCallback (btCollisionObject* me[], int count_) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
|
||||
{
|
||||
count = count_;
|
||||
|
||||
for(int i = 0; i < count; i++)
|
||||
m_me[i] = me[i];
|
||||
}
|
||||
|
||||
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
|
||||
{
|
||||
for(int i = 0; i < count; i++)
|
||||
if (rayResult.m_collisionObject == m_me[i])
|
||||
return 1.0;
|
||||
|
||||
return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace);
|
||||
}
|
||||
protected:
|
||||
btCollisionObject* m_me[10];
|
||||
int count;
|
||||
};
|
||||
|
||||
class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
|
||||
{
|
||||
public:
|
||||
btKinematicClosestNotMeConvexResultCallback( btCollisionObject* me, const btVector3& up, btScalar minSlopeDot )
|
||||
: btCollisionWorld::ClosestConvexResultCallback( btVector3( 0.0, 0.0, 0.0 ), btVector3( 0.0, 0.0, 0.0 ) ),
|
||||
m_me( me ), m_up( up ), m_minSlopeDot( minSlopeDot )
|
||||
{
|
||||
}
|
||||
|
||||
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
|
||||
{
|
||||
if( convexResult.m_hitCollisionObject == m_me )
|
||||
return btScalar( 1 );
|
||||
|
||||
btVector3 hitNormalWorld;
|
||||
if( normalInWorldSpace )
|
||||
{
|
||||
hitNormalWorld = convexResult.m_hitNormalLocal;
|
||||
}
|
||||
else
|
||||
{
|
||||
///need to transform normal into worldspace
|
||||
hitNormalWorld = m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
|
||||
}
|
||||
|
||||
// NOTE : m_hitNormalLocal is not always vertical on the ground with a capsule or a box...
|
||||
|
||||
btScalar dotUp = m_up.dot(hitNormalWorld);
|
||||
if( dotUp < m_minSlopeDot )
|
||||
return btScalar( 1 );
|
||||
|
||||
return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace);
|
||||
}
|
||||
|
||||
protected:
|
||||
btCollisionObject* m_me;
|
||||
const btVector3 m_up;
|
||||
btScalar m_minSlopeDot;
|
||||
};
|
||||
|
||||
|
||||
|
||||
btKinematicCharacterController::btKinematicCharacterController( btPairCachingGhostObject* externalGhostObject_,
|
||||
btPairCachingGhostObject* internalGhostObject_,
|
||||
btScalar stepHeight,
|
||||
btScalar constantScale,
|
||||
btScalar gravity,
|
||||
btScalar fallVelocity,
|
||||
btScalar jumpVelocity,
|
||||
btScalar recoveringFactor )
|
||||
{
|
||||
m_upAxis = btKinematicCharacterController::Y_AXIS;
|
||||
|
||||
m_walkDirection.setValue( btScalar( 0 ), btScalar( 0 ), btScalar( 0 ) );
|
||||
|
||||
m_useGhostObjectSweepTest = true;
|
||||
|
||||
externalGhostObject = externalGhostObject_;
|
||||
internalGhostObject = internalGhostObject_;
|
||||
|
||||
m_recoveringFactor = recoveringFactor;
|
||||
|
||||
m_stepHeight = stepHeight;
|
||||
|
||||
m_useWalkDirection = true; // use walk direction by default, legacy behavior
|
||||
m_velocityTimeInterval = btScalar( 0 );
|
||||
m_verticalVelocity = btScalar( 0 );
|
||||
m_verticalOffset = btScalar( 0 );
|
||||
|
||||
m_gravity = constantScale * gravity;
|
||||
m_fallSpeed = constantScale * fallVelocity; // Terminal velocity of a sky diver in m/s.
|
||||
|
||||
m_jumpSpeed = constantScale * jumpVelocity; // ?
|
||||
m_wasJumping = false;
|
||||
|
||||
setMaxSlope( btRadians( 45.0 ) );
|
||||
|
||||
mCollision = true;
|
||||
}
|
||||
|
||||
|
||||
btKinematicCharacterController::~btKinematicCharacterController ()
|
||||
{
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::setVerticalVelocity(float z)
|
||||
{
|
||||
m_verticalVelocity = z;
|
||||
}
|
||||
|
||||
bool btKinematicCharacterController::recoverFromPenetration( btCollisionWorld* collisionWorld )
|
||||
{
|
||||
bool penetration = false;
|
||||
|
||||
if(!mCollision) return penetration;
|
||||
|
||||
collisionWorld->getDispatcher()->dispatchAllCollisionPairs( internalGhostObject->getOverlappingPairCache(),
|
||||
collisionWorld->getDispatchInfo(),
|
||||
collisionWorld->getDispatcher() );
|
||||
|
||||
btVector3 currentPosition = internalGhostObject->getWorldTransform().getOrigin();
|
||||
|
||||
btScalar maxPen = btScalar( 0 );
|
||||
|
||||
for( int i = 0; i < internalGhostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++ )
|
||||
{
|
||||
m_manifoldArray.resize(0);
|
||||
|
||||
btBroadphasePair* collisionPair = &internalGhostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
|
||||
|
||||
if( collisionPair->m_algorithm )
|
||||
collisionPair->m_algorithm->getAllContactManifolds( m_manifoldArray );
|
||||
|
||||
|
||||
for( int j = 0; j < m_manifoldArray.size(); j++ )
|
||||
{
|
||||
btPersistentManifold* manifold = m_manifoldArray[j];
|
||||
|
||||
btScalar directionSign = manifold->getBody0() == internalGhostObject ? btScalar( -1.0 ) : btScalar( 1.0 );
|
||||
|
||||
for( int p = 0; p < manifold->getNumContacts(); p++ )
|
||||
{
|
||||
const btManifoldPoint&pt = manifold->getContactPoint( p );
|
||||
if( (manifold->getBody1() == externalGhostObject && manifold->getBody0() == internalGhostObject)
|
||||
||(manifold->getBody0() == externalGhostObject && manifold->getBody1() == internalGhostObject) )
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
btScalar dist = pt.getDistance();
|
||||
|
||||
if( dist < 0.0 )
|
||||
{
|
||||
if( dist < maxPen )
|
||||
maxPen = dist;
|
||||
|
||||
// NOTE : btScalar affects the stairs but the parkinson...
|
||||
// 0.0 , the capsule can break the walls...
|
||||
currentPosition += pt.m_normalWorldOnB * directionSign * dist * m_recoveringFactor;
|
||||
|
||||
penetration = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ???
|
||||
//manifold->clearManifold();
|
||||
}
|
||||
}
|
||||
|
||||
btTransform transform = internalGhostObject->getWorldTransform();
|
||||
|
||||
transform.setOrigin( currentPosition );
|
||||
|
||||
internalGhostObject->setWorldTransform( transform );
|
||||
externalGhostObject->setWorldTransform( transform );
|
||||
|
||||
return penetration;
|
||||
}
|
||||
|
||||
|
||||
btVector3 btKinematicCharacterController::stepUp( btCollisionWorld* world, const btVector3& currentPosition, btScalar& currentStepOffset )
|
||||
{
|
||||
btVector3 targetPosition = currentPosition + getUpAxisDirections()[ m_upAxis ] * ( m_stepHeight + ( m_verticalOffset > btScalar( 0.0 ) ? m_verticalOffset : 0.0 ) );
|
||||
|
||||
//if the no collisions mode is on, no need to go any further
|
||||
if(!mCollision)
|
||||
{
|
||||
currentStepOffset = m_stepHeight;
|
||||
return targetPosition;
|
||||
}
|
||||
|
||||
// Retrieve the collision shape
|
||||
//
|
||||
btCollisionShape* collisionShape = externalGhostObject->getCollisionShape();
|
||||
btAssert( collisionShape->isConvex() );
|
||||
|
||||
btConvexShape* convexShape = ( btConvexShape* )collisionShape;
|
||||
|
||||
// FIXME: Handle penetration properly
|
||||
//
|
||||
btTransform start;
|
||||
start.setIdentity();
|
||||
start.setOrigin( currentPosition + getUpAxisDirections()[ m_upAxis ] * ( convexShape->getMargin() ) );
|
||||
|
||||
btTransform end;
|
||||
end.setIdentity();
|
||||
end.setOrigin( targetPosition );
|
||||
|
||||
btKinematicClosestNotMeConvexResultCallback callback( externalGhostObject, -getUpAxisDirections()[ m_upAxis ], m_maxSlopeCosine );
|
||||
callback.m_collisionFilterGroup = externalGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
callback.m_collisionFilterMask = externalGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
||||
// Sweep test
|
||||
//
|
||||
if( m_useGhostObjectSweepTest )
|
||||
externalGhostObject->convexSweepTest( convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration );
|
||||
|
||||
else
|
||||
world->convexSweepTest( convexShape, start, end, callback );
|
||||
|
||||
if( callback.hasHit() )
|
||||
{
|
||||
// Only modify the position if the hit was a slope and not a wall or ceiling.
|
||||
//
|
||||
if( callback.m_hitNormalWorld.dot(getUpAxisDirections()[m_upAxis]) > btScalar( 0.0 ) )
|
||||
{
|
||||
// We moved up only a fraction of the step height
|
||||
//
|
||||
currentStepOffset = m_stepHeight * callback.m_closestHitFraction;
|
||||
|
||||
return currentPosition.lerp( targetPosition, callback.m_closestHitFraction );
|
||||
}
|
||||
|
||||
m_verticalVelocity = btScalar( 0.0 );
|
||||
m_verticalOffset = btScalar( 0.0 );
|
||||
|
||||
return currentPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentStepOffset = m_stepHeight;
|
||||
return targetPosition;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///Reflect the vector d around the vector r
|
||||
inline btVector3 reflect( const btVector3& d, const btVector3& r )
|
||||
{
|
||||
return d - ( btScalar( 2.0 ) * d.dot( r ) ) * r;
|
||||
}
|
||||
|
||||
|
||||
///Project a vector u on another vector v
|
||||
inline btVector3 project( const btVector3& u, const btVector3& v )
|
||||
{
|
||||
return v * u.dot( v );
|
||||
}
|
||||
|
||||
|
||||
///Helper for computing the character sliding
|
||||
inline btVector3 slide( const btVector3& direction, const btVector3& planeNormal )
|
||||
{
|
||||
return direction - project( direction, planeNormal );
|
||||
}
|
||||
|
||||
|
||||
|
||||
btVector3 slideOnCollision( const btVector3& fromPosition, const btVector3& toPosition, const btVector3& hitNormal )
|
||||
{
|
||||
btVector3 moveDirection = toPosition - fromPosition;
|
||||
btScalar moveLength = moveDirection.length();
|
||||
|
||||
if( moveLength <= btScalar( SIMD_EPSILON ) )
|
||||
return toPosition;
|
||||
|
||||
moveDirection.normalize();
|
||||
|
||||
btVector3 reflectDir = reflect( moveDirection, hitNormal );
|
||||
reflectDir.normalize();
|
||||
|
||||
return fromPosition + slide( reflectDir, hitNormal ) * moveLength;
|
||||
}
|
||||
|
||||
|
||||
btVector3 btKinematicCharacterController::stepForwardAndStrafe( btCollisionWorld* collisionWorld, const btVector3& currentPosition, const btVector3& walkMove )
|
||||
{
|
||||
// We go to !
|
||||
//
|
||||
btVector3 targetPosition = currentPosition + walkMove;
|
||||
|
||||
//if the no collisions mode is on, no need to go any further
|
||||
if(!mCollision) return targetPosition;
|
||||
|
||||
// Retrieve the collision shape
|
||||
//
|
||||
btCollisionShape* collisionShape = externalGhostObject->getCollisionShape();
|
||||
btAssert( collisionShape->isConvex() );
|
||||
|
||||
btConvexShape* convexShape = ( btConvexShape* )collisionShape;
|
||||
|
||||
btTransform start;
|
||||
start.setIdentity();
|
||||
|
||||
btTransform end;
|
||||
end.setIdentity();
|
||||
|
||||
btScalar fraction = btScalar( 1.0 );
|
||||
|
||||
// This optimization scheme suffers in the corners.
|
||||
// It basically jumps from a wall to another, then fails to find a new
|
||||
// position (after 4 iterations here) and finally don't move at all.
|
||||
//
|
||||
// The stepping algorithm adds some problems with stairs. It seems
|
||||
// the treads create some fake corner using capsules for collisions.
|
||||
//
|
||||
for( int i = 0; i < 4 && fraction > btScalar( 0.01 ); i++ )
|
||||
{
|
||||
start.setOrigin( currentPosition );
|
||||
end.setOrigin( targetPosition );
|
||||
|
||||
btVector3 sweepDirNegative = currentPosition - targetPosition;
|
||||
|
||||
btKinematicClosestNotMeConvexResultCallback callback( externalGhostObject, sweepDirNegative, btScalar( 0.0 ) );
|
||||
callback.m_collisionFilterGroup = externalGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
callback.m_collisionFilterMask = externalGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
||||
if( m_useGhostObjectSweepTest )
|
||||
externalGhostObject->convexSweepTest( convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration );
|
||||
|
||||
else
|
||||
collisionWorld->convexSweepTest( convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration );
|
||||
|
||||
if( callback.hasHit() )
|
||||
{
|
||||
// Try another target position
|
||||
//
|
||||
targetPosition = slideOnCollision( currentPosition, targetPosition, callback.m_hitNormalWorld );
|
||||
fraction = callback.m_closestHitFraction;
|
||||
}
|
||||
else
|
||||
|
||||
// Move to the valid target position
|
||||
//
|
||||
return targetPosition;
|
||||
}
|
||||
|
||||
// Don't move if you can't find a valid target position...
|
||||
// It prevents some flickering.
|
||||
//
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
|
||||
///Handle the gravity
|
||||
btScalar btKinematicCharacterController::addFallOffset( bool wasOnGround, btScalar currentStepOffset, btScalar dt )
|
||||
{
|
||||
btScalar downVelocity = ( m_verticalVelocity < 0.0 ? -m_verticalVelocity : btScalar( 0.0 ) ) * dt;
|
||||
|
||||
if( downVelocity > btScalar( 0.0 ) && downVelocity < m_stepHeight && ( wasOnGround || !m_wasJumping ) )
|
||||
downVelocity = m_stepHeight;
|
||||
|
||||
return currentStepOffset + downVelocity;
|
||||
}
|
||||
|
||||
|
||||
btVector3 btKinematicCharacterController::stepDown( btCollisionWorld* collisionWorld, const btVector3& currentPosition, btScalar currentStepOffset )
|
||||
{
|
||||
btVector3 stepDrop = getUpAxisDirections()[ m_upAxis ] * currentStepOffset;
|
||||
|
||||
// Be sure we are falling from the last m_currentPosition
|
||||
// It prevents some flickering
|
||||
//
|
||||
btVector3 targetPosition = currentPosition - stepDrop;
|
||||
|
||||
//if the no collisions mode is on, no need to go any further
|
||||
if(!mCollision) return targetPosition;
|
||||
|
||||
btTransform start;
|
||||
start.setIdentity();
|
||||
start.setOrigin( currentPosition );
|
||||
|
||||
btTransform end;
|
||||
end.setIdentity();
|
||||
end.setOrigin( targetPosition );
|
||||
|
||||
btKinematicClosestNotMeConvexResultCallback callback( internalGhostObject, getUpAxisDirections()[ m_upAxis ], m_maxSlopeCosine );
|
||||
callback.m_collisionFilterGroup = internalGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
callback.m_collisionFilterMask = internalGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
||||
// Retrieve the collision shape
|
||||
//
|
||||
btCollisionShape* collisionShape = internalGhostObject->getCollisionShape();
|
||||
btAssert( collisionShape->isConvex() );
|
||||
btConvexShape* convexShape = ( btConvexShape* )collisionShape;
|
||||
|
||||
if( m_useGhostObjectSweepTest )
|
||||
externalGhostObject->convexSweepTest( convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration );
|
||||
|
||||
else
|
||||
collisionWorld->convexSweepTest( convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration );
|
||||
|
||||
if( callback.hasHit() )
|
||||
{
|
||||
m_verticalVelocity = btScalar( 0.0 );
|
||||
m_verticalOffset = btScalar( 0.0 );
|
||||
m_wasJumping = false;
|
||||
|
||||
// We dropped a fraction of the height -> hit floor
|
||||
//
|
||||
return currentPosition.lerp( targetPosition, callback.m_closestHitFraction );
|
||||
}
|
||||
else
|
||||
|
||||
// We dropped the full height
|
||||
//
|
||||
return targetPosition;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void btKinematicCharacterController::setWalkDirection( const btVector3& walkDirection )
|
||||
{
|
||||
m_useWalkDirection = true;
|
||||
m_walkDirection = walkDirection;
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::setVelocityForTimeInterval( const btVector3& velocity, btScalar timeInterval )
|
||||
{
|
||||
m_useWalkDirection = false;
|
||||
m_walkDirection = velocity;
|
||||
m_velocityTimeInterval = timeInterval;
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::reset()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::warp( const btVector3& origin )
|
||||
{
|
||||
btTransform transform;
|
||||
transform.setIdentity();
|
||||
transform.setOrigin( -origin );
|
||||
|
||||
externalGhostObject->setWorldTransform( transform );
|
||||
internalGhostObject->setWorldTransform( transform );
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::preStep( btCollisionWorld* collisionWorld )
|
||||
{
|
||||
BT_PROFILE( "preStep" );
|
||||
|
||||
for( int i = 0; i < 4 && recoverFromPenetration ( collisionWorld ); i++ );
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::playerStep( btCollisionWorld* collisionWorld, btScalar dt )
|
||||
{
|
||||
BT_PROFILE( "playerStep" );
|
||||
|
||||
if( !m_useWalkDirection && m_velocityTimeInterval <= btScalar( 0.0 ) )
|
||||
return;
|
||||
|
||||
bool wasOnGround = onGround();
|
||||
|
||||
// Handle the gravity
|
||||
//
|
||||
m_verticalVelocity -= m_gravity * dt;
|
||||
|
||||
if( m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed )
|
||||
m_verticalVelocity = m_jumpSpeed;
|
||||
|
||||
if( m_verticalVelocity < 0.0 && btFabs( m_verticalVelocity ) > btFabs( m_fallSpeed ) )
|
||||
m_verticalVelocity = -btFabs( m_fallSpeed );
|
||||
|
||||
m_verticalOffset = m_verticalVelocity * dt;
|
||||
|
||||
// This forced stepping up can cause problems when the character
|
||||
// walks (jump in fact...) under too low ceilings.
|
||||
//
|
||||
btVector3 currentPosition = externalGhostObject->getWorldTransform().getOrigin();
|
||||
btScalar currentStepOffset;
|
||||
|
||||
currentPosition = stepUp( collisionWorld, currentPosition, currentStepOffset );
|
||||
|
||||
// Move in the air and slide against the walls ignoring the stair steps.
|
||||
//
|
||||
if( m_useWalkDirection )
|
||||
currentPosition = stepForwardAndStrafe( collisionWorld, currentPosition, m_walkDirection );
|
||||
|
||||
else
|
||||
{
|
||||
btScalar dtMoving = ( dt < m_velocityTimeInterval ) ? dt : m_velocityTimeInterval;
|
||||
m_velocityTimeInterval -= dt;
|
||||
|
||||
// How far will we move while we are moving ?
|
||||
//
|
||||
btVector3 moveDirection = m_walkDirection * dtMoving;
|
||||
|
||||
currentPosition = stepForwardAndStrafe( collisionWorld, currentPosition, moveDirection );
|
||||
}
|
||||
|
||||
// Finally find the ground.
|
||||
//
|
||||
currentStepOffset = addFallOffset( wasOnGround, currentStepOffset, dt );
|
||||
|
||||
currentPosition = stepDown( collisionWorld, currentPosition, currentStepOffset );
|
||||
|
||||
// Apply the new position to the collision objects.
|
||||
//
|
||||
btTransform tranform;
|
||||
tranform = externalGhostObject->getWorldTransform();
|
||||
tranform.setOrigin( currentPosition );
|
||||
|
||||
externalGhostObject->setWorldTransform( tranform );
|
||||
internalGhostObject->setWorldTransform( tranform );
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::setFallSpeed( btScalar fallSpeed )
|
||||
{
|
||||
m_fallSpeed = fallSpeed;
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::setJumpSpeed( btScalar jumpSpeed )
|
||||
{
|
||||
m_jumpSpeed = jumpSpeed;
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::setMaxJumpHeight( btScalar maxJumpHeight )
|
||||
{
|
||||
m_maxJumpHeight = maxJumpHeight;
|
||||
}
|
||||
|
||||
|
||||
bool btKinematicCharacterController::canJump() const
|
||||
{
|
||||
return onGround();
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::jump()
|
||||
{
|
||||
if( !canJump() )
|
||||
return;
|
||||
|
||||
m_verticalVelocity = m_jumpSpeed;
|
||||
m_wasJumping = true;
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::setGravity( btScalar gravity )
|
||||
{
|
||||
m_gravity = gravity;
|
||||
}
|
||||
|
||||
|
||||
btScalar btKinematicCharacterController::getGravity() const
|
||||
{
|
||||
return m_gravity;
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::setMaxSlope( btScalar slopeRadians )
|
||||
{
|
||||
m_maxSlopeRadians = slopeRadians;
|
||||
m_maxSlopeCosine = btCos( slopeRadians );
|
||||
}
|
||||
|
||||
|
||||
btScalar btKinematicCharacterController::getMaxSlope() const
|
||||
{
|
||||
return m_maxSlopeRadians;
|
||||
}
|
||||
|
||||
|
||||
bool btKinematicCharacterController::onGround() const
|
||||
{
|
||||
return btFabs( m_verticalVelocity ) < btScalar( SIMD_EPSILON ) &&
|
||||
btFabs( m_verticalOffset ) < btScalar( SIMD_EPSILON );
|
||||
}
|
||||
|
||||
|
||||
btVector3* btKinematicCharacterController::getUpAxisDirections()
|
||||
{
|
||||
static btVector3 sUpAxisDirection[] =
|
||||
{
|
||||
btVector3( btScalar( 0.0 ), btScalar( 0.0 ), btScalar( 0.0 ) ),
|
||||
btVector3( btScalar( 0.0 ), btScalar( 1.0 ), btScalar( 0.0 ) ),
|
||||
btVector3( btScalar( 0.0 ), btScalar( 0.0 ), btScalar( 1.0 ) )
|
||||
};
|
||||
|
||||
return sUpAxisDirection;
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::debugDraw( btIDebugDraw* debugDrawer )
|
||||
{
|
||||
}
|
168
libs/openengine/bullet/btKinematicCharacterController.h
Normal file
168
libs/openengine/bullet/btKinematicCharacterController.h
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef KINEMATIC_CHARACTER_CONTROLLER_H
|
||||
#define KINEMATIC_CHARACTER_CONTROLLER_H
|
||||
|
||||
#include "LinearMath/btVector3.h"
|
||||
#include "LinearMath/btQuickprof.h"
|
||||
|
||||
#include "BulletDynamics/Character/btCharacterControllerInterface.h"
|
||||
|
||||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
|
||||
|
||||
|
||||
class btCollisionShape;
|
||||
class btRigidBody;
|
||||
class btCollisionWorld;
|
||||
class btCollisionDispatcher;
|
||||
class btPairCachingGhostObject;
|
||||
|
||||
///btKinematicCharacterController is an object that supports a sliding motion in a world.
|
||||
///It uses a ghost object and convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations.
|
||||
///Interaction between btKinematicCharacterController and dynamic rigid bodies needs to be explicity implemented by the user.
|
||||
class btKinematicCharacterController : public btCharacterControllerInterface
|
||||
{
|
||||
public:
|
||||
enum UpAxis
|
||||
{
|
||||
X_AXIS = 0,
|
||||
Y_AXIS = 1,
|
||||
Z_AXIS = 2
|
||||
};
|
||||
|
||||
private:
|
||||
btPairCachingGhostObject* externalGhostObject; // use this for querying collisions for sliding and move
|
||||
btPairCachingGhostObject* internalGhostObject; // and this for recoreving from penetrations
|
||||
|
||||
btScalar m_verticalVelocity;
|
||||
btScalar m_verticalOffset;
|
||||
btScalar m_fallSpeed;
|
||||
btScalar m_jumpSpeed;
|
||||
btScalar m_maxJumpHeight;
|
||||
btScalar m_maxSlopeRadians; // Slope angle that is set (used for returning the exact value)
|
||||
btScalar m_maxSlopeCosine; // Cosine equivalent of m_maxSlopeRadians (calculated once when set, for optimization)
|
||||
btScalar m_gravity;
|
||||
btScalar m_recoveringFactor;
|
||||
|
||||
btScalar m_stepHeight;
|
||||
|
||||
///this is the desired walk direction, set by the user
|
||||
btVector3 m_walkDirection;
|
||||
|
||||
///keep track of the contact manifolds
|
||||
btManifoldArray m_manifoldArray;
|
||||
|
||||
///Gravity attributes
|
||||
bool m_wasJumping;
|
||||
|
||||
bool m_useGhostObjectSweepTest;
|
||||
bool m_useWalkDirection;
|
||||
btScalar m_velocityTimeInterval;
|
||||
|
||||
UpAxis m_upAxis;
|
||||
|
||||
static btVector3* getUpAxisDirections();
|
||||
|
||||
bool recoverFromPenetration ( btCollisionWorld* collisionWorld );
|
||||
|
||||
btVector3 stepUp( btCollisionWorld* collisionWorld, const btVector3& currentPosition, btScalar& currentStepOffset );
|
||||
btVector3 stepForwardAndStrafe( btCollisionWorld* collisionWorld, const btVector3& currentPosition, const btVector3& walkMove );
|
||||
btScalar addFallOffset( bool wasJumping, btScalar currentStepOffset, btScalar dt );
|
||||
btVector3 stepDown( btCollisionWorld* collisionWorld, const btVector3& currentPosition, btScalar currentStepOffset );
|
||||
|
||||
public:
|
||||
/// externalGhostObject is used for querying the collisions for sliding along the wall,
|
||||
/// and internalGhostObject is used for querying the collisions for recovering from large penetrations.
|
||||
/// These parameters can point on the same object.
|
||||
/// Using a smaller internalGhostObject can help for removing some flickering but create some
|
||||
/// stopping artefacts when sliding along stairs or small walls.
|
||||
/// Don't forget to scale gravity and fallSpeed if you scale the world.
|
||||
btKinematicCharacterController( btPairCachingGhostObject* externalGhostObject,
|
||||
btPairCachingGhostObject* internalGhostObject,
|
||||
btScalar stepHeight,
|
||||
btScalar constantScale = btScalar( 1.0 ),
|
||||
btScalar gravity = btScalar( 9.8 ),
|
||||
btScalar fallVelocity = btScalar( 55.0 ),
|
||||
btScalar jumpVelocity = btScalar( 9.8 ),
|
||||
btScalar recoveringFactor = btScalar( 0.2 ) );
|
||||
|
||||
~btKinematicCharacterController ();
|
||||
|
||||
void setVerticalVelocity(float z);
|
||||
|
||||
///btActionInterface interface
|
||||
virtual void updateAction( btCollisionWorld* collisionWorld, btScalar deltaTime )
|
||||
{
|
||||
preStep( collisionWorld );
|
||||
playerStep( collisionWorld, deltaTime );
|
||||
}
|
||||
|
||||
///btActionInterface interface
|
||||
void debugDraw( btIDebugDraw* debugDrawer );
|
||||
|
||||
void setUpAxis( UpAxis axis )
|
||||
{
|
||||
m_upAxis = axis;
|
||||
}
|
||||
|
||||
/// This should probably be called setPositionIncrementPerSimulatorStep.
|
||||
/// This is neither a direction nor a velocity, but the amount to
|
||||
/// increment the position each simulation iteration, regardless
|
||||
/// of dt.
|
||||
/// This call will reset any velocity set by setVelocityForTimeInterval().
|
||||
virtual void setWalkDirection(const btVector3& walkDirection);
|
||||
|
||||
/// Caller provides a velocity with which the character should move for
|
||||
/// the given time period. After the time period, velocity is reset
|
||||
/// to zero.
|
||||
/// This call will reset any walk direction set by setWalkDirection().
|
||||
/// Negative time intervals will result in no motion.
|
||||
virtual void setVelocityForTimeInterval(const btVector3& velocity,
|
||||
btScalar timeInterval);
|
||||
|
||||
void reset();
|
||||
void warp( const btVector3& origin );
|
||||
|
||||
void preStep( btCollisionWorld* collisionWorld );
|
||||
void playerStep( btCollisionWorld* collisionWorld, btScalar dt );
|
||||
|
||||
void setFallSpeed( btScalar fallSpeed );
|
||||
void setJumpSpeed( btScalar jumpSpeed );
|
||||
void setMaxJumpHeight( btScalar maxJumpHeight );
|
||||
bool canJump() const;
|
||||
|
||||
void jump();
|
||||
|
||||
void setGravity( btScalar gravity );
|
||||
btScalar getGravity() const;
|
||||
|
||||
/// The max slope determines the maximum angle that the controller can walk up.
|
||||
/// The slope angle is measured in radians.
|
||||
void setMaxSlope( btScalar slopeRadians );
|
||||
btScalar getMaxSlope() const;
|
||||
|
||||
void setUseGhostSweepTest( bool useGhostObjectSweepTest )
|
||||
{
|
||||
m_useGhostObjectSweepTest = useGhostObjectSweepTest;
|
||||
}
|
||||
|
||||
bool onGround() const;
|
||||
|
||||
//if set to false, there will be no collision.
|
||||
bool mCollision;
|
||||
};
|
||||
|
||||
#endif // KINEMATIC_CHARACTER_CONTROLLER_H
|
799
libs/openengine/bullet/physic.cpp
Normal file
799
libs/openengine/bullet/physic.cpp
Normal file
|
@ -0,0 +1,799 @@
|
|||
#include "physic.hpp"
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <btBulletCollisionCommon.h>
|
||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||
#include <components/nifbullet/bulletnifloader.hpp>
|
||||
#include "CMotionState.h"
|
||||
#include "OgreRoot.h"
|
||||
#include "btKinematicCharacterController.h"
|
||||
#include "BtOgrePG.h"
|
||||
#include "BtOgreGP.h"
|
||||
#include "BtOgreExtras.h"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
namespace OEngine {
|
||||
namespace Physic
|
||||
{
|
||||
|
||||
PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale)
|
||||
: mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0)
|
||||
, mBody(0), mRaycastingBody(0), mOnGround(false), mCollisionMode(true), mBoxRotation(0,0,0,0)
|
||||
, mForce(0.0f)
|
||||
{
|
||||
mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation);
|
||||
mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation, true);
|
||||
Ogre::Quaternion inverse = mBoxRotation.Inverse();
|
||||
mBoxRotationInverse = btQuaternion(inverse.x, inverse.y, inverse.z,inverse.w);
|
||||
mEngine->addRigidBody(mBody, false, mRaycastingBody,true); //Add rigid body to dynamics world, but do not add to object map
|
||||
}
|
||||
|
||||
PhysicActor::~PhysicActor()
|
||||
{
|
||||
if(mBody)
|
||||
{
|
||||
mEngine->dynamicsWorld->removeRigidBody(mBody);
|
||||
delete mBody;
|
||||
}
|
||||
if(mRaycastingBody)
|
||||
{
|
||||
mEngine->dynamicsWorld->removeRigidBody(mRaycastingBody);
|
||||
delete mRaycastingBody;
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicActor::enableCollisions(bool collision)
|
||||
{
|
||||
assert(mBody);
|
||||
if(collision && !mCollisionMode) enableCollisionBody();
|
||||
if(!collision && mCollisionMode) disableCollisionBody();
|
||||
mCollisionMode = collision;
|
||||
}
|
||||
|
||||
|
||||
void PhysicActor::setPosition(const Ogre::Vector3 &pos)
|
||||
{
|
||||
assert(mBody);
|
||||
if(pos != getPosition())
|
||||
{
|
||||
mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation);
|
||||
mEngine->adjustRigidBody(mRaycastingBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation);
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicActor::setRotation(const Ogre::Quaternion &quat)
|
||||
{
|
||||
assert(mBody);
|
||||
if(!quat.equals(getRotation(), Ogre::Radian(0))){
|
||||
mEngine->adjustRigidBody(mBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation);
|
||||
mEngine->adjustRigidBody(mRaycastingBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Ogre::Vector3 PhysicActor::getPosition()
|
||||
{
|
||||
assert(mBody);
|
||||
btVector3 vec = mBody->getWorldTransform().getOrigin();
|
||||
Ogre::Quaternion rotation = Ogre::Quaternion(mBody->getWorldTransform().getRotation().getW(), mBody->getWorldTransform().getRotation().getX(),
|
||||
mBody->getWorldTransform().getRotation().getY(), mBody->getWorldTransform().getRotation().getZ());
|
||||
Ogre::Vector3 transrot = rotation * mBoxScaledTranslation;
|
||||
Ogre::Vector3 visualPosition = Ogre::Vector3(vec.getX(), vec.getY(), vec.getZ()) - transrot;
|
||||
return visualPosition;
|
||||
}
|
||||
|
||||
Ogre::Quaternion PhysicActor::getRotation()
|
||||
{
|
||||
assert(mBody);
|
||||
btQuaternion quat = mBody->getWorldTransform().getRotation() * mBoxRotationInverse;
|
||||
return Ogre::Quaternion(quat.getW(), quat.getX(), quat.getY(), quat.getZ());
|
||||
}
|
||||
|
||||
void PhysicActor::setScale(float scale){
|
||||
//We only need to change the scaled box translation, box rotations remain the same.
|
||||
assert(mBody);
|
||||
mBoxScaledTranslation = mBoxScaledTranslation / mBody->getCollisionShape()->getLocalScaling().getX();
|
||||
mBoxScaledTranslation *= scale;
|
||||
Ogre::Vector3 pos = getPosition();
|
||||
Ogre::Quaternion rot = getRotation();
|
||||
if(mBody){
|
||||
mEngine->dynamicsWorld->removeRigidBody(mBody);
|
||||
mEngine->dynamicsWorld->removeRigidBody(mRaycastingBody);
|
||||
delete mBody;
|
||||
delete mRaycastingBody;
|
||||
}
|
||||
//Create the newly scaled rigid body
|
||||
mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, pos, rot);
|
||||
mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, pos, rot, 0, 0, true);
|
||||
mEngine->addRigidBody(mBody, false, mRaycastingBody,true); //Add rigid body to dynamics world, but do not add to object map
|
||||
}
|
||||
|
||||
Ogre::Vector3 PhysicActor::getHalfExtents() const
|
||||
{
|
||||
if(mBody)
|
||||
{
|
||||
btBoxShape *box = static_cast<btBoxShape*>(mBody->getCollisionShape());
|
||||
if(box != NULL)
|
||||
{
|
||||
btVector3 size = box->getHalfExtentsWithMargin();
|
||||
return Ogre::Vector3(size.getX(), size.getY(), size.getZ());
|
||||
}
|
||||
}
|
||||
return Ogre::Vector3(0.0f);
|
||||
}
|
||||
|
||||
void PhysicActor::setInertialForce(const Ogre::Vector3 &force)
|
||||
{
|
||||
mForce = force;
|
||||
}
|
||||
|
||||
void PhysicActor::setOnGround(bool grounded)
|
||||
{
|
||||
mOnGround = grounded;
|
||||
}
|
||||
|
||||
void PhysicActor::disableCollisionBody()
|
||||
{
|
||||
mEngine->dynamicsWorld->removeRigidBody(mBody);
|
||||
}
|
||||
|
||||
void PhysicActor::enableCollisionBody()
|
||||
{
|
||||
mEngine->dynamicsWorld->addRigidBody(mBody,CollisionType_Actor,CollisionType_World|CollisionType_HeightMap);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
RigidBody::RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name)
|
||||
: btRigidBody(CI)
|
||||
, mName(name)
|
||||
, mPlaceable(false)
|
||||
{
|
||||
}
|
||||
|
||||
RigidBody::~RigidBody()
|
||||
{
|
||||
delete getMotionState();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
PhysicEngine::PhysicEngine(BulletShapeLoader* shapeLoader) :
|
||||
mDebugActive(0)
|
||||
, mSceneMgr(NULL)
|
||||
{
|
||||
// Set up the collision configuration and dispatcher
|
||||
collisionConfiguration = new btDefaultCollisionConfiguration();
|
||||
dispatcher = new btCollisionDispatcher(collisionConfiguration);
|
||||
|
||||
// The actual physics solver
|
||||
solver = new btSequentialImpulseConstraintSolver;
|
||||
|
||||
//btOverlappingPairCache* pairCache = new btSortedOverlappingPairCache();
|
||||
pairCache = new btSortedOverlappingPairCache();
|
||||
|
||||
//pairCache->setInternalGhostPairCallback( new btGhostPairCallback() );
|
||||
|
||||
broadphase = new btDbvtBroadphase();
|
||||
|
||||
// The world.
|
||||
dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);
|
||||
dynamicsWorld->setGravity(btVector3(0,0,-10));
|
||||
|
||||
if(BulletShapeManager::getSingletonPtr() == NULL)
|
||||
{
|
||||
new BulletShapeManager();
|
||||
}
|
||||
//TODO:singleton?
|
||||
mShapeLoader = shapeLoader;
|
||||
|
||||
isDebugCreated = false;
|
||||
mDebugDrawer = NULL;
|
||||
}
|
||||
|
||||
void PhysicEngine::createDebugRendering()
|
||||
{
|
||||
if(!isDebugCreated)
|
||||
{
|
||||
Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
|
||||
mDebugDrawer = new BtOgre::DebugDrawer(node, dynamicsWorld);
|
||||
dynamicsWorld->setDebugDrawer(mDebugDrawer);
|
||||
isDebugCreated = true;
|
||||
dynamicsWorld->debugDrawWorld();
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicEngine::setDebugRenderingMode(int mode)
|
||||
{
|
||||
if(!isDebugCreated)
|
||||
{
|
||||
createDebugRendering();
|
||||
}
|
||||
mDebugDrawer->setDebugMode(mode);
|
||||
mDebugActive = mode;
|
||||
}
|
||||
|
||||
bool PhysicEngine::toggleDebugRendering()
|
||||
{
|
||||
setDebugRenderingMode(!mDebugActive);
|
||||
return mDebugActive;
|
||||
}
|
||||
|
||||
void PhysicEngine::setSceneManager(Ogre::SceneManager* sceneMgr)
|
||||
{
|
||||
mSceneMgr = sceneMgr;
|
||||
}
|
||||
|
||||
PhysicEngine::~PhysicEngine()
|
||||
{
|
||||
HeightFieldContainer::iterator hf_it = mHeightFieldMap.begin();
|
||||
for (; hf_it != mHeightFieldMap.end(); ++hf_it)
|
||||
{
|
||||
dynamicsWorld->removeRigidBody(hf_it->second.mBody);
|
||||
delete hf_it->second.mShape;
|
||||
delete hf_it->second.mBody;
|
||||
}
|
||||
|
||||
RigidBodyContainer::iterator rb_it = mCollisionObjectMap.begin();
|
||||
for (; rb_it != mCollisionObjectMap.end(); ++rb_it)
|
||||
{
|
||||
if (rb_it->second != NULL)
|
||||
{
|
||||
dynamicsWorld->removeRigidBody(rb_it->second);
|
||||
|
||||
delete rb_it->second;
|
||||
rb_it->second = NULL;
|
||||
}
|
||||
}
|
||||
rb_it = mRaycastingObjectMap.begin();
|
||||
for (; rb_it != mRaycastingObjectMap.end(); ++rb_it)
|
||||
{
|
||||
if (rb_it->second != NULL)
|
||||
{
|
||||
dynamicsWorld->removeRigidBody(rb_it->second);
|
||||
|
||||
delete rb_it->second;
|
||||
rb_it->second = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PhysicActorContainer::iterator pa_it = mActorMap.begin();
|
||||
for (; pa_it != mActorMap.end(); ++pa_it)
|
||||
{
|
||||
if (pa_it->second != NULL)
|
||||
{
|
||||
delete pa_it->second;
|
||||
pa_it->second = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
delete mDebugDrawer;
|
||||
|
||||
delete dynamicsWorld;
|
||||
delete solver;
|
||||
delete collisionConfiguration;
|
||||
delete dispatcher;
|
||||
delete broadphase;
|
||||
delete pairCache;
|
||||
delete mShapeLoader;
|
||||
|
||||
delete BulletShapeManager::getSingletonPtr();
|
||||
}
|
||||
|
||||
void PhysicEngine::addHeightField(float* heights,
|
||||
int x, int y, float yoffset,
|
||||
float triSize, float sqrtVerts)
|
||||
{
|
||||
const std::string name = "HeightField_"
|
||||
+ boost::lexical_cast<std::string>(x) + "_"
|
||||
+ boost::lexical_cast<std::string>(y);
|
||||
|
||||
// find the minimum and maximum heights (needed for bullet)
|
||||
float minh = heights[0];
|
||||
float maxh = heights[0];
|
||||
for (int i=0; i<sqrtVerts*sqrtVerts; ++i)
|
||||
{
|
||||
float h = heights[i];
|
||||
|
||||
if (h>maxh) maxh = h;
|
||||
if (h<minh) minh = h;
|
||||
}
|
||||
|
||||
btHeightfieldTerrainShape* hfShape = new btHeightfieldTerrainShape(
|
||||
sqrtVerts, sqrtVerts, heights, 1,
|
||||
minh, maxh, 2,
|
||||
PHY_FLOAT,true);
|
||||
|
||||
hfShape->setUseDiamondSubdivision(true);
|
||||
|
||||
btVector3 scl(triSize, triSize, 1);
|
||||
hfShape->setLocalScaling(scl);
|
||||
|
||||
CMotionState* newMotionState = new CMotionState(this,name);
|
||||
|
||||
btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,newMotionState,hfShape);
|
||||
RigidBody* body = new RigidBody(CI,name);
|
||||
body->getWorldTransform().setOrigin(btVector3( (x+0.5)*triSize*(sqrtVerts-1), (y+0.5)*triSize*(sqrtVerts-1), (maxh+minh)/2.f));
|
||||
|
||||
HeightField hf;
|
||||
hf.mBody = body;
|
||||
hf.mShape = hfShape;
|
||||
|
||||
mHeightFieldMap [name] = hf;
|
||||
|
||||
dynamicsWorld->addRigidBody(body,CollisionType_HeightMap|CollisionType_Raycasting,
|
||||
CollisionType_World|CollisionType_Actor|CollisionType_Raycasting);
|
||||
}
|
||||
|
||||
void PhysicEngine::removeHeightField(int x, int y)
|
||||
{
|
||||
const std::string name = "HeightField_"
|
||||
+ boost::lexical_cast<std::string>(x) + "_"
|
||||
+ boost::lexical_cast<std::string>(y);
|
||||
|
||||
HeightField hf = mHeightFieldMap [name];
|
||||
|
||||
dynamicsWorld->removeRigidBody(hf.mBody);
|
||||
delete hf.mShape;
|
||||
delete hf.mBody;
|
||||
|
||||
mHeightFieldMap.erase(name);
|
||||
}
|
||||
|
||||
void PhysicEngine::adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation,
|
||||
const Ogre::Vector3 &scaledBoxTranslation, const Ogre::Quaternion &boxRotation)
|
||||
{
|
||||
btTransform tr;
|
||||
Ogre::Quaternion boxrot = rotation * boxRotation;
|
||||
Ogre::Vector3 transrot = boxrot * scaledBoxTranslation;
|
||||
Ogre::Vector3 newPosition = transrot + position;
|
||||
|
||||
tr.setOrigin(btVector3(newPosition.x, newPosition.y, newPosition.z));
|
||||
tr.setRotation(btQuaternion(boxrot.x,boxrot.y,boxrot.z,boxrot.w));
|
||||
body->setWorldTransform(tr);
|
||||
}
|
||||
void PhysicEngine::boxAdjustExternal(const std::string &mesh, RigidBody* body,
|
||||
float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation)
|
||||
{
|
||||
std::string sid = (boost::format("%07.3f") % scale).str();
|
||||
std::string outputstring = mesh + sid;
|
||||
//std::cout << "The string" << outputstring << "\n";
|
||||
|
||||
//get the shape from the .nif
|
||||
mShapeLoader->load(outputstring,"General");
|
||||
BulletShapeManager::getSingletonPtr()->load(outputstring,"General");
|
||||
BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General");
|
||||
|
||||
adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation);
|
||||
}
|
||||
|
||||
RigidBody* PhysicEngine::createAndAdjustRigidBody(const std::string &mesh, const std::string &name,
|
||||
float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation,
|
||||
Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool raycasting, bool placeable)
|
||||
{
|
||||
std::string sid = (boost::format("%07.3f") % scale).str();
|
||||
std::string outputstring = mesh + sid;
|
||||
|
||||
//get the shape from the .nif
|
||||
mShapeLoader->load(outputstring,"General");
|
||||
BulletShapeManager::getSingletonPtr()->load(outputstring,"General");
|
||||
BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General");
|
||||
|
||||
if (placeable && !raycasting && shape->mCollisionShape && !shape->mHasCollisionNode)
|
||||
return NULL;
|
||||
|
||||
if (!shape->mCollisionShape && !raycasting)
|
||||
return NULL;
|
||||
if (!shape->mRaycastingShape && raycasting)
|
||||
return NULL;
|
||||
|
||||
if (!raycasting)
|
||||
shape->mCollisionShape->setLocalScaling( btVector3(scale,scale,scale));
|
||||
else
|
||||
shape->mRaycastingShape->setLocalScaling( btVector3(scale,scale,scale));
|
||||
|
||||
//create the motionState
|
||||
CMotionState* newMotionState = new CMotionState(this,name);
|
||||
|
||||
//create the real body
|
||||
btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo
|
||||
(0,newMotionState, raycasting ? shape->mRaycastingShape : shape->mCollisionShape);
|
||||
RigidBody* body = new RigidBody(CI,name);
|
||||
body->mPlaceable = placeable;
|
||||
|
||||
if(scaledBoxTranslation != 0)
|
||||
*scaledBoxTranslation = shape->mBoxTranslation * scale;
|
||||
if(boxRotation != 0)
|
||||
*boxRotation = shape->mBoxRotation;
|
||||
|
||||
adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation);
|
||||
|
||||
return body;
|
||||
|
||||
}
|
||||
|
||||
void PhysicEngine::addRigidBody(RigidBody* body, bool addToMap, RigidBody* raycastingBody,bool actor)
|
||||
{
|
||||
if(!body && !raycastingBody)
|
||||
return; // nothing to do
|
||||
|
||||
const std::string& name = (body ? body->mName : raycastingBody->mName);
|
||||
|
||||
if (body){
|
||||
if(actor) dynamicsWorld->addRigidBody(body,CollisionType_Actor,CollisionType_World|CollisionType_HeightMap);
|
||||
else dynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_Actor|CollisionType_HeightMap);
|
||||
}
|
||||
|
||||
if (raycastingBody)
|
||||
dynamicsWorld->addRigidBody(raycastingBody,CollisionType_Raycasting,CollisionType_Raycasting|CollisionType_World);
|
||||
|
||||
if(addToMap){
|
||||
removeRigidBody(name);
|
||||
deleteRigidBody(name);
|
||||
|
||||
if (body)
|
||||
mCollisionObjectMap[name] = body;
|
||||
if (raycastingBody)
|
||||
mRaycastingObjectMap[name] = raycastingBody;
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicEngine::removeRigidBody(const std::string &name)
|
||||
{
|
||||
RigidBodyContainer::iterator it = mCollisionObjectMap.find(name);
|
||||
if (it != mCollisionObjectMap.end() )
|
||||
{
|
||||
RigidBody* body = it->second;
|
||||
if(body != NULL)
|
||||
{
|
||||
dynamicsWorld->removeRigidBody(body);
|
||||
}
|
||||
}
|
||||
it = mRaycastingObjectMap.find(name);
|
||||
if (it != mRaycastingObjectMap.end() )
|
||||
{
|
||||
RigidBody* body = it->second;
|
||||
if(body != NULL)
|
||||
{
|
||||
dynamicsWorld->removeRigidBody(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicEngine::deleteRigidBody(const std::string &name)
|
||||
{
|
||||
RigidBodyContainer::iterator it = mCollisionObjectMap.find(name);
|
||||
if (it != mCollisionObjectMap.end() )
|
||||
{
|
||||
RigidBody* body = it->second;
|
||||
|
||||
if(body != NULL)
|
||||
{
|
||||
delete body;
|
||||
}
|
||||
mCollisionObjectMap.erase(it);
|
||||
}
|
||||
it = mRaycastingObjectMap.find(name);
|
||||
if (it != mRaycastingObjectMap.end() )
|
||||
{
|
||||
RigidBody* body = it->second;
|
||||
|
||||
if(body != NULL)
|
||||
{
|
||||
delete body;
|
||||
}
|
||||
mRaycastingObjectMap.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
RigidBody* PhysicEngine::getRigidBody(const std::string &name, bool raycasting)
|
||||
{
|
||||
RigidBodyContainer* map = raycasting ? &mRaycastingObjectMap : &mCollisionObjectMap;
|
||||
RigidBodyContainer::iterator it = map->find(name);
|
||||
if (it != map->end() )
|
||||
{
|
||||
RigidBody* body = (*map)[name];
|
||||
return body;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback
|
||||
{
|
||||
public:
|
||||
std::vector<std::string> mResult;
|
||||
|
||||
// added in bullet 2.81
|
||||
// this is just a quick hack, as there does not seem to be a BULLET_VERSION macro?
|
||||
#if defined(BT_COLLISION_OBJECT_WRAPPER_H)
|
||||
virtual btScalar addSingleResult(btManifoldPoint& cp,
|
||||
const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0,
|
||||
const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1)
|
||||
{
|
||||
const RigidBody* body = dynamic_cast<const RigidBody*>(colObj0Wrap->m_collisionObject);
|
||||
if (body && !(colObj0Wrap->m_collisionObject->getBroadphaseHandle()->m_collisionFilterGroup
|
||||
& CollisionType_Raycasting))
|
||||
mResult.push_back(body->mName);
|
||||
|
||||
return 0.f;
|
||||
}
|
||||
#else
|
||||
virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0,
|
||||
const btCollisionObject* col1, int partId1, int index1)
|
||||
{
|
||||
const RigidBody* body = dynamic_cast<const RigidBody*>(col0);
|
||||
if (body && !(col0->getBroadphaseHandle()->m_collisionFilterGroup
|
||||
& CollisionType_Raycasting))
|
||||
mResult.push_back(body->mName);
|
||||
|
||||
return 0.f;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback
|
||||
{
|
||||
const std::string &mFilter;
|
||||
// Store the real origin, since the shape's origin is its center
|
||||
btVector3 mOrigin;
|
||||
|
||||
public:
|
||||
const RigidBody *mObject;
|
||||
btVector3 mContactPoint;
|
||||
btScalar mLeastDistSqr;
|
||||
|
||||
DeepestNotMeContactTestResultCallback(const std::string &filter, const btVector3 &origin)
|
||||
: mFilter(filter), mOrigin(origin), mObject(0), mContactPoint(0,0,0),
|
||||
mLeastDistSqr(std::numeric_limits<float>::max())
|
||||
{ }
|
||||
|
||||
#if defined(BT_COLLISION_OBJECT_WRAPPER_H)
|
||||
virtual btScalar addSingleResult(btManifoldPoint& cp,
|
||||
const btCollisionObjectWrapper* col0Wrap,int partId0,int index0,
|
||||
const btCollisionObjectWrapper* col1Wrap,int partId1,int index1)
|
||||
{
|
||||
const RigidBody* body = dynamic_cast<const RigidBody*>(col1Wrap->m_collisionObject);
|
||||
if(body && body->mName != mFilter)
|
||||
{
|
||||
btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA());
|
||||
if(!mObject || distsqr < mLeastDistSqr)
|
||||
{
|
||||
mObject = body;
|
||||
mLeastDistSqr = distsqr;
|
||||
mContactPoint = cp.getPositionWorldOnA();
|
||||
}
|
||||
}
|
||||
|
||||
return 0.f;
|
||||
}
|
||||
#else
|
||||
virtual btScalar addSingleResult(btManifoldPoint& cp,
|
||||
const btCollisionObject* col0, int partId0, int index0,
|
||||
const btCollisionObject* col1, int partId1, int index1)
|
||||
{
|
||||
const RigidBody* body = dynamic_cast<const RigidBody*>(col1);
|
||||
if(body && body->mName != mFilter)
|
||||
{
|
||||
btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA());
|
||||
if(!mObject || distsqr < mLeastDistSqr)
|
||||
{
|
||||
mObject = body;
|
||||
mLeastDistSqr = distsqr;
|
||||
mContactPoint = cp.getPositionWorldOnA();
|
||||
}
|
||||
}
|
||||
|
||||
return 0.f;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
std::vector<std::string> PhysicEngine::getCollisions(const std::string& name)
|
||||
{
|
||||
RigidBody* body = getRigidBody(name);
|
||||
ContactTestResultCallback callback;
|
||||
dynamicsWorld->contactTest(body, callback);
|
||||
return callback.mResult;
|
||||
}
|
||||
|
||||
|
||||
std::pair<const RigidBody*,btVector3> PhysicEngine::getFilteredContact(const std::string &filter,
|
||||
const btVector3 &origin,
|
||||
btCollisionObject *object)
|
||||
{
|
||||
DeepestNotMeContactTestResultCallback callback(filter, origin);
|
||||
dynamicsWorld->contactTest(object, callback);
|
||||
return std::make_pair(callback.mObject, callback.mContactPoint);
|
||||
}
|
||||
|
||||
|
||||
void PhysicEngine::stepSimulation(double deltaT)
|
||||
{
|
||||
// This seems to be needed for character controller objects
|
||||
dynamicsWorld->stepSimulation(deltaT,10, 1/60.0);
|
||||
if(isDebugCreated)
|
||||
{
|
||||
mDebugDrawer->step();
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicEngine::addCharacter(const std::string &name, const std::string &mesh,
|
||||
const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation)
|
||||
{
|
||||
// Remove character with given name, so we don't make memory
|
||||
// leak when character would be added twice
|
||||
removeCharacter(name);
|
||||
|
||||
PhysicActor* newActor = new PhysicActor(name, mesh, this, position, rotation, scale);
|
||||
|
||||
|
||||
//dynamicsWorld->addAction( newActor->mCharacter );
|
||||
mActorMap[name] = newActor;
|
||||
}
|
||||
|
||||
void PhysicEngine::removeCharacter(const std::string &name)
|
||||
{
|
||||
PhysicActorContainer::iterator it = mActorMap.find(name);
|
||||
if (it != mActorMap.end() )
|
||||
{
|
||||
PhysicActor* act = it->second;
|
||||
if(act != NULL)
|
||||
{
|
||||
|
||||
delete act;
|
||||
}
|
||||
mActorMap.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
PhysicActor* PhysicEngine::getCharacter(const std::string &name)
|
||||
{
|
||||
PhysicActorContainer::iterator it = mActorMap.find(name);
|
||||
if (it != mActorMap.end() )
|
||||
{
|
||||
PhysicActor* act = mActorMap[name];
|
||||
return act;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicEngine::emptyEventLists(void)
|
||||
{
|
||||
}
|
||||
|
||||
std::pair<std::string,float> PhysicEngine::rayTest(btVector3& from,btVector3& to,bool raycastingObjectOnly,bool ignoreHeightMap)
|
||||
{
|
||||
std::string name = "";
|
||||
float d = -1;
|
||||
|
||||
btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to);
|
||||
if(raycastingObjectOnly)
|
||||
resultCallback1.m_collisionFilterMask = CollisionType_Raycasting;
|
||||
else
|
||||
resultCallback1.m_collisionFilterMask = CollisionType_World;
|
||||
|
||||
if(!ignoreHeightMap)
|
||||
resultCallback1.m_collisionFilterMask = resultCallback1.m_collisionFilterMask | CollisionType_HeightMap;
|
||||
dynamicsWorld->rayTest(from, to, resultCallback1);
|
||||
if (resultCallback1.hasHit())
|
||||
{
|
||||
name = static_cast<const RigidBody&>(*resultCallback1.m_collisionObject).mName;
|
||||
d = resultCallback1.m_closestHitFraction;;
|
||||
}
|
||||
|
||||
return std::pair<std::string,float>(name,d);
|
||||
}
|
||||
|
||||
// callback that ignores player in results
|
||||
struct OurClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
|
||||
{
|
||||
public:
|
||||
OurClosestConvexResultCallback(const btVector3& convexFromWorld,const btVector3& convexToWorld)
|
||||
: btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld) {}
|
||||
|
||||
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
|
||||
{
|
||||
if (const RigidBody* body = dynamic_cast<const RigidBody*>(convexResult.m_hitCollisionObject))
|
||||
if (body->mName == "player")
|
||||
return 0;
|
||||
return btCollisionWorld::ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
|
||||
}
|
||||
};
|
||||
|
||||
std::pair<bool, float> PhysicEngine::sphereCast (float radius, btVector3& from, btVector3& to)
|
||||
{
|
||||
OurClosestConvexResultCallback callback(from, to);
|
||||
callback.m_collisionFilterMask = OEngine::Physic::CollisionType_World|OEngine::Physic::CollisionType_HeightMap;
|
||||
|
||||
btSphereShape shape(radius);
|
||||
const btQuaternion btrot(0.0f, 0.0f, 0.0f);
|
||||
|
||||
btTransform from_ (btrot, from);
|
||||
btTransform to_ (btrot, to);
|
||||
|
||||
dynamicsWorld->convexSweepTest(&shape, from_, to_, callback);
|
||||
|
||||
if (callback.hasHit())
|
||||
return std::make_pair(true, callback.m_closestHitFraction);
|
||||
else
|
||||
return std::make_pair(false, 1);
|
||||
}
|
||||
|
||||
std::vector< std::pair<float, std::string> > PhysicEngine::rayTest2(btVector3& from, btVector3& to)
|
||||
{
|
||||
MyRayResultCallback resultCallback1;
|
||||
resultCallback1.m_collisionFilterMask = CollisionType_Raycasting;
|
||||
dynamicsWorld->rayTest(from, to, resultCallback1);
|
||||
std::vector< std::pair<float, const btCollisionObject*> > results = resultCallback1.results;
|
||||
|
||||
std::vector< std::pair<float, std::string> > results2;
|
||||
|
||||
for (std::vector< std::pair<float, const btCollisionObject*> >::iterator it=results.begin();
|
||||
it != results.end(); ++it)
|
||||
{
|
||||
results2.push_back( std::make_pair( (*it).first, static_cast<const RigidBody&>(*(*it).second).mName ) );
|
||||
}
|
||||
|
||||
std::sort(results2.begin(), results2.end(), MyRayResultCallback::cmp);
|
||||
|
||||
return results2;
|
||||
}
|
||||
|
||||
void PhysicEngine::getObjectAABB(const std::string &mesh, float scale, btVector3 &min, btVector3 &max)
|
||||
{
|
||||
std::string sid = (boost::format("%07.3f") % scale).str();
|
||||
std::string outputstring = mesh + sid;
|
||||
|
||||
mShapeLoader->load(outputstring, "General");
|
||||
BulletShapeManager::getSingletonPtr()->load(outputstring, "General");
|
||||
BulletShapePtr shape =
|
||||
BulletShapeManager::getSingleton().getByName(outputstring, "General");
|
||||
|
||||
btTransform trans;
|
||||
trans.setIdentity();
|
||||
|
||||
if (shape->mRaycastingShape)
|
||||
shape->mRaycastingShape->getAabb(trans, min, max);
|
||||
else if (shape->mCollisionShape)
|
||||
shape->mCollisionShape->getAabb(trans, min, max);
|
||||
else
|
||||
{
|
||||
min = btVector3(0,0,0);
|
||||
max = btVector3(0,0,0);
|
||||
}
|
||||
}
|
||||
|
||||
bool PhysicEngine::isAnyActorStandingOn (const std::string& objectName)
|
||||
{
|
||||
for (PhysicActorContainer::iterator it = mActorMap.begin(); it != mActorMap.end(); ++it)
|
||||
{
|
||||
if (!it->second->getOnGround())
|
||||
continue;
|
||||
Ogre::Vector3 pos = it->second->getPosition();
|
||||
btVector3 from (pos.x, pos.y, pos.z);
|
||||
btVector3 to = from - btVector3(0,0,5);
|
||||
std::pair<std::string, float> result = rayTest(from, to);
|
||||
if (result.first == objectName)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
389
libs/openengine/bullet/physic.hpp
Normal file
389
libs/openengine/bullet/physic.hpp
Normal file
|
@ -0,0 +1,389 @@
|
|||
#ifndef OENGINE_BULLET_PHYSIC_H
|
||||
#define OENGINE_BULLET_PHYSIC_H
|
||||
|
||||
#include <BulletDynamics/Dynamics/btRigidBody.h>
|
||||
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include "BulletShapeLoader.h"
|
||||
#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h"
|
||||
|
||||
|
||||
|
||||
class btRigidBody;
|
||||
class btBroadphaseInterface;
|
||||
class btDefaultCollisionConfiguration;
|
||||
class btSequentialImpulseConstraintSolver;
|
||||
class btCollisionDispatcher;
|
||||
class btDiscreteDynamicsWorld;
|
||||
class btHeightfieldTerrainShape;
|
||||
|
||||
namespace BtOgre
|
||||
{
|
||||
class DebugDrawer;
|
||||
}
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
class SceneManager;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class World;
|
||||
}
|
||||
|
||||
|
||||
namespace OEngine {
|
||||
namespace Physic
|
||||
{
|
||||
class CMotionState;
|
||||
struct PhysicEvent;
|
||||
class PhysicEngine;
|
||||
class RigidBody;
|
||||
|
||||
enum CollisionType {
|
||||
CollisionType_Nothing = 0, //<Collide with nothing
|
||||
CollisionType_World = 1<<0, //<Collide with world objects
|
||||
CollisionType_Actor = 1<<1, //<Collide sith actors
|
||||
CollisionType_HeightMap = 1<<2, //<collide with heightmap
|
||||
CollisionType_Raycasting = 1<<3 //Still used?
|
||||
};
|
||||
|
||||
/**
|
||||
*This is just used to be able to name objects.
|
||||
*/
|
||||
class PairCachingGhostObject : public btPairCachingGhostObject
|
||||
{
|
||||
public:
|
||||
PairCachingGhostObject(std::string name)
|
||||
:btPairCachingGhostObject(),mName(name)
|
||||
{
|
||||
}
|
||||
virtual ~PairCachingGhostObject(){}
|
||||
|
||||
std::string mName;
|
||||
};
|
||||
|
||||
/**
|
||||
*This class is just an extension of normal btRigidBody in order to add extra info.
|
||||
*When bullet give back a btRigidBody, you can just do a static_cast to RigidBody,
|
||||
*so one never should use btRigidBody directly!
|
||||
*/
|
||||
class RigidBody: public btRigidBody
|
||||
{
|
||||
public:
|
||||
RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name);
|
||||
virtual ~RigidBody();
|
||||
std::string mName;
|
||||
bool mPlaceable;
|
||||
};
|
||||
|
||||
/**
|
||||
* A physic actor uses a rigid body based on box shapes.
|
||||
* Pmove is used to move the physic actor around the dynamic world.
|
||||
*/
|
||||
class PhysicActor
|
||||
{
|
||||
public:
|
||||
PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale);
|
||||
|
||||
~PhysicActor();
|
||||
|
||||
void setPosition(const Ogre::Vector3 &pos);
|
||||
|
||||
/**
|
||||
* This adjusts the rotation of a PhysicActor
|
||||
* If we have any problems with this (getting stuck in pmove) we should change it
|
||||
* from setting the visual orientation to setting the orientation of the rigid body directly.
|
||||
*/
|
||||
void setRotation(const Ogre::Quaternion &quat);
|
||||
|
||||
void enableCollisions(bool collision);
|
||||
|
||||
bool getCollisionMode() const
|
||||
{
|
||||
return mCollisionMode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This returns the visual position of the PhysicActor (used to position a scenenode).
|
||||
* Note - this is different from the position of the contained mBody.
|
||||
*/
|
||||
Ogre::Vector3 getPosition();
|
||||
|
||||
/**
|
||||
* Returns the visual orientation of the PhysicActor
|
||||
*/
|
||||
Ogre::Quaternion getRotation();
|
||||
|
||||
/**
|
||||
* Sets the scale of the PhysicActor
|
||||
*/
|
||||
void setScale(float scale);
|
||||
|
||||
/**
|
||||
* Returns the half extents for this PhysiActor
|
||||
*/
|
||||
Ogre::Vector3 getHalfExtents() const;
|
||||
|
||||
/**
|
||||
* Sets the current amount of inertial force (incl. gravity) affecting this physic actor
|
||||
*/
|
||||
void setInertialForce(const Ogre::Vector3 &force);
|
||||
|
||||
/**
|
||||
* Gets the current amount of inertial force (incl. gravity) affecting this physic actor
|
||||
*/
|
||||
const Ogre::Vector3 &getInertialForce() const
|
||||
{
|
||||
return mForce;
|
||||
}
|
||||
|
||||
void setOnGround(bool grounded);
|
||||
|
||||
bool getOnGround() const
|
||||
{
|
||||
return mCollisionMode && mOnGround;
|
||||
}
|
||||
|
||||
btCollisionObject *getCollisionBody() const
|
||||
{
|
||||
return mBody;
|
||||
}
|
||||
|
||||
private:
|
||||
void disableCollisionBody();
|
||||
void enableCollisionBody();
|
||||
public:
|
||||
//HACK: in Visual Studio 2010 and presumably above, this structures alignment
|
||||
// must be 16, but the built in operator new & delete don't properly
|
||||
// perform this alignment.
|
||||
#if _MSC_VER >= 1600
|
||||
void * operator new (size_t Size) { return _aligned_malloc (Size, 16); }
|
||||
void operator delete (void * Data) { _aligned_free (Data); }
|
||||
#endif
|
||||
|
||||
|
||||
private:
|
||||
OEngine::Physic::RigidBody* mBody;
|
||||
OEngine::Physic::RigidBody* mRaycastingBody;
|
||||
|
||||
Ogre::Vector3 mBoxScaledTranslation;
|
||||
Ogre::Quaternion mBoxRotation;
|
||||
btQuaternion mBoxRotationInverse;
|
||||
|
||||
Ogre::Vector3 mForce;
|
||||
bool mOnGround;
|
||||
bool mCollisionMode;
|
||||
|
||||
std::string mMesh;
|
||||
std::string mName;
|
||||
PhysicEngine *mEngine;
|
||||
};
|
||||
|
||||
|
||||
struct HeightField
|
||||
{
|
||||
btHeightfieldTerrainShape* mShape;
|
||||
RigidBody* mBody;
|
||||
};
|
||||
|
||||
/**
|
||||
* The PhysicEngine class contain everything which is needed for Physic.
|
||||
* It's needed that Ogre Resources are set up before the PhysicEngine is created.
|
||||
* Note:deleting it WILL NOT delete the RigidBody!
|
||||
* TODO:unload unused resources?
|
||||
*/
|
||||
class PhysicEngine
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Note that the shapeLoader IS destroyed by the phyic Engine!!
|
||||
*/
|
||||
PhysicEngine(BulletShapeLoader* shapeLoader);
|
||||
|
||||
/**
|
||||
* It DOES destroy the shape loader!
|
||||
*/
|
||||
~PhysicEngine();
|
||||
|
||||
/**
|
||||
* Creates a RigidBody. It does not add it to the simulation.
|
||||
* After created, the body is set to the correct rotation, position, and scale
|
||||
*/
|
||||
RigidBody* createAndAdjustRigidBody(const std::string &mesh, const std::string &name,
|
||||
float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation,
|
||||
Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0, bool raycasting=false, bool placeable=false);
|
||||
|
||||
/**
|
||||
* Adjusts a rigid body to the right position and rotation
|
||||
*/
|
||||
|
||||
void adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation,
|
||||
const Ogre::Vector3 &scaledBoxTranslation = Ogre::Vector3::ZERO,
|
||||
const Ogre::Quaternion &boxRotation = Ogre::Quaternion::IDENTITY);
|
||||
/**
|
||||
Mainly used to (but not limited to) adjust rigid bodies based on box shapes to the right position and rotation.
|
||||
*/
|
||||
void boxAdjustExternal(const std::string &mesh, RigidBody* body, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation);
|
||||
/**
|
||||
* Add a HeightField to the simulation
|
||||
*/
|
||||
void addHeightField(float* heights,
|
||||
int x, int y, float yoffset,
|
||||
float triSize, float sqrtVerts);
|
||||
|
||||
/**
|
||||
* Remove a HeightField from the simulation
|
||||
*/
|
||||
void removeHeightField(int x, int y);
|
||||
|
||||
/**
|
||||
* Add a RigidBody to the simulation
|
||||
*/
|
||||
void addRigidBody(RigidBody* body, bool addToMap = true, RigidBody* raycastingBody = NULL,bool actor = false);
|
||||
|
||||
/**
|
||||
* Remove a RigidBody from the simulation. It does not delete it, and does not remove it from the RigidBodyMap.
|
||||
*/
|
||||
void removeRigidBody(const std::string &name);
|
||||
|
||||
/**
|
||||
* Delete a RigidBody, and remove it from RigidBodyMap.
|
||||
*/
|
||||
void deleteRigidBody(const std::string &name);
|
||||
|
||||
/**
|
||||
* Return a pointer to a given rigid body.
|
||||
*/
|
||||
RigidBody* getRigidBody(const std::string &name, bool raycasting=false);
|
||||
|
||||
/**
|
||||
* Create and add a character to the scene, and add it to the ActorMap.
|
||||
*/
|
||||
void addCharacter(const std::string &name, const std::string &mesh,
|
||||
const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation);
|
||||
|
||||
/**
|
||||
* Remove a character from the scene. TODO:delete it! for now, a small memory leak^^ done?
|
||||
*/
|
||||
void removeCharacter(const std::string &name);
|
||||
|
||||
/**
|
||||
* Return a pointer to a character
|
||||
* TODO:check if the actor exist...
|
||||
*/
|
||||
PhysicActor* getCharacter(const std::string &name);
|
||||
|
||||
/**
|
||||
* This step the simulation of a given time.
|
||||
*/
|
||||
void stepSimulation(double deltaT);
|
||||
|
||||
/**
|
||||
* Empty events lists
|
||||
*/
|
||||
void emptyEventLists(void);
|
||||
|
||||
/**
|
||||
* Create a debug rendering. It is called by setDebgRenderingMode if it's not created yet.
|
||||
* Important Note: this will crash if the Render is not yet initialise!
|
||||
*/
|
||||
void createDebugRendering();
|
||||
|
||||
/**
|
||||
* Set the debug rendering mode. 0 to turn it off.
|
||||
* Important Note: this will crash if the Render is not yet initialise!
|
||||
*/
|
||||
void setDebugRenderingMode(int mode);
|
||||
|
||||
bool toggleDebugRendering();
|
||||
|
||||
void getObjectAABB(const std::string &mesh, float scale, btVector3 &min, btVector3 &max);
|
||||
|
||||
void setSceneManager(Ogre::SceneManager* sceneMgr);
|
||||
|
||||
bool isAnyActorStandingOn (const std::string& objectName);
|
||||
|
||||
/**
|
||||
* Return the closest object hit by a ray. If there are no objects, it will return ("",-1).
|
||||
*/
|
||||
std::pair<std::string,float> rayTest(btVector3& from,btVector3& to,bool raycastingObjectOnly = true,bool ignoreHeightMap = false);
|
||||
|
||||
/**
|
||||
* Return all objects hit by a ray.
|
||||
*/
|
||||
std::vector< std::pair<float, std::string> > rayTest2(btVector3& from, btVector3& to);
|
||||
|
||||
std::pair<bool, float> sphereCast (float radius, btVector3& from, btVector3& to);
|
||||
///< @return (hit, relative distance)
|
||||
|
||||
std::vector<std::string> getCollisions(const std::string& name);
|
||||
|
||||
// Get the nearest object that's inside the given object, filtering out objects of the
|
||||
// provided name
|
||||
std::pair<const RigidBody*,btVector3> getFilteredContact(const std::string &filter,
|
||||
const btVector3 &origin,
|
||||
btCollisionObject *object);
|
||||
|
||||
//event list of non player object
|
||||
std::list<PhysicEvent> NPEventList;
|
||||
|
||||
//event list affecting the player
|
||||
std::list<PhysicEvent> PEventList;
|
||||
|
||||
//Bullet Stuff
|
||||
btOverlappingPairCache* pairCache;
|
||||
btBroadphaseInterface* broadphase;
|
||||
btDefaultCollisionConfiguration* collisionConfiguration;
|
||||
btSequentialImpulseConstraintSolver* solver;
|
||||
btCollisionDispatcher* dispatcher;
|
||||
btDiscreteDynamicsWorld* dynamicsWorld;
|
||||
|
||||
//the NIF file loader.
|
||||
BulletShapeLoader* mShapeLoader;
|
||||
|
||||
typedef std::map<std::string, HeightField> HeightFieldContainer;
|
||||
HeightFieldContainer mHeightFieldMap;
|
||||
|
||||
typedef std::map<std::string,RigidBody*> RigidBodyContainer;
|
||||
RigidBodyContainer mCollisionObjectMap;
|
||||
|
||||
RigidBodyContainer mRaycastingObjectMap;
|
||||
|
||||
typedef std::map<std::string, PhysicActor*> PhysicActorContainer;
|
||||
PhysicActorContainer mActorMap;
|
||||
|
||||
Ogre::SceneManager* mSceneMgr;
|
||||
|
||||
//debug rendering
|
||||
BtOgre::DebugDrawer* mDebugDrawer;
|
||||
bool isDebugCreated;
|
||||
bool mDebugActive;
|
||||
};
|
||||
|
||||
|
||||
struct MyRayResultCallback : public btCollisionWorld::RayResultCallback
|
||||
{
|
||||
virtual btScalar addSingleResult( btCollisionWorld::LocalRayResult& rayResult, bool bNormalInWorldSpace)
|
||||
{
|
||||
results.push_back( std::make_pair(rayResult.m_hitFraction, rayResult.m_collisionObject) );
|
||||
return rayResult.m_hitFraction;
|
||||
}
|
||||
|
||||
static bool cmp( const std::pair<float, std::string>& i, const std::pair<float, std::string>& j )
|
||||
{
|
||||
if( i.first > j.first ) return false;
|
||||
if( j.first > i.first ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector < std::pair<float, const btCollisionObject*> > results;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
130
libs/openengine/bullet/trace.cpp
Normal file
130
libs/openengine/bullet/trace.cpp
Normal file
|
@ -0,0 +1,130 @@
|
|||
|
||||
#include "trace.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <btBulletCollisionCommon.h>
|
||||
|
||||
#include "physic.hpp"
|
||||
|
||||
|
||||
namespace OEngine
|
||||
{
|
||||
namespace Physic
|
||||
{
|
||||
|
||||
class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
|
||||
{
|
||||
public:
|
||||
ClosestNotMeConvexResultCallback(btCollisionObject *me, const btVector3 &up, btScalar minSlopeDot)
|
||||
: btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)),
|
||||
mMe(me), mUp(up), mMinSlopeDot(minSlopeDot)
|
||||
{
|
||||
}
|
||||
|
||||
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
|
||||
{
|
||||
if(convexResult.m_hitCollisionObject == mMe)
|
||||
return btScalar( 1 );
|
||||
|
||||
btVector3 hitNormalWorld;
|
||||
if(normalInWorldSpace)
|
||||
hitNormalWorld = convexResult.m_hitNormalLocal;
|
||||
else
|
||||
{
|
||||
///need to transform normal into worldspace
|
||||
hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
|
||||
}
|
||||
|
||||
// NOTE : m_hitNormalLocal is not always vertical on the ground with a capsule or a box...
|
||||
|
||||
btScalar dotUp = mUp.dot(hitNormalWorld);
|
||||
if(dotUp < mMinSlopeDot)
|
||||
return btScalar(1);
|
||||
|
||||
return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
|
||||
}
|
||||
|
||||
protected:
|
||||
btCollisionObject *mMe;
|
||||
const btVector3 mUp;
|
||||
const btScalar mMinSlopeDot;
|
||||
};
|
||||
|
||||
|
||||
void ActorTracer::doTrace(btCollisionObject *actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, const PhysicEngine *enginePass)
|
||||
{
|
||||
const btVector3 btstart(start.x, start.y, start.z);
|
||||
const btVector3 btend(end.x, end.y, end.z);
|
||||
|
||||
const btTransform &trans = actor->getWorldTransform();
|
||||
btTransform from(trans);
|
||||
btTransform to(trans);
|
||||
from.setOrigin(btstart);
|
||||
to.setOrigin(btend);
|
||||
|
||||
ClosestNotMeConvexResultCallback newTraceCallback(actor, btstart-btend, btScalar(0.0));
|
||||
newTraceCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap |
|
||||
CollisionType_Actor;
|
||||
|
||||
btCollisionShape *shape = actor->getCollisionShape();
|
||||
assert(shape->isConvex());
|
||||
enginePass->dynamicsWorld->convexSweepTest(static_cast<btConvexShape*>(shape),
|
||||
from, to, newTraceCallback);
|
||||
|
||||
// Copy the hit data over to our trace results struct:
|
||||
if(newTraceCallback.hasHit())
|
||||
{
|
||||
const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld;
|
||||
mFraction = newTraceCallback.m_closestHitFraction;
|
||||
mPlaneNormal = Ogre::Vector3(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z());
|
||||
mEndPos = (end-start)*mFraction + start;
|
||||
}
|
||||
else
|
||||
{
|
||||
mEndPos = end;
|
||||
mPlaneNormal = Ogre::Vector3(0.0f, 0.0f, 1.0f);
|
||||
mFraction = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void ActorTracer::findGround(btCollisionObject *actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, const PhysicEngine *enginePass)
|
||||
{
|
||||
const btVector3 btstart(start.x, start.y, start.z+1.0f);
|
||||
const btVector3 btend(end.x, end.y, end.z+1.0f);
|
||||
|
||||
const btTransform &trans = actor->getWorldTransform();
|
||||
btTransform from(trans.getBasis(), btstart);
|
||||
btTransform to(trans.getBasis(), btend);
|
||||
|
||||
ClosestNotMeConvexResultCallback newTraceCallback(actor, btstart-btend, btScalar(0.0));
|
||||
newTraceCallback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap |
|
||||
CollisionType_Actor;
|
||||
|
||||
const btBoxShape *shape = dynamic_cast<btBoxShape*>(actor->getCollisionShape());
|
||||
assert(shape);
|
||||
|
||||
btVector3 halfExtents = shape->getHalfExtentsWithMargin();
|
||||
halfExtents[2] = 1.0f;
|
||||
btBoxShape box(halfExtents);
|
||||
|
||||
enginePass->dynamicsWorld->convexSweepTest(&box, from, to, newTraceCallback);
|
||||
if(newTraceCallback.hasHit())
|
||||
{
|
||||
const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld;
|
||||
mFraction = newTraceCallback.m_closestHitFraction;
|
||||
mPlaneNormal = Ogre::Vector3(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z());
|
||||
mEndPos = (end-start)*mFraction + start;
|
||||
mEndPos[2] -= 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
mEndPos = end;
|
||||
mPlaneNormal = Ogre::Vector3(0.0f, 0.0f, 1.0f);
|
||||
mFraction = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
31
libs/openengine/bullet/trace.h
Normal file
31
libs/openengine/bullet/trace.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef OENGINE_BULLET_TRACE_H
|
||||
#define OENGINE_BULLET_TRACE_H
|
||||
|
||||
#include <OgreVector3.h>
|
||||
|
||||
|
||||
class btCollisionObject;
|
||||
|
||||
|
||||
namespace OEngine
|
||||
{
|
||||
namespace Physic
|
||||
{
|
||||
class PhysicEngine;
|
||||
|
||||
struct ActorTracer
|
||||
{
|
||||
Ogre::Vector3 mEndPos;
|
||||
Ogre::Vector3 mPlaneNormal;
|
||||
|
||||
float mFraction;
|
||||
|
||||
void doTrace(btCollisionObject *actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end,
|
||||
const PhysicEngine *enginePass);
|
||||
void findGround(btCollisionObject *actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end,
|
||||
const PhysicEngine *enginePass);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
162
libs/openengine/gui/layout.hpp
Normal file
162
libs/openengine/gui/layout.hpp
Normal file
|
@ -0,0 +1,162 @@
|
|||
#ifndef OENGINE_MYGUI_LAYOUT_H
|
||||
#define OENGINE_MYGUI_LAYOUT_H
|
||||
|
||||
#include <MyGUI.h>
|
||||
|
||||
namespace OEngine {
|
||||
namespace GUI
|
||||
{
|
||||
/** The Layout class is an utility class used to load MyGUI layouts
|
||||
from xml files, and to manipulate member widgets.
|
||||
*/
|
||||
class Layout
|
||||
{
|
||||
public:
|
||||
Layout(const std::string & _layout, MyGUI::Widget* _parent = nullptr)
|
||||
: mMainWidget(nullptr)
|
||||
{ initialise(_layout, _parent); }
|
||||
virtual ~Layout() { shutdown(); }
|
||||
|
||||
template <typename T>
|
||||
void getWidget(T * & _widget, const std::string & _name, bool _throw = true)
|
||||
{
|
||||
_widget = nullptr;
|
||||
for (MyGUI::VectorWidgetPtr::iterator iter=mListWindowRoot.begin();
|
||||
iter!=mListWindowRoot.end(); ++iter)
|
||||
{
|
||||
MyGUI::Widget* find = (*iter)->findWidget(mPrefix + _name);
|
||||
if (nullptr != find)
|
||||
{
|
||||
T * cast = find->castType<T>(false);
|
||||
if (nullptr != cast)
|
||||
_widget = cast;
|
||||
else if (_throw)
|
||||
{
|
||||
MYGUI_EXCEPT("Error cast : dest type = '" << T::getClassTypeName()
|
||||
<< "' source name = '" << find->getName()
|
||||
<< "' source type = '" << find->getTypeName() << "' in layout '" << mLayoutName << "'");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
MYGUI_ASSERT( ! _throw, "widget name '" << _name << "' in layout '" << mLayoutName << "' not found.");
|
||||
}
|
||||
|
||||
void initialise(const std::string & _layout,
|
||||
MyGUI::Widget* _parent = nullptr)
|
||||
{
|
||||
const std::string MAIN_WINDOW = "_Main";
|
||||
mLayoutName = _layout;
|
||||
|
||||
if (mLayoutName.empty())
|
||||
mMainWidget = _parent;
|
||||
else
|
||||
{
|
||||
mPrefix = MyGUI::utility::toString(this, "_");
|
||||
mListWindowRoot = MyGUI::LayoutManager::getInstance().loadLayout(mLayoutName, mPrefix, _parent);
|
||||
|
||||
const std::string main_name = mPrefix + MAIN_WINDOW;
|
||||
for (MyGUI::VectorWidgetPtr::iterator iter=mListWindowRoot.begin(); iter!=mListWindowRoot.end(); ++iter)
|
||||
{
|
||||
if ((*iter)->getName() == main_name)
|
||||
{
|
||||
mMainWidget = (*iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
MYGUI_ASSERT(mMainWidget, "root widget name '" << MAIN_WINDOW << "' in layout '" << mLayoutName << "' not found.");
|
||||
}
|
||||
}
|
||||
|
||||
void shutdown()
|
||||
{
|
||||
MyGUI::Gui::getInstance().destroyWidget(mMainWidget);
|
||||
mListWindowRoot.clear();
|
||||
}
|
||||
|
||||
void setCoord(int x, int y, int w, int h)
|
||||
{
|
||||
mMainWidget->setCoord(x,y,w,h);
|
||||
}
|
||||
|
||||
void adjustWindowCaption()
|
||||
{
|
||||
// adjust the size of the window caption so that all text is visible
|
||||
// NOTE: this assumes that mMainWidget is of type Window.
|
||||
MyGUI::TextBox* box = static_cast<MyGUI::Window*>(mMainWidget)->getCaptionWidget();
|
||||
box->setSize(box->getTextSize().width + 24, box->getSize().height);
|
||||
|
||||
// in order to trigger alignment updates, we need to update the parent
|
||||
// mygui doesn't provide a proper way of doing this, so we are just changing size
|
||||
box->getParent()->setCoord(MyGUI::IntCoord(
|
||||
box->getParent()->getCoord().left,
|
||||
box->getParent()->getCoord().top,
|
||||
box->getParent()->getCoord().width,
|
||||
box->getParent()->getCoord().height+1
|
||||
));
|
||||
box->getParent()->setCoord(MyGUI::IntCoord(
|
||||
box->getParent()->getCoord().left,
|
||||
box->getParent()->getCoord().top,
|
||||
box->getParent()->getCoord().width,
|
||||
box->getParent()->getCoord().height-1
|
||||
));
|
||||
}
|
||||
|
||||
virtual void setVisible(bool b)
|
||||
{
|
||||
mMainWidget->setVisible(b);
|
||||
}
|
||||
|
||||
void setText(const std::string& name, const std::string& caption)
|
||||
{
|
||||
MyGUI::Widget* pt;
|
||||
getWidget(pt, name);
|
||||
static_cast<MyGUI::TextBox*>(pt)->setCaption(caption);
|
||||
}
|
||||
|
||||
void setTitle(const std::string& title)
|
||||
{
|
||||
// NOTE: this assume that mMainWidget is of type Window.
|
||||
static_cast<MyGUI::Window*>(mMainWidget)->setCaptionWithReplacing(title);
|
||||
adjustWindowCaption();
|
||||
}
|
||||
|
||||
void setState(const std::string& widget, const std::string& state)
|
||||
{
|
||||
MyGUI::Widget* pt;
|
||||
getWidget(pt, widget);
|
||||
pt->_setWidgetState(state);
|
||||
}
|
||||
|
||||
void setTextColor(const std::string& name, float r, float g, float b)
|
||||
{
|
||||
MyGUI::Widget* pt;
|
||||
getWidget(pt, name);
|
||||
MyGUI::TextBox *st = dynamic_cast<MyGUI::TextBox*>(pt);
|
||||
if(st != NULL)
|
||||
st->setTextColour(MyGUI::Colour(b,g,r));
|
||||
}
|
||||
|
||||
void setImage(const std::string& name, const std::string& imgName)
|
||||
{
|
||||
MyGUI::ImageBox* pt;
|
||||
getWidget(pt, name);
|
||||
pt->setImageTexture(imgName);
|
||||
}
|
||||
|
||||
void adjustButtonSize(MyGUI::Button* button)
|
||||
{
|
||||
// adjust size of button to fit its text
|
||||
MyGUI::IntSize size = button->getTextSize();
|
||||
button->setSize(size.width + 24, button->getSize().height);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
MyGUI::Widget* mMainWidget;
|
||||
std::string mPrefix;
|
||||
std::string mLayoutName;
|
||||
MyGUI::VectorWidgetPtr mListWindowRoot;
|
||||
};
|
||||
}}
|
||||
#endif
|
652
libs/openengine/gui/manager.cpp
Normal file
652
libs/openengine/gui/manager.cpp
Normal file
|
@ -0,0 +1,652 @@
|
|||
#include "manager.hpp"
|
||||
|
||||
#include <MyGUI_Gui.h>
|
||||
#include <MyGUI_OgrePlatform.h>
|
||||
#include <MyGUI_Timer.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <extern/shiny/Main/Factory.hpp>
|
||||
#include <extern/shiny/Platforms/Ogre/OgreMaterial.hpp>
|
||||
|
||||
using namespace OEngine::GUI;
|
||||
|
||||
namespace MyGUI
|
||||
{
|
||||
|
||||
/*
|
||||
* As of MyGUI 3.2.0, MyGUI::OgreDataManager::isDataExist is unnecessarily complex
|
||||
* this override fixes the resulting performance issue.
|
||||
*/
|
||||
class FixedOgreDataManager : public MyGUI::OgreDataManager
|
||||
{
|
||||
public:
|
||||
bool isDataExist(const std::string& _name)
|
||||
{
|
||||
return Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup (_name);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* As of MyGUI 3.2.0, rendering with shaders is not supported.
|
||||
* We definitely need this though to run in GL3 core / DX11 at all.
|
||||
* To make matters worse, subclassing OgreRenderManager doesn't seem to be possible here. :/
|
||||
*/
|
||||
class ShaderBasedRenderManager : public RenderManager,
|
||||
public IRenderTarget,
|
||||
public Ogre::WindowEventListener,
|
||||
public Ogre::RenderQueueListener,
|
||||
public Ogre::RenderSystem::Listener
|
||||
{
|
||||
// флаг для обновления всех и вся
|
||||
bool mUpdate;
|
||||
|
||||
IntSize mViewSize;
|
||||
|
||||
Ogre::SceneManager* mSceneManager;
|
||||
|
||||
VertexColourType mVertexFormat;
|
||||
|
||||
// окно, на которое мы подписываемся для изменения размеров
|
||||
Ogre::RenderWindow* mWindow;
|
||||
|
||||
// вьюпорт, с которым работает система
|
||||
unsigned short mActiveViewport;
|
||||
|
||||
Ogre::RenderSystem* mRenderSystem;
|
||||
Ogre::TextureUnitState::UVWAddressingMode mTextureAddressMode;
|
||||
Ogre::LayerBlendModeEx mColorBlendMode, mAlphaBlendMode;
|
||||
|
||||
RenderTargetInfo mInfo;
|
||||
|
||||
typedef std::map<std::string, ITexture*> MapTexture;
|
||||
MapTexture mTextures;
|
||||
|
||||
bool mIsInitialise;
|
||||
bool mManualRender;
|
||||
size_t mCountBatch;
|
||||
|
||||
// ADDED
|
||||
Ogre::GpuProgram* mVertexProgramNoTexture;
|
||||
Ogre::GpuProgram* mVertexProgramOneTexture;
|
||||
Ogre::GpuProgram* mFragmentProgramNoTexture;
|
||||
Ogre::GpuProgram* mFragmentProgramOneTexture;
|
||||
|
||||
public:
|
||||
ShaderBasedRenderManager& getInstance()
|
||||
{
|
||||
return *getInstancePtr();
|
||||
}
|
||||
ShaderBasedRenderManager* getInstancePtr()
|
||||
{
|
||||
return static_cast<ShaderBasedRenderManager*>(RenderManager::getInstancePtr());
|
||||
}
|
||||
|
||||
ShaderBasedRenderManager() :
|
||||
mUpdate(false),
|
||||
mSceneManager(nullptr),
|
||||
mWindow(nullptr),
|
||||
mActiveViewport(0),
|
||||
mRenderSystem(nullptr),
|
||||
mIsInitialise(false),
|
||||
mManualRender(false),
|
||||
mCountBatch(0),
|
||||
mVertexProgramNoTexture(NULL),
|
||||
mFragmentProgramNoTexture(NULL),
|
||||
mVertexProgramOneTexture(NULL),
|
||||
mFragmentProgramOneTexture(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void initialise(Ogre::RenderWindow* _window, Ogre::SceneManager* _scene)
|
||||
{
|
||||
MYGUI_PLATFORM_ASSERT(!mIsInitialise, getClassTypeName() << " initialised twice");
|
||||
MYGUI_PLATFORM_LOG(Info, "* Initialise: " << getClassTypeName());
|
||||
|
||||
mColorBlendMode.blendType = Ogre::LBT_COLOUR;
|
||||
mColorBlendMode.source1 = Ogre::LBS_TEXTURE;
|
||||
mColorBlendMode.source2 = Ogre::LBS_DIFFUSE;
|
||||
mColorBlendMode.operation = Ogre::LBX_MODULATE;
|
||||
|
||||
mAlphaBlendMode.blendType = Ogre::LBT_ALPHA;
|
||||
mAlphaBlendMode.source1 = Ogre::LBS_TEXTURE;
|
||||
mAlphaBlendMode.source2 = Ogre::LBS_DIFFUSE;
|
||||
mAlphaBlendMode.operation = Ogre::LBX_MODULATE;
|
||||
|
||||
mTextureAddressMode.u = Ogre::TextureUnitState::TAM_CLAMP;
|
||||
mTextureAddressMode.v = Ogre::TextureUnitState::TAM_CLAMP;
|
||||
mTextureAddressMode.w = Ogre::TextureUnitState::TAM_CLAMP;
|
||||
|
||||
mSceneManager = nullptr;
|
||||
mWindow = nullptr;
|
||||
mUpdate = false;
|
||||
mRenderSystem = nullptr;
|
||||
mActiveViewport = 0;
|
||||
|
||||
Ogre::Root* root = Ogre::Root::getSingletonPtr();
|
||||
if (root != nullptr)
|
||||
setRenderSystem(root->getRenderSystem());
|
||||
setRenderWindow(_window);
|
||||
setSceneManager(_scene);
|
||||
|
||||
// ADDED
|
||||
sh::MaterialInstance* mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/NoTexture");
|
||||
sh::Factory::getInstance()._ensureMaterial("MyGUI/NoTexture", "Default");
|
||||
mVertexProgramNoTexture = static_cast<sh::OgreMaterial*>(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0)
|
||||
->getVertexProgram()->_getBindingDelegate();
|
||||
|
||||
mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/OneTexture");
|
||||
sh::Factory::getInstance()._ensureMaterial("MyGUI/OneTexture", "Default");
|
||||
mVertexProgramOneTexture = static_cast<sh::OgreMaterial*>(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0)
|
||||
->getVertexProgram()->_getBindingDelegate();
|
||||
|
||||
mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/NoTexture");
|
||||
sh::Factory::getInstance()._ensureMaterial("MyGUI/NoTexture", "Default");
|
||||
mFragmentProgramNoTexture = static_cast<sh::OgreMaterial*>(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0)
|
||||
->getFragmentProgram()->_getBindingDelegate();
|
||||
|
||||
mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/OneTexture");
|
||||
sh::Factory::getInstance()._ensureMaterial("MyGUI/OneTexture", "Default");
|
||||
mFragmentProgramOneTexture = static_cast<sh::OgreMaterial*>(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0)
|
||||
->getFragmentProgram()->_getBindingDelegate();
|
||||
|
||||
|
||||
|
||||
MYGUI_PLATFORM_LOG(Info, getClassTypeName() << " successfully initialized");
|
||||
mIsInitialise = true;
|
||||
}
|
||||
|
||||
void shutdown()
|
||||
{
|
||||
MYGUI_PLATFORM_ASSERT(mIsInitialise, getClassTypeName() << " is not initialised");
|
||||
MYGUI_PLATFORM_LOG(Info, "* Shutdown: " << getClassTypeName());
|
||||
|
||||
destroyAllResources();
|
||||
|
||||
setSceneManager(nullptr);
|
||||
setRenderWindow(nullptr);
|
||||
setRenderSystem(nullptr);
|
||||
|
||||
MYGUI_PLATFORM_LOG(Info, getClassTypeName() << " successfully shutdown");
|
||||
mIsInitialise = false;
|
||||
}
|
||||
|
||||
void setRenderSystem(Ogre::RenderSystem* _render)
|
||||
{
|
||||
// отписываемся
|
||||
if (mRenderSystem != nullptr)
|
||||
{
|
||||
mRenderSystem->removeListener(this);
|
||||
mRenderSystem = nullptr;
|
||||
}
|
||||
|
||||
mRenderSystem = _render;
|
||||
|
||||
// подписываемся на рендер евент
|
||||
if (mRenderSystem != nullptr)
|
||||
{
|
||||
mRenderSystem->addListener(this);
|
||||
|
||||
// формат цвета в вершинах
|
||||
Ogre::VertexElementType vertex_type = mRenderSystem->getColourVertexElementType();
|
||||
if (vertex_type == Ogre::VET_COLOUR_ARGB)
|
||||
mVertexFormat = VertexColourType::ColourARGB;
|
||||
else if (vertex_type == Ogre::VET_COLOUR_ABGR)
|
||||
mVertexFormat = VertexColourType::ColourABGR;
|
||||
|
||||
updateRenderInfo();
|
||||
}
|
||||
}
|
||||
|
||||
Ogre::RenderSystem* getRenderSystem()
|
||||
{
|
||||
return mRenderSystem;
|
||||
}
|
||||
|
||||
void setRenderWindow(Ogre::RenderWindow* _window)
|
||||
{
|
||||
// отписываемся
|
||||
if (mWindow != nullptr)
|
||||
{
|
||||
Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this);
|
||||
mWindow = nullptr;
|
||||
}
|
||||
|
||||
mWindow = _window;
|
||||
|
||||
if (mWindow != nullptr)
|
||||
{
|
||||
Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);
|
||||
windowResized(mWindow);
|
||||
}
|
||||
}
|
||||
|
||||
void setSceneManager(Ogre::SceneManager* _scene)
|
||||
{
|
||||
if (nullptr != mSceneManager)
|
||||
{
|
||||
mSceneManager->removeRenderQueueListener(this);
|
||||
mSceneManager = nullptr;
|
||||
}
|
||||
|
||||
mSceneManager = _scene;
|
||||
|
||||
if (nullptr != mSceneManager)
|
||||
{
|
||||
mSceneManager->addRenderQueueListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
void setActiveViewport(unsigned short _num)
|
||||
{
|
||||
mActiveViewport = _num;
|
||||
|
||||
if (mWindow != nullptr)
|
||||
{
|
||||
Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this);
|
||||
Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);
|
||||
|
||||
// рассылка обновлений
|
||||
windowResized(mWindow);
|
||||
}
|
||||
}
|
||||
|
||||
void renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation)
|
||||
{
|
||||
Gui* gui = Gui::getInstancePtr();
|
||||
if (gui == nullptr)
|
||||
return;
|
||||
|
||||
if (Ogre::RENDER_QUEUE_OVERLAY != queueGroupId)
|
||||
return;
|
||||
|
||||
Ogre::Viewport* viewport = mSceneManager->getCurrentViewport();
|
||||
if (nullptr == viewport
|
||||
|| !viewport->getOverlaysEnabled())
|
||||
return;
|
||||
|
||||
if (mWindow->getNumViewports() <= mActiveViewport
|
||||
|| viewport != mWindow->getViewport(mActiveViewport))
|
||||
return;
|
||||
|
||||
mCountBatch = 0;
|
||||
|
||||
static Timer timer;
|
||||
static unsigned long last_time = timer.getMilliseconds();
|
||||
unsigned long now_time = timer.getMilliseconds();
|
||||
unsigned long time = now_time - last_time;
|
||||
|
||||
onFrameEvent((float)((double)(time) / (double)1000));
|
||||
|
||||
last_time = now_time;
|
||||
|
||||
//begin();
|
||||
setManualRender(true);
|
||||
onRenderToTarget(this, mUpdate);
|
||||
//end();
|
||||
|
||||
// сбрасываем флаг
|
||||
mUpdate = false;
|
||||
}
|
||||
|
||||
void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation)
|
||||
{
|
||||
}
|
||||
|
||||
void eventOccurred(const Ogre::String& eventName, const Ogre::NameValuePairList* parameters)
|
||||
{
|
||||
if (eventName == "DeviceLost")
|
||||
{
|
||||
}
|
||||
else if (eventName == "DeviceRestored")
|
||||
{
|
||||
// обновить всех
|
||||
mUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
IVertexBuffer* createVertexBuffer()
|
||||
{
|
||||
return new OgreVertexBuffer();
|
||||
}
|
||||
|
||||
void destroyVertexBuffer(IVertexBuffer* _buffer)
|
||||
{
|
||||
delete _buffer;
|
||||
}
|
||||
|
||||
// для оповещений об изменении окна рендера
|
||||
void windowResized(Ogre::RenderWindow* _window)
|
||||
{
|
||||
if (_window->getNumViewports() > mActiveViewport)
|
||||
{
|
||||
Ogre::Viewport* port = _window->getViewport(mActiveViewport);
|
||||
#if OGRE_VERSION >= MYGUI_DEFINE_VERSION(1, 7, 0) && OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0
|
||||
Ogre::OrientationMode orient = port->getOrientationMode();
|
||||
if (orient == Ogre::OR_DEGREE_90 || orient == Ogre::OR_DEGREE_270)
|
||||
mViewSize.set(port->getActualHeight(), port->getActualWidth());
|
||||
else
|
||||
mViewSize.set(port->getActualWidth(), port->getActualHeight());
|
||||
#else
|
||||
mViewSize.set(port->getActualWidth(), port->getActualHeight());
|
||||
#endif
|
||||
|
||||
// обновить всех
|
||||
mUpdate = true;
|
||||
|
||||
updateRenderInfo();
|
||||
|
||||
onResizeView(mViewSize);
|
||||
}
|
||||
}
|
||||
|
||||
void updateRenderInfo()
|
||||
{
|
||||
if (mRenderSystem != nullptr)
|
||||
{
|
||||
mInfo.maximumDepth = mRenderSystem->getMaximumDepthInputValue();
|
||||
mInfo.hOffset = mRenderSystem->getHorizontalTexelOffset() / float(mViewSize.width);
|
||||
mInfo.vOffset = mRenderSystem->getVerticalTexelOffset() / float(mViewSize.height);
|
||||
mInfo.aspectCoef = float(mViewSize.height) / float(mViewSize.width);
|
||||
mInfo.pixScaleX = 1.0f / float(mViewSize.width);
|
||||
mInfo.pixScaleY = 1.0f / float(mViewSize.height);
|
||||
}
|
||||
}
|
||||
|
||||
void doRender(IVertexBuffer* _buffer, ITexture* _texture, size_t _count)
|
||||
{
|
||||
if (getManualRender())
|
||||
{
|
||||
begin();
|
||||
setManualRender(false);
|
||||
}
|
||||
|
||||
// ADDED
|
||||
|
||||
if (_texture)
|
||||
{
|
||||
Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mVertexProgramOneTexture);
|
||||
Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mFragmentProgramOneTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mVertexProgramNoTexture);
|
||||
Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mFragmentProgramNoTexture);
|
||||
}
|
||||
|
||||
if (_texture)
|
||||
{
|
||||
OgreTexture* texture = static_cast<OgreTexture*>(_texture);
|
||||
Ogre::TexturePtr texture_ptr = texture->getOgreTexture();
|
||||
if (!texture_ptr.isNull())
|
||||
{
|
||||
mRenderSystem->_setTexture(0, true, texture_ptr);
|
||||
mRenderSystem->_setTextureUnitFiltering(0, Ogre::FO_LINEAR, Ogre::FO_LINEAR, Ogre::FO_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
OgreVertexBuffer* buffer = static_cast<OgreVertexBuffer*>(_buffer);
|
||||
Ogre::RenderOperation* operation = buffer->getRenderOperation();
|
||||
operation->vertexData->vertexCount = _count;
|
||||
|
||||
mRenderSystem->_render(*operation);
|
||||
|
||||
++ mCountBatch;
|
||||
}
|
||||
|
||||
void begin()
|
||||
{
|
||||
// set-up matrices
|
||||
mRenderSystem->_setWorldMatrix(Ogre::Matrix4::IDENTITY);
|
||||
mRenderSystem->_setViewMatrix(Ogre::Matrix4::IDENTITY);
|
||||
|
||||
#if OGRE_VERSION >= MYGUI_DEFINE_VERSION(1, 7, 0) && OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0
|
||||
Ogre::OrientationMode orient = mWindow->getViewport(mActiveViewport)->getOrientationMode();
|
||||
mRenderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY * Ogre::Quaternion(Ogre::Degree(orient * 90.f), Ogre::Vector3::UNIT_Z));
|
||||
#else
|
||||
mRenderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY);
|
||||
#endif
|
||||
|
||||
// initialise render settings
|
||||
mRenderSystem->setLightingEnabled(false);
|
||||
mRenderSystem->_setDepthBufferParams(false, false);
|
||||
mRenderSystem->_setDepthBias(0, 0);
|
||||
mRenderSystem->_setCullingMode(Ogre::CULL_NONE);
|
||||
mRenderSystem->_setFog(Ogre::FOG_NONE);
|
||||
mRenderSystem->_setColourBufferWriteEnabled(true, true, true, true);
|
||||
mRenderSystem->unbindGpuProgram(Ogre::GPT_FRAGMENT_PROGRAM);
|
||||
mRenderSystem->unbindGpuProgram(Ogre::GPT_VERTEX_PROGRAM);
|
||||
mRenderSystem->setShadingType(Ogre::SO_GOURAUD);
|
||||
|
||||
// initialise texture settings
|
||||
mRenderSystem->_setTextureCoordCalculation(0, Ogre::TEXCALC_NONE);
|
||||
mRenderSystem->_setTextureCoordSet(0, 0);
|
||||
mRenderSystem->_setTextureUnitFiltering(0, Ogre::FO_LINEAR, Ogre::FO_LINEAR, Ogre::FO_NONE);
|
||||
mRenderSystem->_setTextureAddressingMode(0, mTextureAddressMode);
|
||||
mRenderSystem->_setTextureMatrix(0, Ogre::Matrix4::IDENTITY);
|
||||
#if OGRE_VERSION < MYGUI_DEFINE_VERSION(1, 6, 0)
|
||||
mRenderSystem->_setAlphaRejectSettings(Ogre::CMPF_ALWAYS_PASS, 0);
|
||||
#else
|
||||
mRenderSystem->_setAlphaRejectSettings(Ogre::CMPF_ALWAYS_PASS, 0, false);
|
||||
#endif
|
||||
mRenderSystem->_setTextureBlendMode(0, mColorBlendMode);
|
||||
mRenderSystem->_setTextureBlendMode(0, mAlphaBlendMode);
|
||||
mRenderSystem->_disableTextureUnitsFrom(1);
|
||||
|
||||
// enable alpha blending
|
||||
mRenderSystem->_setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA);
|
||||
|
||||
// always use wireframe
|
||||
// TODO: add option to enable wireframe mode in platform
|
||||
mRenderSystem->_setPolygonMode(Ogre::PM_SOLID);
|
||||
}
|
||||
|
||||
void end()
|
||||
{
|
||||
}
|
||||
|
||||
ITexture* createTexture(const std::string& _name)
|
||||
{
|
||||
MapTexture::const_iterator item = mTextures.find(_name);
|
||||
MYGUI_PLATFORM_ASSERT(item == mTextures.end(), "Texture '" << _name << "' already exist");
|
||||
|
||||
OgreTexture* texture = new OgreTexture(_name, OgreDataManager::getInstance().getGroup());
|
||||
mTextures[_name] = texture;
|
||||
return texture;
|
||||
}
|
||||
|
||||
void destroyTexture(ITexture* _texture)
|
||||
{
|
||||
if (_texture == nullptr) return;
|
||||
|
||||
MapTexture::iterator item = mTextures.find(_texture->getName());
|
||||
MYGUI_PLATFORM_ASSERT(item != mTextures.end(), "Texture '" << _texture->getName() << "' not found");
|
||||
|
||||
mTextures.erase(item);
|
||||
delete _texture;
|
||||
}
|
||||
|
||||
ITexture* getTexture(const std::string& _name)
|
||||
{
|
||||
MapTexture::const_iterator item = mTextures.find(_name);
|
||||
if (item == mTextures.end())
|
||||
{
|
||||
Ogre::TexturePtr texture = (Ogre::TexturePtr)Ogre::TextureManager::getSingleton().getByName(_name);
|
||||
if (!texture.isNull())
|
||||
{
|
||||
ITexture* result = createTexture(_name);
|
||||
static_cast<OgreTexture*>(result)->setOgreTexture(texture);
|
||||
return result;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return item->second;
|
||||
}
|
||||
|
||||
bool isFormatSupported(PixelFormat _format, TextureUsage _usage)
|
||||
{
|
||||
return Ogre::TextureManager::getSingleton().isFormatSupported(
|
||||
Ogre::TEX_TYPE_2D,
|
||||
OgreTexture::convertFormat(_format),
|
||||
OgreTexture::convertUsage(_usage));
|
||||
}
|
||||
|
||||
void destroyAllResources()
|
||||
{
|
||||
for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item)
|
||||
{
|
||||
delete item->second;
|
||||
}
|
||||
mTextures.clear();
|
||||
}
|
||||
|
||||
#if MYGUI_DEBUG_MODE == 1
|
||||
bool checkTexture(ITexture* _texture)
|
||||
{
|
||||
for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item)
|
||||
{
|
||||
if (item->second == _texture)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
const IntSize& getViewSize() const
|
||||
{
|
||||
return mViewSize;
|
||||
}
|
||||
|
||||
VertexColourType getVertexFormat()
|
||||
{
|
||||
return mVertexFormat;
|
||||
}
|
||||
|
||||
const RenderTargetInfo& getInfo()
|
||||
{
|
||||
return mInfo;
|
||||
}
|
||||
|
||||
size_t getActiveViewport()
|
||||
{
|
||||
return mActiveViewport;
|
||||
}
|
||||
|
||||
Ogre::RenderWindow* getRenderWindow()
|
||||
{
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
bool getManualRender()
|
||||
{
|
||||
return mManualRender;
|
||||
}
|
||||
|
||||
void setManualRender(bool _value)
|
||||
{
|
||||
mManualRender = _value;
|
||||
}
|
||||
|
||||
size_t getBatchCount() const
|
||||
{
|
||||
return mCountBatch;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging, const std::string& logDir)
|
||||
{
|
||||
assert(wnd);
|
||||
assert(mgr);
|
||||
|
||||
mSceneMgr = mgr;
|
||||
mShaderRenderManager = NULL;
|
||||
mRenderManager = NULL;
|
||||
|
||||
using namespace MyGUI;
|
||||
|
||||
// Enable/disable MyGUI logging to stdout. (Logging to MyGUI.log is
|
||||
// still enabled.) In order to do this we have to initialize the log
|
||||
// manager before the main gui system itself, otherwise the main
|
||||
// object will get the chance to spit out a few messages before we
|
||||
// can able to disable it.
|
||||
|
||||
std::string theLogFile = std::string(MYGUI_PLATFORM_LOG_FILENAME);
|
||||
if(!logDir.empty())
|
||||
theLogFile.insert(0, logDir);
|
||||
|
||||
// Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later.
|
||||
mLogManager = new LogManager();
|
||||
if (!Ogre::Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_FIXED_FUNCTION))
|
||||
mShaderRenderManager = new MyGUI::ShaderBasedRenderManager();
|
||||
else
|
||||
mRenderManager = new MyGUI::OgreRenderManager();
|
||||
mDataManager = new MyGUI::FixedOgreDataManager();
|
||||
|
||||
LogManager::getInstance().setSTDOutputEnabled(logging);
|
||||
|
||||
if (!theLogFile.empty())
|
||||
LogManager::getInstance().createDefaultSource(theLogFile);
|
||||
|
||||
if (mShaderRenderManager)
|
||||
mShaderRenderManager->initialise(wnd, mgr);
|
||||
else
|
||||
mRenderManager->initialise(wnd, mgr);
|
||||
mDataManager->initialise("General");
|
||||
|
||||
// Create GUI
|
||||
mGui = new Gui();
|
||||
mGui->initialise("");
|
||||
}
|
||||
|
||||
void MyGUIManager::updateWindow (Ogre::RenderWindow *wnd)
|
||||
{
|
||||
if (mShaderRenderManager)
|
||||
{
|
||||
mShaderRenderManager->setRenderWindow (wnd);
|
||||
mShaderRenderManager->setActiveViewport(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
mRenderManager->setRenderWindow (wnd);
|
||||
mRenderManager->setActiveViewport(0);
|
||||
}
|
||||
}
|
||||
|
||||
void MyGUIManager::windowResized()
|
||||
{
|
||||
mRenderManager->setActiveViewport(0);
|
||||
}
|
||||
|
||||
void MyGUIManager::shutdown()
|
||||
{
|
||||
mGui->shutdown ();
|
||||
delete mGui;
|
||||
if(mRenderManager)
|
||||
{
|
||||
mRenderManager->shutdown();
|
||||
delete mRenderManager;
|
||||
mRenderManager = NULL;
|
||||
}
|
||||
if(mShaderRenderManager)
|
||||
{
|
||||
mShaderRenderManager->shutdown();
|
||||
delete mShaderRenderManager;
|
||||
mShaderRenderManager = NULL;
|
||||
}
|
||||
if(mDataManager)
|
||||
{
|
||||
mDataManager->shutdown();
|
||||
delete mDataManager;
|
||||
mDataManager = NULL;
|
||||
}
|
||||
if (mLogManager)
|
||||
{
|
||||
delete mLogManager;
|
||||
mLogManager = NULL;
|
||||
}
|
||||
mGui = NULL;
|
||||
}
|
55
libs/openengine/gui/manager.hpp
Normal file
55
libs/openengine/gui/manager.hpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
#ifndef OENGINE_MYGUI_MANAGER_H
|
||||
#define OENGINE_MYGUI_MANAGER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace MyGUI
|
||||
{
|
||||
class Gui;
|
||||
class LogManager;
|
||||
class OgreDataManager;
|
||||
class OgreRenderManager;
|
||||
class ShaderBasedRenderManager;
|
||||
}
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
class RenderWindow;
|
||||
class SceneManager;
|
||||
}
|
||||
|
||||
namespace OEngine {
|
||||
namespace GUI
|
||||
{
|
||||
class MyGUIManager
|
||||
{
|
||||
MyGUI::Gui *mGui;
|
||||
MyGUI::LogManager* mLogManager;
|
||||
MyGUI::OgreDataManager* mDataManager;
|
||||
MyGUI::OgreRenderManager* mRenderManager;
|
||||
MyGUI::ShaderBasedRenderManager* mShaderRenderManager;
|
||||
Ogre::SceneManager* mSceneMgr;
|
||||
|
||||
|
||||
public:
|
||||
MyGUIManager(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string(""))
|
||||
{
|
||||
setup(wnd,mgr,logging, logDir);
|
||||
}
|
||||
~MyGUIManager()
|
||||
{
|
||||
shutdown();
|
||||
}
|
||||
|
||||
void updateWindow (Ogre::RenderWindow* wnd);
|
||||
|
||||
void windowResized();
|
||||
|
||||
void setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string(""));
|
||||
void shutdown();
|
||||
|
||||
MyGUI::Gui *getGui() { return mGui; }
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
178
libs/openengine/misc/list.hpp
Normal file
178
libs/openengine/misc/list.hpp
Normal file
|
@ -0,0 +1,178 @@
|
|||
#ifndef MISC_LIST_H
|
||||
#define MISC_LIST_H
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace Misc{
|
||||
|
||||
/*
|
||||
A simple and completely allocation-less doubly linked list. The
|
||||
class only manages pointers to and between elements. It leaving all
|
||||
memory management to the user.
|
||||
*/
|
||||
template <typename Elem>
|
||||
struct List
|
||||
{
|
||||
List() : head(0), tail(0), totalNum(0) {}
|
||||
|
||||
// Empty the list.
|
||||
void reset()
|
||||
{
|
||||
head = 0;
|
||||
tail = 0;
|
||||
totalNum = 0;
|
||||
}
|
||||
|
||||
// Insert an element at the end of the list. The element cannot be
|
||||
// part of any other list when this is called.
|
||||
void insert(Elem *p)
|
||||
{
|
||||
if(tail)
|
||||
{
|
||||
// There are existing elements. Insert the node at the end of
|
||||
// the list.
|
||||
assert(head && totalNum > 0);
|
||||
tail->next = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is the first element
|
||||
assert(head == 0 && totalNum == 0);
|
||||
head = p;
|
||||
}
|
||||
|
||||
// These have to be done in either case
|
||||
p->prev = tail;
|
||||
p->next = 0;
|
||||
tail = p;
|
||||
|
||||
totalNum++;
|
||||
}
|
||||
|
||||
// Remove element from the list. The element MUST be part of the
|
||||
// list when this is called.
|
||||
void remove(Elem *p)
|
||||
{
|
||||
assert(totalNum > 0);
|
||||
|
||||
if(p->next)
|
||||
{
|
||||
// There's an element following us. Set it up correctly.
|
||||
p->next->prev = p->prev;
|
||||
assert(tail && tail != p);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're the tail
|
||||
assert(tail == p);
|
||||
tail = p->prev;
|
||||
}
|
||||
|
||||
// Now do exactly the same for the previous element
|
||||
if(p->prev)
|
||||
{
|
||||
p->prev->next = p->next;
|
||||
assert(head && head != p);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(head == p);
|
||||
head = p->next;
|
||||
}
|
||||
|
||||
totalNum--;
|
||||
}
|
||||
|
||||
// Pop the first element off the list
|
||||
Elem *pop()
|
||||
{
|
||||
Elem *res = getHead();
|
||||
if(res) remove(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Swap the contents of this list with another of the same type
|
||||
void swap(List &other)
|
||||
{
|
||||
Elem *tmp;
|
||||
|
||||
tmp = head;
|
||||
head = other.head;
|
||||
other.head = tmp;
|
||||
|
||||
tmp = tail;
|
||||
tail = other.tail;
|
||||
other.tail = tmp;
|
||||
|
||||
unsigned int tmp2 = totalNum;
|
||||
totalNum = other.totalNum;
|
||||
other.totalNum = tmp2;
|
||||
}
|
||||
|
||||
/* Absorb the contents of another list. All the elements from the
|
||||
list are moved to the end of this list, and the other list is
|
||||
cleared.
|
||||
*/
|
||||
void absorb(List &other)
|
||||
{
|
||||
assert(&other != this);
|
||||
if(other.totalNum)
|
||||
{
|
||||
absorb(other.head, other.tail, other.totalNum);
|
||||
other.reset();
|
||||
}
|
||||
assert(other.totalNum == 0);
|
||||
}
|
||||
|
||||
/* Absorb a range of elements, endpoints included. The elements are
|
||||
assumed NOT to belong to any list, but they ARE assumed to be
|
||||
connected with a chain between them.
|
||||
|
||||
The connection MUST run all the way from 'first' to 'last'
|
||||
through the ->next pointers, and vice versa through ->prev
|
||||
pointers.
|
||||
|
||||
The parameter 'num' must give the exact number of elements in the
|
||||
chain.
|
||||
|
||||
Passing first == last, num == 1 is allowed and is equivalent to
|
||||
calling insert().
|
||||
*/
|
||||
void absorb(Elem* first, Elem *last, int num)
|
||||
{
|
||||
assert(first && last && num>=1);
|
||||
if(tail)
|
||||
{
|
||||
// There are existing elements. Insert the first node at the
|
||||
// end of the list.
|
||||
assert(head && totalNum > 0);
|
||||
tail->next = first;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is the first element
|
||||
assert(head == 0 && totalNum == 0);
|
||||
head = first;
|
||||
}
|
||||
|
||||
// These have to be done in either case
|
||||
first->prev = tail;
|
||||
last->next = 0;
|
||||
tail = last;
|
||||
|
||||
totalNum += num;
|
||||
}
|
||||
|
||||
Elem* getHead() const { return head; }
|
||||
Elem* getTail() const { return tail; }
|
||||
unsigned int getNum() const { return totalNum; }
|
||||
|
||||
private:
|
||||
|
||||
Elem *head;
|
||||
Elem *tail;
|
||||
unsigned int totalNum;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
135
libs/openengine/ogre/fader.cpp
Normal file
135
libs/openengine/ogre/fader.cpp
Normal file
|
@ -0,0 +1,135 @@
|
|||
#include "fader.hpp"
|
||||
|
||||
#include <OgreMaterial.h>
|
||||
#include <OgreTechnique.h>
|
||||
#include <OgreMaterialManager.h>
|
||||
#include <OgreResourceGroupManager.h>
|
||||
#include <OgreRectangle2D.h>
|
||||
#include <OgreSceneManager.h>
|
||||
|
||||
|
||||
using namespace Ogre;
|
||||
using namespace OEngine::Render;
|
||||
|
||||
Fader::Fader(Ogre::SceneManager* sceneMgr)
|
||||
: mSceneMgr(sceneMgr)
|
||||
, mMode(FadingMode_In)
|
||||
, mRemainingTime(0.f)
|
||||
, mTargetTime(0.f)
|
||||
, mTargetAlpha(0.f)
|
||||
, mCurrentAlpha(0.f)
|
||||
, mStartAlpha(0.f)
|
||||
, mFactor(1.f)
|
||||
{
|
||||
// Create the fading material
|
||||
MaterialPtr material = MaterialManager::getSingleton().create("FadeInOutMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
|
||||
Pass* pass = material->getTechnique(0)->getPass(0);
|
||||
pass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
||||
pass->setDepthWriteEnabled (false);
|
||||
mFadeTextureUnit = pass->createTextureUnitState("black.png");
|
||||
mFadeTextureUnit->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, ColourValue(0.f, 0.f, 0.f)); // always black colour
|
||||
|
||||
mRectangle = new Ogre::Rectangle2D(true);
|
||||
mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0);
|
||||
mRectangle->setMaterial("FadeInOutMaterial");
|
||||
mRectangle->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY-1);
|
||||
// Use infinite AAB to always stay visible
|
||||
Ogre::AxisAlignedBox aabInf;
|
||||
aabInf.setInfinite();
|
||||
mRectangle->setBoundingBox(aabInf);
|
||||
// Attach background to the scene
|
||||
Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
|
||||
node->attachObject(mRectangle);
|
||||
mRectangle->setVisible(false);
|
||||
mRectangle->setVisibilityFlags (2048);
|
||||
}
|
||||
|
||||
Fader::~Fader()
|
||||
{
|
||||
delete mRectangle;
|
||||
}
|
||||
|
||||
void Fader::update(float dt)
|
||||
{
|
||||
if (mRemainingTime > 0)
|
||||
{
|
||||
if (mMode == FadingMode_In)
|
||||
{
|
||||
mCurrentAlpha -= dt/mTargetTime * (mStartAlpha-mTargetAlpha);
|
||||
if (mCurrentAlpha < mTargetAlpha) mCurrentAlpha = mTargetAlpha;
|
||||
}
|
||||
else if (mMode == FadingMode_Out)
|
||||
{
|
||||
mCurrentAlpha += dt/mTargetTime * (mTargetAlpha-mStartAlpha);
|
||||
if (mCurrentAlpha > mTargetAlpha) mCurrentAlpha = mTargetAlpha;
|
||||
}
|
||||
|
||||
mRemainingTime -= dt;
|
||||
}
|
||||
|
||||
if (1.f-((1.f-mCurrentAlpha) * mFactor) == 0.f)
|
||||
mRectangle->setVisible(false);
|
||||
else
|
||||
applyAlpha();
|
||||
}
|
||||
|
||||
void Fader::applyAlpha()
|
||||
{
|
||||
mRectangle->setVisible(true);
|
||||
mFadeTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 1.f-((1.f-mCurrentAlpha) * mFactor));
|
||||
}
|
||||
|
||||
void Fader::fadeIn(float time)
|
||||
{
|
||||
if (time<0.f) return;
|
||||
if (time==0.f)
|
||||
{
|
||||
mCurrentAlpha = 0.f;
|
||||
applyAlpha();
|
||||
return;
|
||||
}
|
||||
|
||||
mStartAlpha = mCurrentAlpha;
|
||||
mTargetAlpha = 0.f;
|
||||
mMode = FadingMode_In;
|
||||
mTargetTime = time;
|
||||
mRemainingTime = time;
|
||||
}
|
||||
|
||||
void Fader::fadeOut(const float time)
|
||||
{
|
||||
if (time<0.f) return;
|
||||
if (time==0.f)
|
||||
{
|
||||
mCurrentAlpha = 1.f;
|
||||
applyAlpha();
|
||||
return;
|
||||
}
|
||||
|
||||
mStartAlpha = mCurrentAlpha;
|
||||
mTargetAlpha = 1.f;
|
||||
mMode = FadingMode_Out;
|
||||
mTargetTime = time;
|
||||
mRemainingTime = time;
|
||||
}
|
||||
|
||||
void Fader::fadeTo(const int percent, const float time)
|
||||
{
|
||||
if (time<0.f) return;
|
||||
if (time==0.f)
|
||||
{
|
||||
mCurrentAlpha = percent/100.f;
|
||||
applyAlpha();
|
||||
return;
|
||||
}
|
||||
|
||||
mStartAlpha = mCurrentAlpha;
|
||||
mTargetAlpha = percent/100.f;
|
||||
|
||||
if (mTargetAlpha == mStartAlpha) return;
|
||||
else if (mTargetAlpha > mStartAlpha) mMode = FadingMode_Out;
|
||||
else mMode = FadingMode_In;
|
||||
|
||||
mTargetTime = time;
|
||||
mRemainingTime = time;
|
||||
}
|
59
libs/openengine/ogre/fader.hpp
Normal file
59
libs/openengine/ogre/fader.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#ifndef OENGINE_OGRE_FADE_H
|
||||
#define OENGINE_OGRE_FADE_H
|
||||
|
||||
/*
|
||||
A class that handles fading in the screen from black or fading it out to black.
|
||||
|
||||
To achieve this, it uses a full-screen Rectangle2d
|
||||
*/
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
class TextureUnitState;
|
||||
class Rectangle2D;
|
||||
class SceneManager;
|
||||
}
|
||||
|
||||
namespace OEngine {
|
||||
namespace Render
|
||||
{
|
||||
class Fader
|
||||
{
|
||||
public:
|
||||
Fader(Ogre::SceneManager* sceneMgr);
|
||||
~Fader();
|
||||
|
||||
void update(float dt);
|
||||
|
||||
void fadeIn(const float time);
|
||||
void fadeOut(const float time);
|
||||
void fadeTo(const int percent, const float time);
|
||||
|
||||
void setFactor (float factor) { mFactor = factor; }
|
||||
|
||||
private:
|
||||
enum FadingMode
|
||||
{
|
||||
FadingMode_In,
|
||||
FadingMode_Out
|
||||
};
|
||||
|
||||
void applyAlpha();
|
||||
|
||||
Ogre::TextureUnitState* mFadeTextureUnit;
|
||||
Ogre::Rectangle2D* mRectangle;
|
||||
|
||||
FadingMode mMode;
|
||||
|
||||
float mRemainingTime;
|
||||
float mTargetTime;
|
||||
float mTargetAlpha;
|
||||
float mCurrentAlpha;
|
||||
float mStartAlpha;
|
||||
|
||||
float mFactor;
|
||||
|
||||
Ogre::SceneManager* mSceneMgr;
|
||||
};
|
||||
}}
|
||||
#endif
|
88
libs/openengine/ogre/imagerotate.cpp
Normal file
88
libs/openengine/ogre/imagerotate.cpp
Normal file
|
@ -0,0 +1,88 @@
|
|||
#include "imagerotate.hpp"
|
||||
|
||||
#include <OgreRoot.h>
|
||||
#include <OgreSceneManager.h>
|
||||
#include <OgreImage.h>
|
||||
#include <OgreTexture.h>
|
||||
#include <OgreRenderTarget.h>
|
||||
#include <OgreCamera.h>
|
||||
#include <OgreTextureUnitState.h>
|
||||
#include <OgreHardwarePixelBuffer.h>
|
||||
|
||||
using namespace Ogre;
|
||||
using namespace OEngine::Render;
|
||||
|
||||
void ImageRotate::rotate(const std::string& sourceImage, const std::string& destImage, const float angle)
|
||||
{
|
||||
Root* root = Ogre::Root::getSingletonPtr();
|
||||
|
||||
std::string destImageRot = std::string(destImage) + std::string("_rot");
|
||||
|
||||
SceneManager* sceneMgr = root->createSceneManager(ST_GENERIC);
|
||||
Camera* camera = sceneMgr->createCamera("ImageRotateCamera");
|
||||
|
||||
MaterialPtr material = MaterialManager::getSingleton().create("ImageRotateMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||
material->getTechnique(0)->getPass(0)->setLightingEnabled(false);
|
||||
material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false);
|
||||
TextureUnitState* tus = material->getTechnique(0)->getPass(0)->createTextureUnitState(sourceImage);
|
||||
Degree deg(angle);
|
||||
tus->setTextureRotate(Radian(deg.valueRadians()));
|
||||
tus->setTextureAddressingMode(TextureUnitState::TAM_BORDER);
|
||||
tus->setTextureBorderColour(ColourValue(0, 0, 0, 0));
|
||||
|
||||
Rectangle2D* rect = new Rectangle2D(true);
|
||||
rect->setCorners(-1.0, 1.0, 1.0, -1.0);
|
||||
rect->setMaterial("ImageRotateMaterial");
|
||||
// Render the background before everything else
|
||||
rect->setRenderQueueGroup(RENDER_QUEUE_BACKGROUND);
|
||||
|
||||
// Use infinite AAB to always stay visible
|
||||
AxisAlignedBox aabInf;
|
||||
aabInf.setInfinite();
|
||||
rect->setBoundingBox(aabInf);
|
||||
|
||||
// Attach background to the scene
|
||||
SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode();
|
||||
node->attachObject(rect);
|
||||
|
||||
// retrieve image width and height
|
||||
TexturePtr sourceTexture = TextureManager::getSingleton().getByName(sourceImage);
|
||||
unsigned int width = sourceTexture->getWidth();
|
||||
unsigned int height = sourceTexture->getHeight();
|
||||
|
||||
TexturePtr destTextureRot = TextureManager::getSingleton().createManual(
|
||||
destImageRot,
|
||||
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
TEX_TYPE_2D,
|
||||
width, height,
|
||||
0,
|
||||
PF_A8B8G8R8,
|
||||
TU_RENDERTARGET);
|
||||
|
||||
RenderTarget* rtt = destTextureRot->getBuffer()->getRenderTarget();
|
||||
rtt->setAutoUpdated(false);
|
||||
Viewport* vp = rtt->addViewport(camera);
|
||||
vp->setOverlaysEnabled(false);
|
||||
vp->setShadowsEnabled(false);
|
||||
vp->setBackgroundColour(ColourValue(0,0,0,0));
|
||||
|
||||
rtt->update();
|
||||
|
||||
//copy the rotated image to a static texture
|
||||
TexturePtr destTexture = TextureManager::getSingleton().createManual(
|
||||
destImage,
|
||||
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
TEX_TYPE_2D,
|
||||
width, height,
|
||||
0,
|
||||
PF_A8B8G8R8,
|
||||
Ogre::TU_STATIC);
|
||||
|
||||
destTexture->getBuffer()->blit(destTextureRot->getBuffer());
|
||||
|
||||
// remove all the junk we've created
|
||||
TextureManager::getSingleton().remove(destImageRot);
|
||||
MaterialManager::getSingleton().remove("ImageRotateMaterial");
|
||||
root->destroySceneManager(sceneMgr);
|
||||
delete rect;
|
||||
}
|
27
libs/openengine/ogre/imagerotate.hpp
Normal file
27
libs/openengine/ogre/imagerotate.hpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef OENGINE_OGRE_IMAGEROTATE_HPP
|
||||
#define OENGINE_OGRE_IMAGEROTATE_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace OEngine
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
|
||||
/// Rotate an image by certain degrees and save as file, uses the GPU
|
||||
/// Make sure Ogre Root is initialised before calling
|
||||
class ImageRotate
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param source image (file name - has to exist in an resource group)
|
||||
* @param name of the destination texture to save to (in memory)
|
||||
* @param angle in degrees to turn
|
||||
*/
|
||||
static void rotate(const std::string& sourceImage, const std::string& destImage, const float angle);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
118
libs/openengine/ogre/lights.cpp
Normal file
118
libs/openengine/ogre/lights.cpp
Normal file
|
@ -0,0 +1,118 @@
|
|||
#include "lights.hpp"
|
||||
|
||||
#include <OgreLight.h>
|
||||
#include <OgreMath.h>
|
||||
|
||||
namespace OEngine {
|
||||
namespace Render {
|
||||
|
||||
|
||||
LightFunction::LightFunction(LightType type)
|
||||
: ControllerFunction<Ogre::Real>(true)
|
||||
, mType(type)
|
||||
, mPhase(Ogre::Math::RangeRandom(-500.0f, +500.0f))
|
||||
, mDirection(1.0f)
|
||||
{
|
||||
}
|
||||
|
||||
Ogre::Real LightFunction::pulseAmplitude(Ogre::Real time)
|
||||
{
|
||||
return std::sin(time);
|
||||
}
|
||||
|
||||
Ogre::Real LightFunction::flickerAmplitude(Ogre::Real time)
|
||||
{
|
||||
static const float fb = 1.17024f;
|
||||
static const float f[3] = { 1.5708f, 4.18774f, 5.19934f };
|
||||
static const float o[3] = { 0.804248f, 2.11115f, 3.46832f };
|
||||
static const float m[3] = { 1.0f, 0.785f, 0.876f };
|
||||
static const float s = 0.394f;
|
||||
|
||||
float v = 0.0f;
|
||||
for(int i = 0;i < 3;++i)
|
||||
v += std::sin(fb*time*f[i] + o[1])*m[i];
|
||||
return v * s;
|
||||
}
|
||||
|
||||
Ogre::Real LightFunction::flickerFrequency(Ogre::Real phase)
|
||||
{
|
||||
static const float fa = 0.785398f;
|
||||
static const float tdo = 0.94f;
|
||||
static const float tdm = 2.48f;
|
||||
|
||||
return tdo + tdm*std::sin(fa * phase);
|
||||
}
|
||||
|
||||
Ogre::Real LightFunction::calculate(Ogre::Real value)
|
||||
{
|
||||
Ogre::Real brightness = 1.0f;
|
||||
float cycle_time;
|
||||
float time_distortion;
|
||||
|
||||
if(mType == LT_Pulse || mType == LT_PulseSlow)
|
||||
{
|
||||
cycle_time = 2.0f * Ogre::Math::PI;
|
||||
time_distortion = 20.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
static const float fa = 0.785398f;
|
||||
static const float phase_wavelength = 120.0f * 3.14159265359f / fa;
|
||||
|
||||
cycle_time = 500.0f;
|
||||
mPhase = std::fmod(mPhase + value, phase_wavelength);
|
||||
time_distortion = flickerFrequency(mPhase);
|
||||
}
|
||||
|
||||
mDeltaCount += mDirection*value*time_distortion;
|
||||
if(mDirection > 0 && mDeltaCount > +cycle_time)
|
||||
{
|
||||
mDirection = -1.0f;
|
||||
mDeltaCount = 2.0f*cycle_time - mDeltaCount;
|
||||
}
|
||||
if(mDirection < 0 && mDeltaCount < -cycle_time)
|
||||
{
|
||||
mDirection = +1.0f;
|
||||
mDeltaCount = -2.0f*cycle_time - mDeltaCount;
|
||||
}
|
||||
|
||||
static const float fast = 4.0f/1.0f;
|
||||
static const float slow = 1.0f/1.0f;
|
||||
|
||||
// These formulas are just guesswork, but they work pretty well
|
||||
if(mType == LT_Normal)
|
||||
{
|
||||
// Less than 1/255 light modifier for a constant light:
|
||||
brightness = 1.0 + flickerAmplitude(mDeltaCount*slow)/255.0f;
|
||||
}
|
||||
else if(mType == LT_Flicker)
|
||||
brightness = 0.75 + flickerAmplitude(mDeltaCount*fast)*0.25;
|
||||
else if(mType == LT_FlickerSlow)
|
||||
brightness = 0.75 + flickerAmplitude(mDeltaCount*slow)*0.25;
|
||||
else if(mType == LT_Pulse)
|
||||
brightness = 1.0 + pulseAmplitude(mDeltaCount*fast)*0.25;
|
||||
else if(mType == LT_PulseSlow)
|
||||
brightness = 1.0 + pulseAmplitude(mDeltaCount*slow)*0.25;
|
||||
|
||||
return brightness;
|
||||
}
|
||||
|
||||
|
||||
LightValue::LightValue(Ogre::Light *light, const Ogre::ColourValue &color)
|
||||
: mTarget(light)
|
||||
, mColor(color)
|
||||
{
|
||||
}
|
||||
|
||||
Ogre::Real LightValue::getValue() const
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void LightValue::setValue(Ogre::Real value)
|
||||
{
|
||||
mTarget->setDiffuseColour(mColor * value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
51
libs/openengine/ogre/lights.hpp
Normal file
51
libs/openengine/ogre/lights.hpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
#ifndef OENGINE_OGRE_LIGHTS_H
|
||||
#define OENGINE_OGRE_LIGHTS_H
|
||||
|
||||
#include <OgreController.h>
|
||||
#include <OgreColourValue.h>
|
||||
|
||||
/*
|
||||
* Controller classes to handle pulsing and flicker lights
|
||||
*/
|
||||
|
||||
namespace OEngine {
|
||||
namespace Render {
|
||||
enum LightType {
|
||||
LT_Normal,
|
||||
LT_Flicker,
|
||||
LT_FlickerSlow,
|
||||
LT_Pulse,
|
||||
LT_PulseSlow
|
||||
};
|
||||
|
||||
class LightFunction : public Ogre::ControllerFunction<Ogre::Real>
|
||||
{
|
||||
LightType mType;
|
||||
Ogre::Real mPhase;
|
||||
Ogre::Real mDirection;
|
||||
|
||||
static Ogre::Real pulseAmplitude(Ogre::Real time);
|
||||
|
||||
static Ogre::Real flickerAmplitude(Ogre::Real time);
|
||||
static Ogre::Real flickerFrequency(Ogre::Real phase);
|
||||
|
||||
public:
|
||||
LightFunction(LightType type);
|
||||
virtual Ogre::Real calculate(Ogre::Real value);
|
||||
};
|
||||
|
||||
class LightValue : public Ogre::ControllerValue<Ogre::Real>
|
||||
{
|
||||
Ogre::Light *mTarget;
|
||||
Ogre::ColourValue mColor;
|
||||
|
||||
public:
|
||||
LightValue(Ogre::Light *light, const Ogre::ColourValue &color);
|
||||
|
||||
virtual Ogre::Real getValue() const;
|
||||
virtual void setValue(Ogre::Real value);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
693
libs/openengine/ogre/particles.cpp
Normal file
693
libs/openengine/ogre/particles.cpp
Normal file
|
@ -0,0 +1,693 @@
|
|||
#include "particles.hpp"
|
||||
|
||||
#include <OgreStringConverter.h>
|
||||
#include <OgreParticleSystem.h>
|
||||
#include <OgreParticleEmitter.h>
|
||||
#include <OgreParticleAffector.h>
|
||||
#include <OgreParticle.h>
|
||||
|
||||
/* FIXME: "Nif" isn't really an appropriate emitter name. */
|
||||
class NifEmitter : public Ogre::ParticleEmitter
|
||||
{
|
||||
public:
|
||||
/** Command object for the emitter width (see Ogre::ParamCommand).*/
|
||||
class CmdWidth : public Ogre::ParamCommand
|
||||
{
|
||||
public:
|
||||
Ogre::String doGet(const void *target) const
|
||||
{
|
||||
return Ogre::StringConverter::toString(static_cast<const NifEmitter*>(target)->getWidth());
|
||||
}
|
||||
void doSet(void *target, const Ogre::String &val)
|
||||
{
|
||||
static_cast<NifEmitter*>(target)->setWidth(Ogre::StringConverter::parseReal(val));
|
||||
}
|
||||
};
|
||||
|
||||
/** Command object for the emitter height (see Ogre::ParamCommand).*/
|
||||
class CmdHeight : public Ogre::ParamCommand
|
||||
{
|
||||
public:
|
||||
Ogre::String doGet(const void *target) const
|
||||
{
|
||||
return Ogre::StringConverter::toString(static_cast<const NifEmitter*>(target)->getHeight());
|
||||
}
|
||||
void doSet(void *target, const Ogre::String &val)
|
||||
{
|
||||
static_cast<NifEmitter*>(target)->setHeight(Ogre::StringConverter::parseReal(val));
|
||||
}
|
||||
};
|
||||
|
||||
/** Command object for the emitter depth (see Ogre::ParamCommand).*/
|
||||
class CmdDepth : public Ogre::ParamCommand
|
||||
{
|
||||
public:
|
||||
Ogre::String doGet(const void *target) const
|
||||
{
|
||||
return Ogre::StringConverter::toString(static_cast<const NifEmitter*>(target)->getDepth());
|
||||
}
|
||||
void doSet(void *target, const Ogre::String &val)
|
||||
{
|
||||
static_cast<NifEmitter*>(target)->setDepth(Ogre::StringConverter::parseReal(val));
|
||||
}
|
||||
};
|
||||
|
||||
/** Command object for the emitter vertical_direction (see Ogre::ParamCommand).*/
|
||||
class CmdVerticalDir : public Ogre::ParamCommand
|
||||
{
|
||||
public:
|
||||
Ogre::String doGet(const void *target) const
|
||||
{
|
||||
const NifEmitter *self = static_cast<const NifEmitter*>(target);
|
||||
return Ogre::StringConverter::toString(self->getVerticalDirection().valueDegrees());
|
||||
}
|
||||
void doSet(void *target, const Ogre::String &val)
|
||||
{
|
||||
NifEmitter *self = static_cast<NifEmitter*>(target);
|
||||
self->setVerticalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val)));
|
||||
}
|
||||
};
|
||||
|
||||
/** Command object for the emitter vertical_angle (see Ogre::ParamCommand).*/
|
||||
class CmdVerticalAngle : public Ogre::ParamCommand
|
||||
{
|
||||
public:
|
||||
Ogre::String doGet(const void *target) const
|
||||
{
|
||||
const NifEmitter *self = static_cast<const NifEmitter*>(target);
|
||||
return Ogre::StringConverter::toString(self->getVerticalAngle().valueDegrees());
|
||||
}
|
||||
void doSet(void *target, const Ogre::String &val)
|
||||
{
|
||||
NifEmitter *self = static_cast<NifEmitter*>(target);
|
||||
self->setVerticalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val)));
|
||||
}
|
||||
};
|
||||
|
||||
/** Command object for the emitter horizontal_direction (see Ogre::ParamCommand).*/
|
||||
class CmdHorizontalDir : public Ogre::ParamCommand
|
||||
{
|
||||
public:
|
||||
Ogre::String doGet(const void *target) const
|
||||
{
|
||||
const NifEmitter *self = static_cast<const NifEmitter*>(target);
|
||||
return Ogre::StringConverter::toString(self->getHorizontalDirection().valueDegrees());
|
||||
}
|
||||
void doSet(void *target, const Ogre::String &val)
|
||||
{
|
||||
NifEmitter *self = static_cast<NifEmitter*>(target);
|
||||
self->setHorizontalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val)));
|
||||
}
|
||||
};
|
||||
|
||||
/** Command object for the emitter horizontal_angle (see Ogre::ParamCommand).*/
|
||||
class CmdHorizontalAngle : public Ogre::ParamCommand
|
||||
{
|
||||
public:
|
||||
Ogre::String doGet(const void *target) const
|
||||
{
|
||||
const NifEmitter *self = static_cast<const NifEmitter*>(target);
|
||||
return Ogre::StringConverter::toString(self->getHorizontalAngle().valueDegrees());
|
||||
}
|
||||
void doSet(void *target, const Ogre::String &val)
|
||||
{
|
||||
NifEmitter *self = static_cast<NifEmitter*>(target);
|
||||
self->setHorizontalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val)));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
NifEmitter(Ogre::ParticleSystem *psys)
|
||||
: Ogre::ParticleEmitter(psys)
|
||||
{
|
||||
initDefaults("Nif");
|
||||
}
|
||||
|
||||
/** See Ogre::ParticleEmitter. */
|
||||
unsigned short _getEmissionCount(Ogre::Real timeElapsed)
|
||||
{
|
||||
// Use basic constant emission
|
||||
return genConstantEmissionCount(timeElapsed);
|
||||
}
|
||||
|
||||
/** See Ogre::ParticleEmitter. */
|
||||
void _initParticle(Ogre::Particle *particle)
|
||||
{
|
||||
Ogre::Vector3 xOff, yOff, zOff;
|
||||
|
||||
// Call superclass
|
||||
ParticleEmitter::_initParticle(particle);
|
||||
|
||||
xOff = Ogre::Math::SymmetricRandom() * mXRange;
|
||||
yOff = Ogre::Math::SymmetricRandom() * mYRange;
|
||||
zOff = Ogre::Math::SymmetricRandom() * mZRange;
|
||||
|
||||
particle->position = mPosition + xOff + yOff + zOff;
|
||||
|
||||
// Generate complex data by reference
|
||||
genEmissionColour(particle->colour);
|
||||
|
||||
// NOTE: We do not use mDirection/mAngle for the initial direction.
|
||||
Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom();
|
||||
Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom();
|
||||
particle->direction = (Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) *
|
||||
Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) *
|
||||
Ogre::Vector3::UNIT_Z;
|
||||
|
||||
genEmissionVelocity(particle->direction);
|
||||
|
||||
// Generate simpler data
|
||||
particle->timeToLive = particle->totalTimeToLive = genEmissionTTL();
|
||||
}
|
||||
|
||||
/** Overloaded to update the trans. matrix */
|
||||
void setDirection(const Ogre::Vector3 &dir)
|
||||
{
|
||||
ParticleEmitter::setDirection(dir);
|
||||
genAreaAxes();
|
||||
}
|
||||
|
||||
/** Sets the size of the area from which particles are emitted.
|
||||
@param
|
||||
size Vector describing the size of the area. The area extends
|
||||
around the center point by half the x, y and z components of
|
||||
this vector. The box is aligned such that it's local Z axis points
|
||||
along it's direction (see setDirection)
|
||||
*/
|
||||
void setSize(const Ogre::Vector3 &size)
|
||||
{
|
||||
mSize = size;
|
||||
genAreaAxes();
|
||||
}
|
||||
|
||||
/** Sets the size of the area from which particles are emitted.
|
||||
@param x,y,z
|
||||
Individual axis lengths describing the size of the area. The area
|
||||
extends around the center point by half the x, y and z components
|
||||
of this vector. The box is aligned such that it's local Z axis
|
||||
points along it's direction (see setDirection)
|
||||
*/
|
||||
void setSize(Ogre::Real x, Ogre::Real y, Ogre::Real z)
|
||||
{
|
||||
mSize.x = x;
|
||||
mSize.y = y;
|
||||
mSize.z = z;
|
||||
genAreaAxes();
|
||||
}
|
||||
|
||||
/** Sets the width (local x size) of the emitter. */
|
||||
void setWidth(Ogre::Real width)
|
||||
{
|
||||
mSize.x = width;
|
||||
genAreaAxes();
|
||||
}
|
||||
/** Gets the width (local x size) of the emitter. */
|
||||
Ogre::Real getWidth(void) const
|
||||
{ return mSize.x; }
|
||||
/** Sets the height (local y size) of the emitter. */
|
||||
void setHeight(Ogre::Real height)
|
||||
{
|
||||
mSize.y = height;
|
||||
genAreaAxes();
|
||||
}
|
||||
/** Gets the height (local y size) of the emitter. */
|
||||
Ogre::Real getHeight(void) const
|
||||
{ return mSize.y; }
|
||||
/** Sets the depth (local y size) of the emitter. */
|
||||
void setDepth(Ogre::Real depth)
|
||||
{
|
||||
mSize.z = depth;
|
||||
genAreaAxes();
|
||||
}
|
||||
/** Gets the depth (local y size) of the emitter. */
|
||||
Ogre::Real getDepth(void) const
|
||||
{ return mSize.z; }
|
||||
|
||||
void setVerticalDirection(Ogre::Radian vdir)
|
||||
{ mVerticalDir = vdir; }
|
||||
Ogre::Radian getVerticalDirection(void) const
|
||||
{ return mVerticalDir; }
|
||||
|
||||
void setVerticalAngle(Ogre::Radian vangle)
|
||||
{ mVerticalAngle = vangle; }
|
||||
Ogre::Radian getVerticalAngle(void) const
|
||||
{ return mVerticalAngle; }
|
||||
|
||||
void setHorizontalDirection(Ogre::Radian hdir)
|
||||
{ mHorizontalDir = hdir; }
|
||||
Ogre::Radian getHorizontalDirection(void) const
|
||||
{ return mHorizontalDir; }
|
||||
|
||||
void setHorizontalAngle(Ogre::Radian hangle)
|
||||
{ mHorizontalAngle = hangle; }
|
||||
Ogre::Radian getHorizontalAngle(void) const
|
||||
{ return mHorizontalAngle; }
|
||||
|
||||
|
||||
protected:
|
||||
/// Size of the area
|
||||
Ogre::Vector3 mSize;
|
||||
|
||||
Ogre::Radian mVerticalDir;
|
||||
Ogre::Radian mVerticalAngle;
|
||||
Ogre::Radian mHorizontalDir;
|
||||
Ogre::Radian mHorizontalAngle;
|
||||
|
||||
/// Local axes, not normalised, their magnitude reflects area size
|
||||
Ogre::Vector3 mXRange, mYRange, mZRange;
|
||||
|
||||
/// Internal method for generating the area axes
|
||||
void genAreaAxes(void)
|
||||
{
|
||||
Ogre::Vector3 mLeft = mUp.crossProduct(mDirection);
|
||||
mXRange = mLeft * (mSize.x * 0.5f);
|
||||
mYRange = mUp * (mSize.y * 0.5f);
|
||||
mZRange = mDirection * (mSize.z * 0.5f);
|
||||
}
|
||||
|
||||
/** Internal for initializing some defaults and parameters
|
||||
@return True if custom parameters need initialising
|
||||
*/
|
||||
bool initDefaults(const Ogre::String &t)
|
||||
{
|
||||
// Defaults
|
||||
mDirection = Ogre::Vector3::UNIT_Z;
|
||||
mUp = Ogre::Vector3::UNIT_Y;
|
||||
setSize(100.0f, 100.0f, 100.0f);
|
||||
mType = t;
|
||||
|
||||
// Set up parameters
|
||||
if(createParamDictionary(mType + "Emitter"))
|
||||
{
|
||||
addBaseParameters();
|
||||
Ogre::ParamDictionary *dict = getParamDictionary();
|
||||
|
||||
// Custom params
|
||||
dict->addParameter(Ogre::ParameterDef("width",
|
||||
"Width of the shape in world coordinates.",
|
||||
Ogre::PT_REAL),
|
||||
&msWidthCmd);
|
||||
dict->addParameter(Ogre::ParameterDef("height",
|
||||
"Height of the shape in world coordinates.",
|
||||
Ogre::PT_REAL),
|
||||
&msHeightCmd);
|
||||
dict->addParameter(Ogre::ParameterDef("depth",
|
||||
"Depth of the shape in world coordinates.",
|
||||
Ogre::PT_REAL),
|
||||
&msDepthCmd);
|
||||
|
||||
dict->addParameter(Ogre::ParameterDef("vertical_direction",
|
||||
"Vertical direction of emitted particles (in degrees).",
|
||||
Ogre::PT_REAL),
|
||||
&msVerticalDirCmd);
|
||||
dict->addParameter(Ogre::ParameterDef("vertical_angle",
|
||||
"Vertical direction variance of emitted particles (in degrees).",
|
||||
Ogre::PT_REAL),
|
||||
&msVerticalAngleCmd);
|
||||
dict->addParameter(Ogre::ParameterDef("horizontal_direction",
|
||||
"Horizontal direction of emitted particles (in degrees).",
|
||||
Ogre::PT_REAL),
|
||||
&msHorizontalDirCmd);
|
||||
dict->addParameter(Ogre::ParameterDef("horizontal_angle",
|
||||
"Horizontal direction variance of emitted particles (in degrees).",
|
||||
Ogre::PT_REAL),
|
||||
&msHorizontalAngleCmd);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Command objects
|
||||
static CmdWidth msWidthCmd;
|
||||
static CmdHeight msHeightCmd;
|
||||
static CmdDepth msDepthCmd;
|
||||
static CmdVerticalDir msVerticalDirCmd;
|
||||
static CmdVerticalAngle msVerticalAngleCmd;
|
||||
static CmdHorizontalDir msHorizontalDirCmd;
|
||||
static CmdHorizontalAngle msHorizontalAngleCmd;
|
||||
};
|
||||
NifEmitter::CmdWidth NifEmitter::msWidthCmd;
|
||||
NifEmitter::CmdHeight NifEmitter::msHeightCmd;
|
||||
NifEmitter::CmdDepth NifEmitter::msDepthCmd;
|
||||
NifEmitter::CmdVerticalDir NifEmitter::msVerticalDirCmd;
|
||||
NifEmitter::CmdVerticalAngle NifEmitter::msVerticalAngleCmd;
|
||||
NifEmitter::CmdHorizontalDir NifEmitter::msHorizontalDirCmd;
|
||||
NifEmitter::CmdHorizontalAngle NifEmitter::msHorizontalAngleCmd;
|
||||
|
||||
Ogre::ParticleEmitter* NifEmitterFactory::createEmitter(Ogre::ParticleSystem *psys)
|
||||
{
|
||||
Ogre::ParticleEmitter *emit = OGRE_NEW NifEmitter(psys);
|
||||
mEmitters.push_back(emit);
|
||||
return emit;
|
||||
}
|
||||
|
||||
|
||||
class GrowFadeAffector : public Ogre::ParticleAffector
|
||||
{
|
||||
public:
|
||||
/** Command object for grow_time (see Ogre::ParamCommand).*/
|
||||
class CmdGrowTime : public Ogre::ParamCommand
|
||||
{
|
||||
public:
|
||||
Ogre::String doGet(const void *target) const
|
||||
{
|
||||
const GrowFadeAffector *self = static_cast<const GrowFadeAffector*>(target);
|
||||
return Ogre::StringConverter::toString(self->getGrowTime());
|
||||
}
|
||||
void doSet(void *target, const Ogre::String &val)
|
||||
{
|
||||
GrowFadeAffector *self = static_cast<GrowFadeAffector*>(target);
|
||||
self->setGrowTime(Ogre::StringConverter::parseReal(val));
|
||||
}
|
||||
};
|
||||
|
||||
/** Command object for fade_time (see Ogre::ParamCommand).*/
|
||||
class CmdFadeTime : public Ogre::ParamCommand
|
||||
{
|
||||
public:
|
||||
Ogre::String doGet(const void *target) const
|
||||
{
|
||||
const GrowFadeAffector *self = static_cast<const GrowFadeAffector*>(target);
|
||||
return Ogre::StringConverter::toString(self->getFadeTime());
|
||||
}
|
||||
void doSet(void *target, const Ogre::String &val)
|
||||
{
|
||||
GrowFadeAffector *self = static_cast<GrowFadeAffector*>(target);
|
||||
self->setFadeTime(Ogre::StringConverter::parseReal(val));
|
||||
}
|
||||
};
|
||||
|
||||
/** Default constructor. */
|
||||
GrowFadeAffector(Ogre::ParticleSystem *psys) : ParticleAffector(psys)
|
||||
{
|
||||
mGrowTime = 0.0f;
|
||||
mFadeTime = 0.0f;
|
||||
|
||||
mType = "GrowFade";
|
||||
|
||||
// Init parameters
|
||||
if(createParamDictionary("GrowFadeAffector"))
|
||||
{
|
||||
Ogre::ParamDictionary *dict = getParamDictionary();
|
||||
|
||||
Ogre::String grow_title("grow_time");
|
||||
Ogre::String fade_title("fade_time");
|
||||
Ogre::String grow_descr("Time from begin to reach full size.");
|
||||
Ogre::String fade_descr("Time from end to shrink.");
|
||||
|
||||
dict->addParameter(Ogre::ParameterDef(grow_title, grow_descr, Ogre::PT_REAL), &msGrowCmd);
|
||||
dict->addParameter(Ogre::ParameterDef(fade_title, fade_descr, Ogre::PT_REAL), &msFadeCmd);
|
||||
}
|
||||
}
|
||||
|
||||
/** See Ogre::ParticleAffector. */
|
||||
void _initParticle(Ogre::Particle *particle)
|
||||
{
|
||||
const Ogre::Real life_time = particle->totalTimeToLive;
|
||||
Ogre::Real particle_time = particle->timeToLive;
|
||||
|
||||
Ogre::Real width = mParent->getDefaultWidth();
|
||||
Ogre::Real height = mParent->getDefaultHeight();
|
||||
if(life_time-particle_time < mGrowTime)
|
||||
{
|
||||
Ogre::Real scale = (life_time-particle_time) / mGrowTime;
|
||||
width *= scale;
|
||||
height *= scale;
|
||||
}
|
||||
if(particle_time < mFadeTime)
|
||||
{
|
||||
Ogre::Real scale = particle_time / mFadeTime;
|
||||
width *= scale;
|
||||
height *= scale;
|
||||
}
|
||||
particle->setDimensions(width, height);
|
||||
}
|
||||
|
||||
/** See Ogre::ParticleAffector. */
|
||||
void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed)
|
||||
{
|
||||
Ogre::ParticleIterator pi = psys->_getIterator();
|
||||
while (!pi.end())
|
||||
{
|
||||
Ogre::Particle *p = pi.getNext();
|
||||
const Ogre::Real life_time = p->totalTimeToLive;
|
||||
Ogre::Real particle_time = p->timeToLive;
|
||||
|
||||
Ogre::Real width = mParent->getDefaultWidth();
|
||||
Ogre::Real height = mParent->getDefaultHeight();
|
||||
if(life_time-particle_time < mGrowTime)
|
||||
{
|
||||
Ogre::Real scale = (life_time-particle_time) / mGrowTime;
|
||||
width *= scale;
|
||||
height *= scale;
|
||||
}
|
||||
if(particle_time < mFadeTime)
|
||||
{
|
||||
Ogre::Real scale = particle_time / mFadeTime;
|
||||
width *= scale;
|
||||
height *= scale;
|
||||
}
|
||||
p->setDimensions(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void setGrowTime(Ogre::Real time)
|
||||
{
|
||||
mGrowTime = time;
|
||||
}
|
||||
Ogre::Real getGrowTime() const
|
||||
{ return mGrowTime; }
|
||||
|
||||
void setFadeTime(Ogre::Real time)
|
||||
{
|
||||
mFadeTime = time;
|
||||
}
|
||||
Ogre::Real getFadeTime() const
|
||||
{ return mFadeTime; }
|
||||
|
||||
static CmdGrowTime msGrowCmd;
|
||||
static CmdFadeTime msFadeCmd;
|
||||
|
||||
protected:
|
||||
Ogre::Real mGrowTime;
|
||||
Ogre::Real mFadeTime;
|
||||
};
|
||||
GrowFadeAffector::CmdGrowTime GrowFadeAffector::msGrowCmd;
|
||||
GrowFadeAffector::CmdFadeTime GrowFadeAffector::msFadeCmd;
|
||||
|
||||
Ogre::ParticleAffector *GrowFadeAffectorFactory::createAffector(Ogre::ParticleSystem *psys)
|
||||
{
|
||||
Ogre::ParticleAffector *p = new GrowFadeAffector(psys);
|
||||
mAffectors.push_back(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
class GravityAffector : public Ogre::ParticleAffector
|
||||
{
|
||||
enum ForceType {
|
||||
Type_Wind,
|
||||
Type_Point
|
||||
};
|
||||
|
||||
public:
|
||||
/** Command object for force (see Ogre::ParamCommand).*/
|
||||
class CmdForce : public Ogre::ParamCommand
|
||||
{
|
||||
public:
|
||||
Ogre::String doGet(const void *target) const
|
||||
{
|
||||
const GravityAffector *self = static_cast<const GravityAffector*>(target);
|
||||
return Ogre::StringConverter::toString(self->getForce());
|
||||
}
|
||||
void doSet(void *target, const Ogre::String &val)
|
||||
{
|
||||
GravityAffector *self = static_cast<GravityAffector*>(target);
|
||||
self->setForce(Ogre::StringConverter::parseReal(val));
|
||||
}
|
||||
};
|
||||
|
||||
/** Command object for force_type (see Ogre::ParamCommand).*/
|
||||
class CmdForceType : public Ogre::ParamCommand
|
||||
{
|
||||
static ForceType getTypeFromString(const Ogre::String &type)
|
||||
{
|
||||
if(type == "wind")
|
||||
return Type_Wind;
|
||||
if(type == "point")
|
||||
return Type_Point;
|
||||
OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type string: "+type,
|
||||
"CmdForceType::getTypeFromString");
|
||||
}
|
||||
|
||||
static Ogre::String getStringFromType(ForceType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case Type_Wind: return "wind";
|
||||
case Type_Point: return "point";
|
||||
}
|
||||
OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type enum: "+Ogre::StringConverter::toString(type),
|
||||
"CmdForceType::getStringFromType");
|
||||
}
|
||||
|
||||
public:
|
||||
Ogre::String doGet(const void *target) const
|
||||
{
|
||||
const GravityAffector *self = static_cast<const GravityAffector*>(target);
|
||||
return getStringFromType(self->getForceType());
|
||||
}
|
||||
void doSet(void *target, const Ogre::String &val)
|
||||
{
|
||||
GravityAffector *self = static_cast<GravityAffector*>(target);
|
||||
self->setForceType(getTypeFromString(val));
|
||||
}
|
||||
};
|
||||
|
||||
/** Command object for direction (see Ogre::ParamCommand).*/
|
||||
class CmdDirection : public Ogre::ParamCommand
|
||||
{
|
||||
public:
|
||||
Ogre::String doGet(const void *target) const
|
||||
{
|
||||
const GravityAffector *self = static_cast<const GravityAffector*>(target);
|
||||
return Ogre::StringConverter::toString(self->getDirection());
|
||||
}
|
||||
void doSet(void *target, const Ogre::String &val)
|
||||
{
|
||||
GravityAffector *self = static_cast<GravityAffector*>(target);
|
||||
self->setDirection(Ogre::StringConverter::parseVector3(val));
|
||||
}
|
||||
};
|
||||
|
||||
/** Command object for position (see Ogre::ParamCommand).*/
|
||||
class CmdPosition : public Ogre::ParamCommand
|
||||
{
|
||||
public:
|
||||
Ogre::String doGet(const void *target) const
|
||||
{
|
||||
const GravityAffector *self = static_cast<const GravityAffector*>(target);
|
||||
return Ogre::StringConverter::toString(self->getPosition());
|
||||
}
|
||||
void doSet(void *target, const Ogre::String &val)
|
||||
{
|
||||
GravityAffector *self = static_cast<GravityAffector*>(target);
|
||||
self->setPosition(Ogre::StringConverter::parseVector3(val));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Default constructor. */
|
||||
GravityAffector(Ogre::ParticleSystem *psys)
|
||||
: ParticleAffector(psys)
|
||||
, mForce(0.0f)
|
||||
, mForceType(Type_Wind)
|
||||
, mPosition(0.0f)
|
||||
, mDirection(0.0f)
|
||||
{
|
||||
mType = "Gravity";
|
||||
|
||||
// Init parameters
|
||||
if(createParamDictionary("GravityAffector"))
|
||||
{
|
||||
Ogre::ParamDictionary *dict = getParamDictionary();
|
||||
|
||||
Ogre::String force_title("force");
|
||||
Ogre::String force_descr("Amount of force applied to particles.");
|
||||
Ogre::String force_type_title("force_type");
|
||||
Ogre::String force_type_descr("Type of force applied to particles (point or wind).");
|
||||
Ogre::String direction_title("direction");
|
||||
Ogre::String direction_descr("Direction of wind forces.");
|
||||
Ogre::String position_title("position");
|
||||
Ogre::String position_descr("Position of point forces.");
|
||||
|
||||
dict->addParameter(Ogre::ParameterDef(force_title, force_descr, Ogre::PT_REAL), &msForceCmd);
|
||||
dict->addParameter(Ogre::ParameterDef(force_type_title, force_type_descr, Ogre::PT_STRING), &msForceTypeCmd);
|
||||
dict->addParameter(Ogre::ParameterDef(direction_title, direction_descr, Ogre::PT_VECTOR3), &msDirectionCmd);
|
||||
dict->addParameter(Ogre::ParameterDef(position_title, position_descr, Ogre::PT_VECTOR3), &msPositionCmd);
|
||||
}
|
||||
}
|
||||
|
||||
/** See Ogre::ParticleAffector. */
|
||||
void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed)
|
||||
{
|
||||
switch(mForceType)
|
||||
{
|
||||
case Type_Wind:
|
||||
applyWindForce(psys, timeElapsed);
|
||||
break;
|
||||
case Type_Point:
|
||||
applyPointForce(psys, timeElapsed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void setForce(Ogre::Real force)
|
||||
{ mForce = force; }
|
||||
Ogre::Real getForce() const
|
||||
{ return mForce; }
|
||||
|
||||
void setForceType(ForceType type)
|
||||
{ mForceType = type; }
|
||||
ForceType getForceType() const
|
||||
{ return mForceType; }
|
||||
|
||||
void setDirection(const Ogre::Vector3 &dir)
|
||||
{ mDirection = dir; }
|
||||
const Ogre::Vector3 &getDirection() const
|
||||
{ return mDirection; }
|
||||
|
||||
void setPosition(const Ogre::Vector3 &pos)
|
||||
{ mPosition = pos; }
|
||||
const Ogre::Vector3 &getPosition() const
|
||||
{ return mPosition; }
|
||||
|
||||
static CmdForce msForceCmd;
|
||||
static CmdForceType msForceTypeCmd;
|
||||
static CmdDirection msDirectionCmd;
|
||||
static CmdPosition msPositionCmd;
|
||||
|
||||
protected:
|
||||
void applyWindForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed)
|
||||
{
|
||||
const Ogre::Vector3 vec = mDirection * mForce * timeElapsed;
|
||||
Ogre::ParticleIterator pi = psys->_getIterator();
|
||||
while (!pi.end())
|
||||
{
|
||||
Ogre::Particle *p = pi.getNext();
|
||||
p->direction += vec;
|
||||
}
|
||||
}
|
||||
|
||||
void applyPointForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed)
|
||||
{
|
||||
const Ogre::Real force = mForce * timeElapsed;
|
||||
Ogre::ParticleIterator pi = psys->_getIterator();
|
||||
while (!pi.end())
|
||||
{
|
||||
Ogre::Particle *p = pi.getNext();
|
||||
const Ogre::Vector3 vec = (p->position - mPosition).normalisedCopy() * force;
|
||||
p->direction += vec;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float mForce;
|
||||
|
||||
ForceType mForceType;
|
||||
|
||||
Ogre::Vector3 mPosition;
|
||||
Ogre::Vector3 mDirection;
|
||||
};
|
||||
GravityAffector::CmdForce GravityAffector::msForceCmd;
|
||||
GravityAffector::CmdForceType GravityAffector::msForceTypeCmd;
|
||||
GravityAffector::CmdDirection GravityAffector::msDirectionCmd;
|
||||
GravityAffector::CmdPosition GravityAffector::msPositionCmd;
|
||||
|
||||
Ogre::ParticleAffector *GravityAffectorFactory::createAffector(Ogre::ParticleSystem *psys)
|
||||
{
|
||||
Ogre::ParticleAffector *p = new GravityAffector(psys);
|
||||
mAffectors.push_back(p);
|
||||
return p;
|
||||
}
|
41
libs/openengine/ogre/particles.hpp
Normal file
41
libs/openengine/ogre/particles.hpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
#ifndef OENGINE_OGRE_PARTICLES_H
|
||||
#define OENGINE_OGRE_PARTICLES_H
|
||||
|
||||
#include <OgreParticleEmitterFactory.h>
|
||||
#include <OgreParticleAffectorFactory.h>
|
||||
|
||||
/** Factory class for NifEmitter. */
|
||||
class NifEmitterFactory : public Ogre::ParticleEmitterFactory
|
||||
{
|
||||
public:
|
||||
/** See ParticleEmitterFactory */
|
||||
Ogre::String getName() const
|
||||
{ return "Nif"; }
|
||||
|
||||
/** See ParticleEmitterFactory */
|
||||
Ogre::ParticleEmitter* createEmitter(Ogre::ParticleSystem *psys);
|
||||
};
|
||||
|
||||
/** Factory class for GrowFadeAffector. */
|
||||
class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory
|
||||
{
|
||||
/** See Ogre::ParticleAffectorFactory */
|
||||
Ogre::String getName() const
|
||||
{ return "GrowFade"; }
|
||||
|
||||
/** See Ogre::ParticleAffectorFactory */
|
||||
Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys);
|
||||
};
|
||||
|
||||
/** Factory class for GravityAffector. */
|
||||
class GravityAffectorFactory : public Ogre::ParticleAffectorFactory
|
||||
{
|
||||
/** See Ogre::ParticleAffectorFactory */
|
||||
Ogre::String getName() const
|
||||
{ return "Gravity"; }
|
||||
|
||||
/** See Ogre::ParticleAffectorFactory */
|
||||
Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys);
|
||||
};
|
||||
|
||||
#endif /* OENGINE_OGRE_PARTICLES_H */
|
319
libs/openengine/ogre/renderer.cpp
Normal file
319
libs/openengine/ogre/renderer.cpp
Normal file
|
@ -0,0 +1,319 @@
|
|||
#include "renderer.hpp"
|
||||
#include "fader.hpp"
|
||||
#include "particles.hpp"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "OgreRoot.h"
|
||||
#include "OgreRenderWindow.h"
|
||||
#include "OgreLogManager.h"
|
||||
#include "OgreLog.h"
|
||||
#include "OgreTextureManager.h"
|
||||
#include "OgreTexture.h"
|
||||
#include "OgreHardwarePixelBuffer.h"
|
||||
#include <OgreParticleSystemManager.h>
|
||||
#include "OgreParticleAffectorFactory.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <components/files/ogreplugin.hpp>
|
||||
|
||||
#include <extern/sdl4ogre/sdlwindowhelper.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace Ogre;
|
||||
using namespace OEngine::Render;
|
||||
|
||||
|
||||
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
|
||||
|
||||
CustomRoot::CustomRoot(const Ogre::String& pluginFileName,
|
||||
const Ogre::String& configFileName,
|
||||
const Ogre::String& logFileName)
|
||||
: Ogre::Root(pluginFileName, configFileName, logFileName)
|
||||
{}
|
||||
|
||||
bool CustomRoot::isQueuedEnd() const
|
||||
{
|
||||
return mQueuedEnd;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void OgreRenderer::cleanup()
|
||||
{
|
||||
delete mFader;
|
||||
mFader = NULL;
|
||||
|
||||
delete mRoot;
|
||||
mRoot = NULL;
|
||||
|
||||
// If we don't do this, the desktop resolution is not restored on exit
|
||||
SDL_SetWindowFullscreen(mSDLWindow, 0);
|
||||
|
||||
SDL_DestroyWindow(mSDLWindow);
|
||||
mSDLWindow = NULL;
|
||||
|
||||
unloadPlugins();
|
||||
}
|
||||
|
||||
void OgreRenderer::start()
|
||||
{
|
||||
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
|
||||
// we need this custom main loop because otherwise Ogre's Carbon message pump will
|
||||
// steal input events even from our Cocoa window
|
||||
// There's no way to disable Ogre's message pump other that comment pump code in Ogre's source
|
||||
do {
|
||||
if (!mRoot->renderOneFrame()) {
|
||||
break;
|
||||
}
|
||||
|
||||
} while (!mRoot->isQueuedEnd());
|
||||
#else
|
||||
mRoot->startRendering();
|
||||
#endif
|
||||
}
|
||||
|
||||
void OgreRenderer::loadPlugins()
|
||||
{
|
||||
#ifdef ENABLE_PLUGIN_GL
|
||||
mGLPlugin = new Ogre::GLPlugin();
|
||||
mRoot->installPlugin(mGLPlugin);
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_Direct3D9
|
||||
mD3D9Plugin = new Ogre::D3D9Plugin();
|
||||
mRoot->installPlugin(mD3D9Plugin);
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_CgProgramManager
|
||||
mCgPlugin = new Ogre::CgPlugin();
|
||||
mRoot->installPlugin(mCgPlugin);
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_OctreeSceneManager
|
||||
mOctreePlugin = new Ogre::OctreePlugin();
|
||||
mRoot->installPlugin(mOctreePlugin);
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_ParticleFX
|
||||
mParticleFXPlugin = new Ogre::ParticleFXPlugin();
|
||||
mRoot->installPlugin(mParticleFXPlugin);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OgreRenderer::unloadPlugins()
|
||||
{
|
||||
std::vector<Ogre::ParticleEmitterFactory*>::iterator ei;
|
||||
for(ei = mEmitterFactories.begin();ei != mEmitterFactories.end();++ei)
|
||||
OGRE_DELETE (*ei);
|
||||
mEmitterFactories.clear();
|
||||
|
||||
std::vector<Ogre::ParticleAffectorFactory*>::iterator ai;
|
||||
for(ai = mAffectorFactories.begin();ai != mAffectorFactories.end();++ai)
|
||||
OGRE_DELETE (*ai);
|
||||
mAffectorFactories.clear();
|
||||
|
||||
#ifdef ENABLE_PLUGIN_GL
|
||||
delete mGLPlugin;
|
||||
mGLPlugin = NULL;
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_Direct3D9
|
||||
delete mD3D9Plugin;
|
||||
mD3D9Plugin = NULL;
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_CgProgramManager
|
||||
delete mCgPlugin;
|
||||
mCgPlugin = NULL;
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_OctreeSceneManager
|
||||
delete mOctreePlugin;
|
||||
mOctreePlugin = NULL;
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_ParticleFX
|
||||
delete mParticleFXPlugin;
|
||||
mParticleFXPlugin = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void OgreRenderer::update(float dt)
|
||||
{
|
||||
mFader->update(dt);
|
||||
}
|
||||
|
||||
void OgreRenderer::screenshot(const std::string &file)
|
||||
{
|
||||
mWindow->writeContentsToFile(file);
|
||||
}
|
||||
|
||||
float OgreRenderer::getFPS()
|
||||
{
|
||||
return mWindow->getLastFPS();
|
||||
}
|
||||
|
||||
void OgreRenderer::configure(const std::string &logPath,
|
||||
const std::string& renderSystem,
|
||||
const std::string& rttMode,
|
||||
bool _logging)
|
||||
{
|
||||
// Set up logging first
|
||||
new LogManager;
|
||||
Log *log = LogManager::getSingleton().createLog(logPath + std::string("Ogre.log"));
|
||||
logging = _logging;
|
||||
|
||||
if(logging)
|
||||
// Full log detail
|
||||
log->setLogDetail(LL_BOREME);
|
||||
else
|
||||
// Disable logging
|
||||
log->setDebugOutputEnabled(false);
|
||||
|
||||
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
|
||||
mRoot = new CustomRoot("", "", "");
|
||||
#else
|
||||
mRoot = new Root("", "", "");
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_PLUGIN_GL) || defined(ENABLE_PLUGIN_Direct3D9) || defined(ENABLE_PLUGIN_CgProgramManager) || defined(ENABLE_PLUGIN_OctreeSceneManager) || defined(ENABLE_PLUGIN_ParticleFX)
|
||||
loadPlugins();
|
||||
#endif
|
||||
|
||||
std::string pluginDir;
|
||||
const char* pluginEnv = getenv("OPENMW_OGRE_PLUGIN_DIR");
|
||||
if (pluginEnv)
|
||||
pluginDir = pluginEnv;
|
||||
else
|
||||
{
|
||||
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
|
||||
pluginDir = ".\\";
|
||||
#endif
|
||||
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
|
||||
pluginDir = OGRE_PLUGIN_DIR;
|
||||
#endif
|
||||
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
|
||||
pluginDir = OGRE_PLUGIN_DIR_REL;
|
||||
#endif
|
||||
}
|
||||
|
||||
boost::filesystem::path absPluginPath = boost::filesystem::absolute(boost::filesystem::path(pluginDir));
|
||||
|
||||
pluginDir = absPluginPath.string();
|
||||
|
||||
Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mRoot);
|
||||
Files::loadOgrePlugin(pluginDir, "RenderSystem_GLES2", *mRoot);
|
||||
Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mRoot);
|
||||
Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mRoot);
|
||||
Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot);
|
||||
Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot);
|
||||
|
||||
|
||||
Ogre::ParticleEmitterFactory *emitter;
|
||||
emitter = OGRE_NEW NifEmitterFactory();
|
||||
Ogre::ParticleSystemManager::getSingleton().addEmitterFactory(emitter);
|
||||
mEmitterFactories.push_back(emitter);
|
||||
|
||||
|
||||
Ogre::ParticleAffectorFactory *affector;
|
||||
affector = OGRE_NEW GrowFadeAffectorFactory();
|
||||
Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector);
|
||||
mAffectorFactories.push_back(affector);
|
||||
|
||||
affector = OGRE_NEW GravityAffectorFactory();
|
||||
Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector);
|
||||
mAffectorFactories.push_back(affector);
|
||||
|
||||
|
||||
RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem);
|
||||
if (rs == 0)
|
||||
throw std::runtime_error ("RenderSystem with name " + renderSystem + " not found, make sure the plugins are loaded");
|
||||
mRoot->setRenderSystem(rs);
|
||||
|
||||
if (rs->getName().find("OpenGL") != std::string::npos)
|
||||
rs->setConfigOption ("RTT Preferred Mode", rttMode);
|
||||
}
|
||||
|
||||
void OgreRenderer::createWindow(const std::string &title, const WindowSettings& settings)
|
||||
{
|
||||
assert(mRoot);
|
||||
mRoot->initialise(false);
|
||||
|
||||
NameValuePairList params;
|
||||
params.insert(std::make_pair("title", title));
|
||||
params.insert(std::make_pair("FSAA", settings.fsaa));
|
||||
params.insert(std::make_pair("vsync", settings.vsync ? "true" : "false"));
|
||||
|
||||
int pos_x = SDL_WINDOWPOS_CENTERED_DISPLAY(settings.screen),
|
||||
pos_y = SDL_WINDOWPOS_CENTERED_DISPLAY(settings.screen);
|
||||
|
||||
if(settings.fullscreen)
|
||||
{
|
||||
pos_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(settings.screen);
|
||||
pos_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(settings.screen);
|
||||
}
|
||||
|
||||
|
||||
// Create an application window with the following settings:
|
||||
mSDLWindow = SDL_CreateWindow(
|
||||
"OpenMW", // window title
|
||||
pos_x, // initial x position
|
||||
pos_y, // initial y position
|
||||
settings.window_x, // width, in pixels
|
||||
settings.window_y, // height, in pixels
|
||||
SDL_WINDOW_SHOWN
|
||||
| (settings.fullscreen ? SDL_WINDOW_FULLSCREEN : 0) | SDL_WINDOW_RESIZABLE
|
||||
);
|
||||
|
||||
SFO::SDLWindowHelper helper(mSDLWindow, settings.window_x, settings.window_y, title, settings.fullscreen, params);
|
||||
if (settings.icon != "")
|
||||
helper.setWindowIcon(settings.icon);
|
||||
mWindow = helper.getWindow();
|
||||
|
||||
|
||||
// create the semi-transparent black background texture used by the GUI.
|
||||
// has to be created in code with TU_DYNAMIC_WRITE_ONLY param
|
||||
// so that it can be modified at runtime.
|
||||
Ogre::TextureManager::getSingleton().createManual(
|
||||
"transparent.png",
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
Ogre::TEX_TYPE_2D,
|
||||
1, 1,
|
||||
0,
|
||||
Ogre::PF_A8R8G8B8,
|
||||
Ogre::TU_WRITE_ONLY);
|
||||
|
||||
mScene = mRoot->createSceneManager(ST_GENERIC);
|
||||
|
||||
mFader = new Fader(mScene);
|
||||
|
||||
mCamera = mScene->createCamera("cam");
|
||||
|
||||
// Create one viewport, entire window
|
||||
mView = mWindow->addViewport(mCamera);
|
||||
// Alter the camera aspect ratio to match the viewport
|
||||
mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight()));
|
||||
}
|
||||
|
||||
void OgreRenderer::adjustCamera(float fov, float nearClip)
|
||||
{
|
||||
mCamera->setNearClipDistance(nearClip);
|
||||
mCamera->setFOVy(Degree(fov));
|
||||
}
|
||||
|
||||
void OgreRenderer::adjustViewport()
|
||||
{
|
||||
// Alter the camera aspect ratio to match the viewport
|
||||
if(mCamera != NULL)
|
||||
{
|
||||
mView->setDimensions(0, 0, 1, 1);
|
||||
mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight()));
|
||||
}
|
||||
}
|
||||
|
||||
void OgreRenderer::setFov(float fov)
|
||||
{
|
||||
mCamera->setFOVy(Degree(fov));
|
||||
}
|
||||
|
||||
void OgreRenderer::windowResized(int x, int y)
|
||||
{
|
||||
mWindowListener->windowResized(x,y);
|
||||
}
|
213
libs/openengine/ogre/renderer.hpp
Normal file
213
libs/openengine/ogre/renderer.hpp
Normal file
|
@ -0,0 +1,213 @@
|
|||
#ifndef OENGINE_OGRE_RENDERER_H
|
||||
#define OENGINE_OGRE_RENDERER_H
|
||||
|
||||
/*
|
||||
Ogre renderer class
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
// Static plugin headers
|
||||
#ifdef ENABLE_PLUGIN_CgProgramManager
|
||||
# include "OgreCgPlugin.h"
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_OctreeSceneManager
|
||||
# include "OgreOctreePlugin.h"
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_ParticleFX
|
||||
# include "OgreParticleFXPlugin.h"
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_GL
|
||||
# include "OgreGLPlugin.h"
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_Direct3D9
|
||||
# include "OgreD3D9Plugin.h"
|
||||
#endif
|
||||
|
||||
#include "OgreTexture.h"
|
||||
#include <OgreWindowEventUtilities.h>
|
||||
|
||||
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
|
||||
#include <OgreRoot.h>
|
||||
#endif
|
||||
|
||||
struct SDL_Window;
|
||||
struct SDL_Surface;
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
#if OGRE_PLATFORM != OGRE_PLATFORM_APPLE
|
||||
class Root;
|
||||
#endif
|
||||
class RenderWindow;
|
||||
class SceneManager;
|
||||
class Camera;
|
||||
class Viewport;
|
||||
class ParticleEmitterFactory;
|
||||
class ParticleAffectorFactory;
|
||||
}
|
||||
|
||||
namespace OEngine
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
struct WindowSettings
|
||||
{
|
||||
bool vsync;
|
||||
bool fullscreen;
|
||||
int window_x, window_y;
|
||||
int screen;
|
||||
std::string fsaa;
|
||||
std::string icon;
|
||||
};
|
||||
|
||||
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
|
||||
class CustomRoot : public Ogre::Root {
|
||||
public:
|
||||
bool isQueuedEnd() const;
|
||||
|
||||
CustomRoot(const Ogre::String& pluginFileName = "plugins.cfg",
|
||||
const Ogre::String& configFileName = "ogre.cfg",
|
||||
const Ogre::String& logFileName = "Ogre.log");
|
||||
};
|
||||
#endif
|
||||
|
||||
class Fader;
|
||||
|
||||
class WindowSizeListener
|
||||
{
|
||||
public:
|
||||
virtual void windowResized (int x, int y) = 0;
|
||||
};
|
||||
|
||||
class OgreRenderer
|
||||
{
|
||||
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
|
||||
CustomRoot *mRoot;
|
||||
#else
|
||||
Ogre::Root *mRoot;
|
||||
#endif
|
||||
Ogre::RenderWindow *mWindow;
|
||||
SDL_Window *mSDLWindow;
|
||||
Ogre::SceneManager *mScene;
|
||||
Ogre::Camera *mCamera;
|
||||
Ogre::Viewport *mView;
|
||||
#ifdef ENABLE_PLUGIN_CgProgramManager
|
||||
Ogre::CgPlugin* mCgPlugin;
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_OctreeSceneManager
|
||||
Ogre::OctreePlugin* mOctreePlugin;
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_ParticleFX
|
||||
Ogre::ParticleFXPlugin* mParticleFXPlugin;
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_GL
|
||||
Ogre::GLPlugin* mGLPlugin;
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_Direct3D9
|
||||
Ogre::D3D9Plugin* mD3D9Plugin;
|
||||
#endif
|
||||
Fader* mFader;
|
||||
std::vector<Ogre::ParticleEmitterFactory*> mEmitterFactories;
|
||||
std::vector<Ogre::ParticleAffectorFactory*> mAffectorFactories;
|
||||
bool logging;
|
||||
|
||||
WindowSizeListener* mWindowListener;
|
||||
|
||||
public:
|
||||
OgreRenderer()
|
||||
: mRoot(NULL)
|
||||
, mWindow(NULL)
|
||||
, mSDLWindow(NULL)
|
||||
, mScene(NULL)
|
||||
, mCamera(NULL)
|
||||
, mView(NULL)
|
||||
, mWindowListener(NULL)
|
||||
#ifdef ENABLE_PLUGIN_CgProgramManager
|
||||
, mCgPlugin(NULL)
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_OctreeSceneManager
|
||||
, mOctreePlugin(NULL)
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_ParticleFX
|
||||
, mParticleFXPlugin(NULL)
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_GL
|
||||
, mGLPlugin(NULL)
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_Direct3D9
|
||||
, mD3D9Plugin(NULL)
|
||||
#endif
|
||||
, mFader(NULL)
|
||||
, logging(false)
|
||||
{
|
||||
}
|
||||
|
||||
~OgreRenderer() { cleanup(); }
|
||||
|
||||
/** Configure the renderer. This will load configuration files and
|
||||
set up the Root and logging classes. */
|
||||
void configure(
|
||||
const std::string &logPath, // Path to directory where to store log files
|
||||
const std::string &renderSystem,
|
||||
const std::string &rttMode,
|
||||
bool _logging); // Enable or disable logging
|
||||
|
||||
/// Create a window with the given title
|
||||
void createWindow(const std::string &title, const WindowSettings& settings);
|
||||
|
||||
/// Set up the scene manager, camera and viewport
|
||||
void adjustCamera(
|
||||
float fov=55, // Field of view angle
|
||||
float nearClip=5 // Near clip distance
|
||||
);
|
||||
|
||||
void setFov(float fov);
|
||||
|
||||
/// Kill the renderer.
|
||||
void cleanup();
|
||||
|
||||
/// Start the main rendering loop
|
||||
void start();
|
||||
|
||||
void loadPlugins();
|
||||
|
||||
void unloadPlugins();
|
||||
|
||||
void update(float dt);
|
||||
|
||||
/// Write a screenshot to file
|
||||
void screenshot(const std::string &file);
|
||||
|
||||
float getFPS();
|
||||
|
||||
void windowResized(int x, int y);
|
||||
|
||||
/// Get the Root
|
||||
Ogre::Root *getRoot() { return mRoot; }
|
||||
|
||||
/// Get the rendering window
|
||||
Ogre::RenderWindow *getWindow() { return mWindow; }
|
||||
|
||||
/// Get the SDL Window
|
||||
SDL_Window *getSDLWindow() { return mSDLWindow; }
|
||||
|
||||
/// Get the scene manager
|
||||
Ogre::SceneManager *getScene() { return mScene; }
|
||||
|
||||
/// Get the screen colour fader
|
||||
Fader *getFader() { return mFader; }
|
||||
|
||||
/// Camera
|
||||
Ogre::Camera *getCamera() { return mCamera; }
|
||||
|
||||
/// Viewport
|
||||
Ogre::Viewport *getViewport() { return mView; }
|
||||
|
||||
void setWindowListener(WindowSizeListener* listener) { mWindowListener = listener; }
|
||||
|
||||
void adjustViewport();
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
134
libs/openengine/ogre/selectionbuffer.cpp
Normal file
134
libs/openengine/ogre/selectionbuffer.cpp
Normal file
|
@ -0,0 +1,134 @@
|
|||
#include "selectionbuffer.hpp"
|
||||
|
||||
#include <OgreHardwarePixelBuffer.h>
|
||||
#include <OgreRenderTexture.h>
|
||||
#include <OgreSubEntity.h>
|
||||
#include <OgreEntity.h>
|
||||
#include <OgreTechnique.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <extern/shiny/Main/Factory.hpp>
|
||||
|
||||
namespace OEngine
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
|
||||
SelectionBuffer::SelectionBuffer(Ogre::Camera *camera, int sizeX, int sizeY, int visibilityFlags)
|
||||
{
|
||||
mTexture = Ogre::TextureManager::getSingleton().createManual("SelectionBuffer",
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, sizeX, sizeY, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
|
||||
|
||||
mRenderTarget = mTexture->getBuffer()->getRenderTarget();
|
||||
Ogre::Viewport* vp = mRenderTarget->addViewport(camera);
|
||||
vp->setOverlaysEnabled(false);
|
||||
vp->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0));
|
||||
vp->setShadowsEnabled(false);
|
||||
vp->setMaterialScheme("selectionbuffer");
|
||||
if (visibilityFlags != 0)
|
||||
vp->setVisibilityMask (visibilityFlags);
|
||||
mRenderTarget->setActive(true);
|
||||
mRenderTarget->setAutoUpdated (false);
|
||||
|
||||
mCurrentColour = Ogre::ColourValue(0.3, 0.3, 0.3);
|
||||
}
|
||||
|
||||
SelectionBuffer::~SelectionBuffer()
|
||||
{
|
||||
Ogre::TextureManager::getSingleton ().remove("SelectionBuffer");
|
||||
}
|
||||
|
||||
void SelectionBuffer::update ()
|
||||
{
|
||||
Ogre::MaterialManager::getSingleton ().addListener (this);
|
||||
|
||||
mRenderTarget->update();
|
||||
|
||||
Ogre::MaterialManager::getSingleton ().removeListener (this);
|
||||
|
||||
mTexture->convertToImage(mBuffer);
|
||||
}
|
||||
|
||||
int SelectionBuffer::getSelected(int xPos, int yPos)
|
||||
{
|
||||
Ogre::ColourValue clr = mBuffer.getColourAt (xPos, yPos, 0);
|
||||
clr.a = 1;
|
||||
if (mColourMap.find(clr) != mColourMap.end())
|
||||
return mColourMap[clr];
|
||||
else
|
||||
return -1; // nothing selected
|
||||
}
|
||||
|
||||
Ogre::Technique* SelectionBuffer::handleSchemeNotFound (
|
||||
unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial,
|
||||
unsigned short lodIndex, const Ogre::Renderable *rend)
|
||||
{
|
||||
if (schemeName == "selectionbuffer")
|
||||
{
|
||||
sh::Factory::getInstance ()._ensureMaterial ("SelectionColour", "Default");
|
||||
|
||||
Ogre::MaterialPtr m = Ogre::MaterialManager::getSingleton ().getByName("SelectionColour");
|
||||
|
||||
|
||||
if(typeid(*rend) == typeid(Ogre::SubEntity))
|
||||
{
|
||||
const Ogre::SubEntity *subEntity = static_cast<const Ogre::SubEntity *>(rend);
|
||||
int id = Ogre::any_cast<int>(subEntity->getParent ()->getUserObjectBindings().getUserAny());
|
||||
bool found = false;
|
||||
Ogre::ColourValue colour;
|
||||
for (std::map<Ogre::ColourValue, int, cmp_ColourValue>::iterator it = mColourMap.begin(); it != mColourMap.end(); ++it)
|
||||
{
|
||||
if (it->second == id)
|
||||
{
|
||||
found = true;
|
||||
colour = it->first;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!found)
|
||||
{
|
||||
getNextColour();
|
||||
const_cast<Ogre::SubEntity *>(subEntity)->setCustomParameter(1, Ogre::Vector4(mCurrentColour.r, mCurrentColour.g, mCurrentColour.b, 1.0));
|
||||
mColourMap[mCurrentColour] = id;
|
||||
}
|
||||
else
|
||||
{
|
||||
const_cast<Ogre::SubEntity *>(subEntity)->setCustomParameter(1, Ogre::Vector4(colour.r, colour.g, colour.b, 1.0));
|
||||
}
|
||||
|
||||
assert(m->getTechnique(1));
|
||||
return m->getTechnique(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m = Ogre::MaterialManager::getSingleton().getByName("NullMaterial");
|
||||
if(m.isNull())
|
||||
{
|
||||
m = Ogre::MaterialManager::getSingleton().create("NullMaterial", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||
m->getTechnique(0)->getPass(0)->setDepthCheckEnabled(true);
|
||||
m->getTechnique(0)->getPass(0)->setDepthFunction(Ogre::CMPF_ALWAYS_FAIL);
|
||||
}
|
||||
return m->getTechnique(0);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SelectionBuffer::getNextColour ()
|
||||
{
|
||||
Ogre::ARGB color = (float(rand()) / float(RAND_MAX)) * std::numeric_limits<Ogre::uint32>::max();
|
||||
|
||||
if (mCurrentColour.getAsARGB () == color)
|
||||
{
|
||||
getNextColour();
|
||||
return;
|
||||
}
|
||||
|
||||
mCurrentColour.setAsARGB(color);
|
||||
mCurrentColour.a = 1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
54
libs/openengine/ogre/selectionbuffer.hpp
Normal file
54
libs/openengine/ogre/selectionbuffer.hpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef OENGINE_SELECTIONBUFFER_H
|
||||
#define OENGINE_SELECTIONBUFFER_H
|
||||
|
||||
|
||||
#include <OgreTexture.h>
|
||||
#include <OgreRenderTarget.h>
|
||||
#include <OgreMaterialManager.h>
|
||||
|
||||
namespace OEngine
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
|
||||
struct cmp_ColourValue
|
||||
{
|
||||
bool operator()(const Ogre::ColourValue &a, const Ogre::ColourValue &b) const
|
||||
{
|
||||
return a.getAsBGRA() < b.getAsBGRA();
|
||||
}
|
||||
};
|
||||
|
||||
class SelectionBuffer : public Ogre::MaterialManager::Listener
|
||||
{
|
||||
public:
|
||||
SelectionBuffer(Ogre::Camera* camera, int sizeX, int sizeY, int visibilityFlags);
|
||||
virtual ~SelectionBuffer();
|
||||
|
||||
int getSelected(int xPos, int yPos);
|
||||
///< @return ID of the selected object
|
||||
|
||||
void update();
|
||||
|
||||
virtual Ogre::Technique* handleSchemeNotFound (
|
||||
unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial,
|
||||
unsigned short lodIndex, const Ogre::Renderable *rend);
|
||||
|
||||
|
||||
private:
|
||||
Ogre::TexturePtr mTexture;
|
||||
Ogre::RenderTexture* mRenderTarget;
|
||||
|
||||
Ogre::Image mBuffer;
|
||||
|
||||
std::map<Ogre::ColourValue, int, cmp_ColourValue> mColourMap;
|
||||
|
||||
Ogre::ColourValue mCurrentColour;
|
||||
|
||||
void getNextColour();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
11
libs/openengine/testall.sh
Executable file
11
libs/openengine/testall.sh
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
function run()
|
||||
{
|
||||
echo "TESTING $1"
|
||||
cd "$1/tests/"
|
||||
./test.sh
|
||||
cd ../../
|
||||
}
|
||||
|
||||
run input
|
Loading…
Add table
Add a link
Reference in a new issue