mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:23:51 +00:00
Various collision changes:
- no collision with NCO objects - better camera control (no turning the camera upside down) - up/down buttons (shift/ctrl) does not move the player when walking - eye level adjusted - various updates git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@55 ea6a568a-9f4f-0410-981a-c910a81bb256
This commit is contained in:
parent
e927c9a70e
commit
08ba0278a1
9 changed files with 236 additions and 97 deletions
2
Makefile
2
Makefile
|
@ -28,7 +28,7 @@ ogre_cpp=ogre framelistener interface overlay bsaarchive
|
||||||
avcodec_cpp=avcodec
|
avcodec_cpp=avcodec
|
||||||
|
|
||||||
# Bullet cpp files
|
# Bullet cpp files
|
||||||
bullet_cpp=bullet player
|
bullet_cpp=bullet player scale
|
||||||
|
|
||||||
#### No modifications should be required below this line. ####
|
#### No modifications should be required below this line. ####
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,7 @@ Changelog:
|
||||||
0.5 (WIP)
|
0.5 (WIP)
|
||||||
|
|
||||||
- working on collision detection with Bullet
|
- working on collision detection with Bullet
|
||||||
|
- working on walk & fall character physics
|
||||||
- working on fixing sound issues for windows (running out of sound
|
- working on fixing sound issues for windows (running out of sound
|
||||||
resources, music playback doesn't good)
|
resources, music playback doesn't good)
|
||||||
- new key bindings:
|
- new key bindings:
|
||||||
|
|
|
@ -48,6 +48,13 @@ void bullet_setPlayerDir(float x, float y, float z);
|
||||||
// been applied.
|
// been applied.
|
||||||
void bullet_getPlayerPos(float *x, float *y, float *z);
|
void bullet_getPlayerPos(float *x, float *y, float *z);
|
||||||
|
|
||||||
|
// Create a box shape.
|
||||||
|
/*
|
||||||
|
void bullet_createBoxShape(float minX, float minY, float minZ,
|
||||||
|
float maxX, float maxY, float maxZ,
|
||||||
|
float *trans,float *matrix);
|
||||||
|
*/
|
||||||
|
|
||||||
// Create a triangle shape. This is cumulative, all meshes created
|
// Create a triangle shape. This is cumulative, all meshes created
|
||||||
// with this function are added to the same shape. Since the various
|
// with this function are added to the same shape. Since the various
|
||||||
// parts of a mesh can be differently transformed and we are putting
|
// parts of a mesh can be differently transformed and we are putting
|
||||||
|
|
|
@ -29,6 +29,12 @@ using namespace std;
|
||||||
|
|
||||||
class CustomOverlappingPairCallback;
|
class CustomOverlappingPairCallback;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MASK_PLAYER = 1,
|
||||||
|
MASK_STATIC = 2
|
||||||
|
};
|
||||||
|
|
||||||
// System variables
|
// System variables
|
||||||
btDefaultCollisionConfiguration* g_collisionConfiguration;
|
btDefaultCollisionConfiguration* g_collisionConfiguration;
|
||||||
btCollisionDispatcher *g_dispatcher;
|
btCollisionDispatcher *g_dispatcher;
|
||||||
|
@ -56,6 +62,11 @@ btVector3 g_walkDirection;
|
||||||
// added into this, until bullet_getFinalShape() is called.
|
// added into this, until bullet_getFinalShape() is called.
|
||||||
btTriangleIndexVertexArray *g_currentMesh;
|
btTriangleIndexVertexArray *g_currentMesh;
|
||||||
|
|
||||||
|
// Current compound shape being built. g_compoundShape and
|
||||||
|
// g_currentMesh are returned together (the mesh inserted into the
|
||||||
|
// compound) if both are present.
|
||||||
|
btCompoundShape *g_compoundShape;
|
||||||
|
|
||||||
// These variables and the class below are used in player collision
|
// These variables and the class below are used in player collision
|
||||||
// detection. The callback is injected into the broadphase and keeps a
|
// detection. The callback is injected into the broadphase and keeps a
|
||||||
// continuously updated list of what objects are colliding with the
|
// continuously updated list of what objects are colliding with the
|
||||||
|
@ -77,6 +88,9 @@ int g_physMode;
|
||||||
// Include the player physics
|
// Include the player physics
|
||||||
#include "cpp_player.cpp"
|
#include "cpp_player.cpp"
|
||||||
|
|
||||||
|
// Include the uniform shape scaler
|
||||||
|
//#include "cpp_scale.cpp"
|
||||||
|
|
||||||
class CustomOverlappingPairCallback : public btOverlappingPairCallback
|
class CustomOverlappingPairCallback : public btOverlappingPairCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -105,13 +119,6 @@ public:
|
||||||
{ if (proxy0->m_clientObject==g_playerObject)
|
{ if (proxy0->m_clientObject==g_playerObject)
|
||||||
g_pairCache->removeOverlappingPairsContainingProxy(proxy0,dispatcher);
|
g_pairCache->removeOverlappingPairsContainingProxy(proxy0,dispatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* KILLME
|
|
||||||
btBroadphasePairArray& getOverlappingPairArray()
|
|
||||||
{ return g_pairCache->getOverlappingPairArray(); }
|
|
||||||
btOverlappingPairCache* getOverlappingPairCache()
|
|
||||||
{ return g_pairCache; }
|
|
||||||
*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" int32_t bullet_init()
|
extern "C" int32_t bullet_init()
|
||||||
|
@ -132,8 +139,8 @@ extern "C" int32_t bullet_init()
|
||||||
// to create a custom broadphase designed for our purpose. (We
|
// to create a custom broadphase designed for our purpose. (We
|
||||||
// should probably use different ones for interior and exterior
|
// should probably use different ones for interior and exterior
|
||||||
// cells in any case.)
|
// cells in any case.)
|
||||||
btVector3 worldMin(-40000,-40000,-40000);
|
btVector3 worldMin(-20000,-20000,-20000);
|
||||||
btVector3 worldMax(40000,40000,40000);
|
btVector3 worldMax(20000,20000,20000);
|
||||||
g_broadphase = new btAxisSweep3(worldMin,worldMax);
|
g_broadphase = new btAxisSweep3(worldMin,worldMax);
|
||||||
|
|
||||||
g_dynamicsWorld =
|
g_dynamicsWorld =
|
||||||
|
@ -149,20 +156,25 @@ extern "C" int32_t bullet_init()
|
||||||
|
|
||||||
// Create the player collision shape.
|
// Create the player collision shape.
|
||||||
float width = 50;
|
float width = 50;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// One possible shape is the convex hull around two spheres
|
float height = 50;
|
||||||
float height = 100;
|
|
||||||
btVector3 spherePositions[2];
|
btVector3 spherePositions[2];
|
||||||
btScalar sphereRadii[2];
|
btScalar sphereRadii[2];
|
||||||
sphereRadii[0] = width;
|
sphereRadii[0] = width;
|
||||||
sphereRadii[1] = width;
|
sphereRadii[1] = width;
|
||||||
spherePositions[0] = btVector3 (0.0, height/2.0, 0.0);
|
spherePositions[0] = btVector3 (0,0,0);
|
||||||
spherePositions[1] = btVector3 (0.0, -height/2.0, 0.0);
|
spherePositions[1] = btVector3 (0,0,-height);
|
||||||
|
|
||||||
|
// One possible shape is the convex hull around two spheres
|
||||||
g_playerShape = new btMultiSphereShape(btVector3(width/2.0, height/2.0,
|
g_playerShape = new btMultiSphereShape(btVector3(width/2.0, height/2.0,
|
||||||
width/2.0), &spherePositions[0], &sphereRadii[0], 2);
|
width/2.0), &spherePositions[0], &sphereRadii[0], 2);
|
||||||
//*/
|
*/
|
||||||
//g_playerShape = new btCylinderShape(btVector3(50, 50, 50));
|
|
||||||
|
// Other posibilities - most are too slow, except the sphere
|
||||||
|
//g_playerShape = new btCylinderShapeZ(btVector3(width, width, height));
|
||||||
g_playerShape = new btSphereShape(width);
|
g_playerShape = new btSphereShape(width);
|
||||||
|
//g_playerShape = new btCapsuleShapeZ(width, height);
|
||||||
|
|
||||||
// Create the collision object
|
// Create the collision object
|
||||||
g_playerObject = new btCollisionObject ();
|
g_playerObject = new btCollisionObject ();
|
||||||
|
@ -183,13 +195,13 @@ extern "C" int32_t bullet_init()
|
||||||
g_dynamicsWorld->setInternalTickCallback(playerStepCallback);
|
g_dynamicsWorld->setInternalTickCallback(playerStepCallback);
|
||||||
|
|
||||||
// Add the character collision object to the world.
|
// Add the character collision object to the world.
|
||||||
g_dynamicsWorld->addCollisionObject(g_playerObject
|
g_dynamicsWorld->addCollisionObject(g_playerObject,
|
||||||
,btBroadphaseProxy::DebrisFilter
|
MASK_PLAYER,
|
||||||
//,btBroadphaseProxy::StaticFilter
|
MASK_STATIC);
|
||||||
);
|
|
||||||
|
|
||||||
// Make sure this is zero at startup
|
// Make sure these is zero at startup
|
||||||
g_currentMesh = NULL;
|
g_currentMesh = NULL;
|
||||||
|
g_compoundShape = NULL;
|
||||||
|
|
||||||
// Start out walking
|
// Start out walking
|
||||||
g_physMode = PHYS_WALK;
|
g_physMode = PHYS_WALK;
|
||||||
|
@ -242,6 +254,41 @@ extern "C" void bullet_getPlayerPos(float *x, float *y, float *z)
|
||||||
*z = g_playerPosition.getZ();
|
*z = g_playerPosition.getZ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a box shape and add it to the cumulative shape of the
|
||||||
|
// current object
|
||||||
|
/*
|
||||||
|
extern "C" void bullet_createBoxShape(float minX, float minY, float minZ,
|
||||||
|
float maxX, float maxY, float maxZ,
|
||||||
|
float *trans,float *matrix)
|
||||||
|
{
|
||||||
|
if(g_compoundShape == NULL)
|
||||||
|
g_compoundShape = new btCompoundShape;
|
||||||
|
|
||||||
|
// Build a box from the given data.
|
||||||
|
int x = (maxX-minX)/2;
|
||||||
|
int y = (maxY-minY)/2;
|
||||||
|
int z = (maxZ-minZ)/2;
|
||||||
|
btBoxShape *box = new btBoxShape(btVector3(x,y,z));
|
||||||
|
|
||||||
|
// Next, create the transformations
|
||||||
|
btMatrix3x3 mat(matrix[0], matrix[1], matrix[2],
|
||||||
|
matrix[3], matrix[4], matrix[5],
|
||||||
|
matrix[6], matrix[7], matrix[8]);
|
||||||
|
|
||||||
|
// In addition to the mesh's world translation, we have to add the
|
||||||
|
// local translation of the box origin to fit with the given min/max
|
||||||
|
// values.
|
||||||
|
x += minX + trans[0];
|
||||||
|
y += minY + trans[1];
|
||||||
|
z += minZ + trans[2];
|
||||||
|
btVector3 trns(x,y,z);
|
||||||
|
|
||||||
|
// Finally, add the shape to the compound
|
||||||
|
btTransform tr(mat, trns);
|
||||||
|
g_compoundShape->addChildShape(tr, box);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void* copyBuffer(void *buf, int elemSize, int len)
|
void* copyBuffer(void *buf, int elemSize, int len)
|
||||||
{
|
{
|
||||||
int size = elemSize * len;
|
int size = elemSize * len;
|
||||||
|
@ -251,41 +298,6 @@ void* copyBuffer(void *buf, int elemSize, int len)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define a cube with coordinates 0,0,0 - 1,1,1.
|
|
||||||
const float cube_verts[] =
|
|
||||||
{
|
|
||||||
0,0,0, 1,0,0, 0,1,0,
|
|
||||||
1,1,0, 0,0,1, 1,0,1,
|
|
||||||
0,1,1, 1,1,1
|
|
||||||
};
|
|
||||||
|
|
||||||
// Triangles of the cube. The orientation of each triange doesn't
|
|
||||||
// matter.
|
|
||||||
const short cube_tris[] =
|
|
||||||
{
|
|
||||||
// bottom side
|
|
||||||
0, 1, 2,
|
|
||||||
1, 2, 3,
|
|
||||||
// top side
|
|
||||||
4, 5, 6,
|
|
||||||
5, 6, 7,
|
|
||||||
// front side
|
|
||||||
0, 4, 5,
|
|
||||||
0, 1, 5,
|
|
||||||
// back side
|
|
||||||
2, 3, 7,
|
|
||||||
2, 6, 7,
|
|
||||||
// left side
|
|
||||||
0, 2, 4,
|
|
||||||
2, 4, 6,
|
|
||||||
// right side
|
|
||||||
1, 3, 5,
|
|
||||||
3, 5, 7
|
|
||||||
};
|
|
||||||
|
|
||||||
const int cube_num_verts = 8;
|
|
||||||
const int cube_num_tris = 12;
|
|
||||||
|
|
||||||
// Internal version that does not copy buffers
|
// Internal version that does not copy buffers
|
||||||
void createTriShape(int32_t numFaces, void *triArray,
|
void createTriShape(int32_t numFaces, void *triArray,
|
||||||
int32_t numVerts, void *vertArray,
|
int32_t numVerts, void *vertArray,
|
||||||
|
@ -329,6 +341,41 @@ void createTriShape(int32_t numFaces, void *triArray,
|
||||||
g_currentMesh->addIndexedMesh(im, PHY_SHORT);
|
g_currentMesh->addIndexedMesh(im, PHY_SHORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Define a cube with coordinates 0,0,0 - 1,1,1.
|
||||||
|
const float cube_verts[] =
|
||||||
|
{
|
||||||
|
0,0,0, 1,0,0, 0,1,0,
|
||||||
|
1,1,0, 0,0,1, 1,0,1,
|
||||||
|
0,1,1, 1,1,1
|
||||||
|
};
|
||||||
|
|
||||||
|
// Triangles of the cube. The orientation of each triange doesn't
|
||||||
|
// matter.
|
||||||
|
const short cube_tris[] =
|
||||||
|
{
|
||||||
|
// bottom side
|
||||||
|
0, 1, 2,
|
||||||
|
1, 2, 3,
|
||||||
|
// top side
|
||||||
|
4, 5, 6,
|
||||||
|
5, 6, 7,
|
||||||
|
// front side
|
||||||
|
0, 4, 5,
|
||||||
|
0, 1, 5,
|
||||||
|
// back side
|
||||||
|
2, 3, 7,
|
||||||
|
2, 6, 7,
|
||||||
|
// left side
|
||||||
|
0, 2, 4,
|
||||||
|
2, 4, 6,
|
||||||
|
// right side
|
||||||
|
1, 3, 5,
|
||||||
|
3, 5, 7
|
||||||
|
};
|
||||||
|
|
||||||
|
const int cube_num_verts = 8;
|
||||||
|
const int cube_num_tris = 12;
|
||||||
|
|
||||||
// Create a (trimesh) box with the given dimensions. Used for bounding
|
// Create a (trimesh) box with the given dimensions. Used for bounding
|
||||||
// boxes. TODO: I guess we have to use the NIF-specified bounding box
|
// boxes. TODO: I guess we have to use the NIF-specified bounding box
|
||||||
// for this, not our automatically calculated one.
|
// for this, not our automatically calculated one.
|
||||||
|
@ -379,14 +426,33 @@ extern "C" void bullet_createTriShape(int32_t numFaces,
|
||||||
// so the next call to createTriShape will start a new shape.
|
// so the next call to createTriShape will start a new shape.
|
||||||
extern "C" btCollisionShape *bullet_getFinalShape()
|
extern "C" btCollisionShape *bullet_getFinalShape()
|
||||||
{
|
{
|
||||||
// Return null if no meshes have been inserted
|
btCollisionShape *shape;
|
||||||
if(g_currentMesh == NULL) return NULL;
|
|
||||||
|
|
||||||
// Create the shape from the completed mesh
|
// Create a shape from all the inserted completed meshes
|
||||||
btBvhTriangleMeshShape *shape =
|
shape = NULL;
|
||||||
new btBvhTriangleMeshShape(g_currentMesh, false);
|
if(g_currentMesh != NULL)
|
||||||
|
shape = new btBvhTriangleMeshShape(g_currentMesh, false);
|
||||||
|
|
||||||
|
// Is there a compound shape as well? (usually contains bounding
|
||||||
|
// boxes)
|
||||||
|
if(g_compoundShape != NULL)
|
||||||
|
{
|
||||||
|
// If both shape types are present, insert the mesh shape into
|
||||||
|
// the compound.
|
||||||
|
if(shape != NULL)
|
||||||
|
{
|
||||||
|
btTransform tr;
|
||||||
|
tr.setIdentity();
|
||||||
|
g_compoundShape->addChildShape(tr, shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The compound is the final shape
|
||||||
|
shape = g_compoundShape;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear these for the next NIF
|
||||||
g_currentMesh = NULL;
|
g_currentMesh = NULL;
|
||||||
|
g_compoundShape = NULL;
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,14 +462,12 @@ extern "C" void bullet_insertStatic(btCollisionShape *shape,
|
||||||
float *quat,
|
float *quat,
|
||||||
float scale)
|
float scale)
|
||||||
{
|
{
|
||||||
// TODO: Good test case for scaled meshes: Aharunartus, some of the
|
// Are we scaled?
|
||||||
// stairs inside the cavern currently don't collide
|
|
||||||
if(scale != 1.0)
|
if(scale != 1.0)
|
||||||
{
|
return;
|
||||||
cout << "WARNING: Cannot scale collision meshes yet (wanted "
|
// Wrap the shape in a class that scales it. TODO: Try this on
|
||||||
<< scale << ")\n";
|
// ALL shapes, just to test the slowdown.
|
||||||
return;
|
//shape = new ScaleShape(shape, scale);
|
||||||
}
|
|
||||||
|
|
||||||
btTransform trafo;
|
btTransform trafo;
|
||||||
trafo.setIdentity();
|
trafo.setIdentity();
|
||||||
|
@ -416,7 +480,7 @@ extern "C" void bullet_insertStatic(btCollisionShape *shape,
|
||||||
btCollisionObject *obj = new btCollisionObject();
|
btCollisionObject *obj = new btCollisionObject();
|
||||||
obj->setCollisionShape(shape);
|
obj->setCollisionShape(shape);
|
||||||
obj->setWorldTransform(trafo);
|
obj->setWorldTransform(trafo);
|
||||||
g_dynamicsWorld->addCollisionObject(obj);
|
g_dynamicsWorld->addCollisionObject(obj, MASK_STATIC, MASK_PLAYER);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the physics simulation 'delta' seconds forward in time
|
// Move the physics simulation 'delta' seconds forward in time
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
bool g_touchingContact;
|
bool g_touchingContact;
|
||||||
btVector3 g_touchingNormal;
|
btVector3 g_touchingNormal;
|
||||||
btScalar g_currentStepOffset;
|
btScalar g_currentStepOffset;
|
||||||
float g_stepHeight = 20;
|
float g_stepHeight = 5;
|
||||||
|
|
||||||
// Returns the reflection direction of a ray going 'direction' hitting
|
// Returns the reflection direction of a ray going 'direction' hitting
|
||||||
// a surface with normal 'normal'
|
// a surface with normal 'normal'
|
||||||
|
@ -293,6 +293,18 @@ void playerStepCallback(btDynamicsWorld* dynamicsWorld, btScalar timeStep)
|
||||||
// simulation.
|
// simulation.
|
||||||
btVector3 walkStep = g_walkDirection * timeStep;
|
btVector3 walkStep = g_walkDirection * timeStep;
|
||||||
|
|
||||||
|
float len = walkStep.length();
|
||||||
|
|
||||||
|
// In walk mode, it shouldn't matter whether or not we look up or
|
||||||
|
// down. Rotate the vector back to the horizontal plane.
|
||||||
|
if(g_physMode == PHYS_WALK)
|
||||||
|
{
|
||||||
|
walkStep.setZ(0);
|
||||||
|
float len2 = walkStep.length();
|
||||||
|
if(len2 > 0)
|
||||||
|
walkStep *= len/len2;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the player position
|
// Get the player position
|
||||||
g_playerPosition = g_playerObject->getWorldTransform().getOrigin();
|
g_playerPosition = g_playerObject->getWorldTransform().getOrigin();
|
||||||
|
|
||||||
|
|
|
@ -312,6 +312,9 @@ extern(C) int d_frameStarted(float time)
|
||||||
if(isPressed(Keys.MoveRight)) moveX += speed;
|
if(isPressed(Keys.MoveRight)) moveX += speed;
|
||||||
if(isPressed(Keys.MoveForward)) moveZ -= speed;
|
if(isPressed(Keys.MoveForward)) moveZ -= speed;
|
||||||
if(isPressed(Keys.MoveBackward)) moveZ += speed;
|
if(isPressed(Keys.MoveBackward)) moveZ += speed;
|
||||||
|
|
||||||
|
// TODO: These should be enabled for floating modes (like swimming
|
||||||
|
// and levitation) only.
|
||||||
if(isPressed(Keys.MoveUp)) moveY += speed;
|
if(isPressed(Keys.MoveUp)) moveY += speed;
|
||||||
if(isPressed(Keys.MoveDown)) moveY -= speed;
|
if(isPressed(Keys.MoveDown)) moveY -= speed;
|
||||||
|
|
||||||
|
|
|
@ -120,9 +120,15 @@ extern "C" void ogre_screenshot(char* filename)
|
||||||
extern "C" void ogre_rotateCamera(float x, float y)
|
extern "C" void ogre_rotateCamera(float x, float y)
|
||||||
{
|
{
|
||||||
mCamera->yaw(Degree(-x));
|
mCamera->yaw(Degree(-x));
|
||||||
|
|
||||||
|
Quaternion nopitch = mCamera->getOrientation();
|
||||||
|
|
||||||
mCamera->pitch(Degree(-y));
|
mCamera->pitch(Degree(-y));
|
||||||
|
|
||||||
//g_light->setDirection(mCamera->getDirection());
|
// Is the camera close to being upside down?
|
||||||
|
if(mCamera->getUp()[1] <= 0.1)
|
||||||
|
// If so, undo the last pitch
|
||||||
|
mCamera->setOrientation(nopitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current camera position
|
// Get current camera position
|
||||||
|
@ -155,7 +161,7 @@ extern "C" void ogre_moveCamera(float x, float y, float z)
|
||||||
// Transforms Morrowind coordinates to OGRE coordinates. The camera
|
// Transforms Morrowind coordinates to OGRE coordinates. The camera
|
||||||
// is not affected by the rotation of the root node, so we must
|
// is not affected by the rotation of the root node, so we must
|
||||||
// transform this manually.
|
// transform this manually.
|
||||||
mCamera->setPosition(Vector3(x,z,-y));
|
mCamera->setPosition(Vector3(x,z+90,-y));
|
||||||
|
|
||||||
//g_light->setPosition(mCamera->getPosition());
|
//g_light->setPosition(mCamera->getPosition());
|
||||||
}
|
}
|
||||||
|
@ -181,5 +187,8 @@ extern "C" void ogre_setCameraRotation(float r1, float r2, float r3)
|
||||||
// Move camera relative to its own axis set.
|
// Move camera relative to its own axis set.
|
||||||
extern "C" void ogre_moveCameraRel(float x, float y, float z)
|
extern "C" void ogre_moveCameraRel(float x, float y, float z)
|
||||||
{
|
{
|
||||||
mCamera->moveRelative(Vector3(x,y,z));
|
mCamera->moveRelative(Vector3(x,0,z));
|
||||||
|
|
||||||
|
// up/down movement is always done relative the world axis
|
||||||
|
mCamera->move(Vector3(0,y,0));
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,6 +182,8 @@ extern "C" void ogre_makeScene()
|
||||||
// Alter the camera aspect ratio to match the viewport
|
// Alter the camera aspect ratio to match the viewport
|
||||||
mCamera->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
|
mCamera->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
|
||||||
|
|
||||||
|
mCamera->setFOVy(Degree(55));
|
||||||
|
|
||||||
// Set default mipmap level (NB some APIs ignore this)
|
// Set default mipmap level (NB some APIs ignore this)
|
||||||
TextureManager::getSingleton().setDefaultNumMipmaps(5);
|
TextureManager::getSingleton().setDefaultNumMipmaps(5);
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ struct MeshLoader
|
||||||
base = ogre_getDetachedNode();
|
base = ogre_getDetachedNode();
|
||||||
|
|
||||||
// Recursively insert nodes (don't rotate the first node)
|
// Recursively insert nodes (don't rotate the first node)
|
||||||
insertNode(n, base, true);
|
insertNode(n, base, 0, true);
|
||||||
|
|
||||||
// Get the final shape, if any
|
// Get the final shape, if any
|
||||||
shape = bullet_getFinalShape();
|
shape = bullet_getFinalShape();
|
||||||
|
@ -92,10 +92,12 @@ struct MeshLoader
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void insertNode(Node data, NodePtr parent, bool noRot = false)
|
void insertNode(Node data, NodePtr parent,
|
||||||
|
int flags,
|
||||||
|
bool noRot = false)
|
||||||
{
|
{
|
||||||
// Skip hidden nodes for now.
|
// Add the flags to the previous node's flags
|
||||||
if(data.flags & 0x01) return;
|
flags = data.flags | flags;
|
||||||
|
|
||||||
// Create a scene node, move and rotate it into place. The name
|
// Create a scene node, move and rotate it into place. The name
|
||||||
// must be unique, however we might have to recognize some special
|
// must be unique, however we might have to recognize some special
|
||||||
|
@ -115,23 +117,29 @@ struct MeshLoader
|
||||||
NiNode n = cast(NiNode)data;
|
NiNode n = cast(NiNode)data;
|
||||||
if(n !is null)
|
if(n !is null)
|
||||||
// Handle the NiNode, and any children it might have
|
// Handle the NiNode, and any children it might have
|
||||||
handleNiNode(n, node);
|
handleNiNode(n, node, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
NiTriShape n = cast(NiTriShape)data;
|
NiTriShape n = cast(NiTriShape)data;
|
||||||
if(n !is null)
|
if(n !is null)
|
||||||
// Trishape, with a mesh
|
// Trishape, with a mesh
|
||||||
handleNiTriShape(n, node);
|
handleNiTriShape(n, node, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleNiNode(NiNode data, NodePtr node)
|
void handleNiNode(NiNode data, NodePtr node, int flags)
|
||||||
{
|
{
|
||||||
// Ignore sound activators and similar objects.
|
// Ignore sound activators and similar objects.
|
||||||
NiStringExtraData d = cast(NiStringExtraData) data.extra;
|
NiStringExtraData d = cast(NiStringExtraData) data.extra;
|
||||||
if(d !is null && d.string == "MRK")
|
if(d !is null)
|
||||||
return;
|
{
|
||||||
|
if(d.string == "MRK")
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(d.string == "NCO")
|
||||||
|
flags |= 0x800; // Temporary internal marker
|
||||||
|
}
|
||||||
|
|
||||||
// Handle any effects here
|
// Handle any effects here
|
||||||
|
|
||||||
|
@ -144,16 +152,31 @@ struct MeshLoader
|
||||||
|
|
||||||
// Loop through children
|
// Loop through children
|
||||||
foreach(Node n; data.children)
|
foreach(Node n; data.children)
|
||||||
insertNode(n, node);
|
insertNode(n, node, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleNiTriShape(NiTriShape shape, NodePtr node)
|
void handleNiTriShape(NiTriShape shape, NodePtr node, int flags)
|
||||||
{
|
{
|
||||||
char[] texture;
|
char[] texture;
|
||||||
char[] material;
|
char[] material;
|
||||||
char[] newName = UniqueName(baseName);
|
char[] newName = UniqueName(baseName);
|
||||||
NiMaterialProperty mp;
|
NiMaterialProperty mp;
|
||||||
|
|
||||||
|
bool hidden = (flags & 0x01) != 0; // Not displayed
|
||||||
|
bool collide = (flags & 0x02) != 0; // Use this mesh for collision
|
||||||
|
bool bbcollide = (flags & 0x04) != 0; // Use bounding box for
|
||||||
|
// collision
|
||||||
|
// Always use mesh collision for now
|
||||||
|
if(bbcollide) collide = true;
|
||||||
|
bbcollide = false;
|
||||||
|
|
||||||
|
// Things marked "NCO" should not collide with anything.
|
||||||
|
if(flags & 0x800)
|
||||||
|
collide = false;
|
||||||
|
|
||||||
|
// Skip the entire material phase for hidden nodes
|
||||||
|
if(hidden) goto nomaterial;
|
||||||
|
|
||||||
// Scan the property list for textures
|
// Scan the property list for textures
|
||||||
foreach(Property p; shape.properties)
|
foreach(Property p; shape.properties)
|
||||||
{
|
{
|
||||||
|
@ -227,6 +250,8 @@ struct MeshLoader
|
||||||
texturePtr);
|
texturePtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nomaterial:
|
||||||
|
|
||||||
with(shape.data)
|
with(shape.data)
|
||||||
{
|
{
|
||||||
//writefln("Number of vertices: ", vertices.length);
|
//writefln("Number of vertices: ", vertices.length);
|
||||||
|
@ -251,7 +276,9 @@ struct MeshLoader
|
||||||
maxY = -float.infinity,
|
maxY = -float.infinity,
|
||||||
maxZ = -float.infinity;
|
maxZ = -float.infinity;
|
||||||
|
|
||||||
// Calculate the bounding box. TODO: This is really a hack.
|
// Calculate the bounding box. TODO: This is really a
|
||||||
|
// hack. IIRC the bounding box supplied by the NIF could not
|
||||||
|
// be trusted, but I can't remember why :/
|
||||||
for( int i; i < vertices.length; i+=3 )
|
for( int i; i < vertices.length; i+=3 )
|
||||||
{
|
{
|
||||||
if( vertices[i] < minX ) minX = vertices[i];
|
if( vertices[i] < minX ) minX = vertices[i];
|
||||||
|
@ -269,20 +296,34 @@ struct MeshLoader
|
||||||
float[9] matrix;
|
float[9] matrix;
|
||||||
ogre_getWorldTransform(node, trans.ptr, matrix.ptr);
|
ogre_getWorldTransform(node, trans.ptr, matrix.ptr);
|
||||||
|
|
||||||
// Create a bullet collision shape from the trimesh, if there
|
// Next we must create the actual OGRE mesh and the collision
|
||||||
// are any triangles present. Pass along the world
|
// objects, based on the flags we have been given.
|
||||||
// transformation as well, since we must transform the trimesh
|
assert(!bbcollide);
|
||||||
// data manually.
|
/* // Bounding box collision currently disabled
|
||||||
if(facesPtr != null)
|
if(bbcollide)
|
||||||
bullet_createTriShape(triangles.length, facesPtr,
|
// Insert the bounding box into the collision system
|
||||||
vertices.length, vertices.ptr,
|
bullet_createBoxShape(minX, minY, minZ, maxX, maxY, maxZ,
|
||||||
trans.ptr, matrix.ptr);
|
trans.ptr, matrix.ptr);
|
||||||
|
|
||||||
// Create the ogre mesh, associate it with the node
|
// Create a bullet collision shape from the trimesh. Pass
|
||||||
ogre_createMesh(newName.ptr, vertices.length, vertices.ptr,
|
// along the world transformation as well, since we must
|
||||||
normalsPtr, colorsPtr, uvsPtr, triangles.length, facesPtr,
|
// transform the trimesh data manually.
|
||||||
radius, material.ptr, minX, minY, minZ, maxX, maxY, maxZ,
|
else*/if(collide)
|
||||||
node);
|
{
|
||||||
|
assert(facesPtr !is null,
|
||||||
|
"cannot create collision shape without a mesh");
|
||||||
|
bullet_createTriShape(triangles.length, facesPtr,
|
||||||
|
vertices.length, vertices.ptr,
|
||||||
|
trans.ptr, matrix.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the ogre mesh, associate it with the node. Skip for
|
||||||
|
// hidden nodes.
|
||||||
|
if(!hidden)
|
||||||
|
ogre_createMesh(newName.ptr, vertices.length, vertices.ptr,
|
||||||
|
normalsPtr, colorsPtr, uvsPtr, triangles.length,
|
||||||
|
facesPtr, radius, material.ptr, minX, minY, minZ,
|
||||||
|
maxX, maxY, maxZ, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue