mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 19:19:56 +00:00
First alpha release of REAL collision detection.
git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@48 ea6a568a-9f4f-0410-981a-c910a81bb256
This commit is contained in:
parent
5fad8ea459
commit
c094324ef2
23 changed files with 617 additions and 268 deletions
2
Makefile
2
Makefile
|
@ -28,7 +28,7 @@ ogre_cpp=ogre framelistener interface overlay bsaarchive
|
|||
avcodec_cpp=avcodec
|
||||
|
||||
# Bullet cpp files
|
||||
bullet_cpp=bullet
|
||||
bullet_cpp=bullet player
|
||||
|
||||
#### No modifications should be required below this line. ####
|
||||
|
||||
|
|
19
README.txt
19
README.txt
|
@ -49,11 +49,11 @@ On the near-future TODO list:
|
|||
|
||||
- full support for localized versions (with character recoding)
|
||||
- support for Mac
|
||||
- collision detection + walking & fall physics
|
||||
- collision detection + walk & fall physics
|
||||
- displaying creatures correcty, animation
|
||||
- rendering NPCs
|
||||
- rendering outdoor scenes (exterior cells)
|
||||
- choosing a GUI/HUD system that playes well with OGRE
|
||||
- choosing a GUI/HUD system that plays well with OGRE
|
||||
|
||||
|
||||
|
||||
|
@ -62,7 +62,7 @@ Installation
|
|||
============
|
||||
|
||||
Currently supported platforms are Windows, Linux and FreeBSD. Most
|
||||
testing has been on Windows XP and Ubuntu 8.04.
|
||||
testing is on Ubuntu 8.04 and Windows XP Professional (in that order).
|
||||
|
||||
For instructions, see one of the following:
|
||||
|
||||
|
@ -70,7 +70,9 @@ README-win32.txt - instructions for binary Windows release
|
|||
COMPILE-win32.txt - instructions for building source on Windows
|
||||
COMPILE-linux.tx - instructions for building source on Linux / Unix
|
||||
|
||||
Linux 64 bit is known NOT to work, because of compiler deficiencies.
|
||||
Linux 64 bit is known NOT to work, because of current compiler
|
||||
deficiencies. This will hopefully be sorted out at some point, but
|
||||
it's not a bug in the OpenMW code.
|
||||
|
||||
|
||||
|
||||
|
@ -115,6 +117,15 @@ Thanks goes out to:
|
|||
Changelog:
|
||||
==========
|
||||
|
||||
0.5 (WIP)
|
||||
|
||||
- working on collision detection with Bullet
|
||||
- working on fixing sound issues for windows (running out of sound
|
||||
resources, music playback doesn't good)
|
||||
- added build files for CMake (with CMakeD) and Code::Blocks (neither
|
||||
are tested yet)
|
||||
- various minor changes and updates
|
||||
|
||||
0.4 (2008 aug. 30) - latest release
|
||||
|
||||
- switched from Audiere to OpenAL (BIG thanks to Chris Robinson)
|
||||
|
|
|
@ -28,27 +28,46 @@ module bullet.bindings;
|
|||
* handles Bullet.
|
||||
*/
|
||||
|
||||
typedef void* BulletShape;
|
||||
|
||||
extern(C):
|
||||
|
||||
// Initialize the dynamic world. Returns non-zero if an error occurs.
|
||||
int cpp_initBullet();
|
||||
int bullet_init();
|
||||
|
||||
// Warp the player to a specific location.
|
||||
void cpp_movePlayer(float x, float y, float z);
|
||||
void bullet_movePlayer(float x, float y, float z);
|
||||
|
||||
// Request that the player moves in this direction
|
||||
void cpp_setPlayerDir(float x, float y, float z);
|
||||
void bullet_setPlayerDir(float x, float y, float z);
|
||||
|
||||
// Get the current player position, after physics and collision have
|
||||
// been applied.
|
||||
void cpp_getPlayerPos(float *x, float *y, float *z);
|
||||
void bullet_getPlayerPos(float *x, float *y, float *z);
|
||||
|
||||
// Insert a debug collision object
|
||||
void cpp_insertBox(float x, float y, float z);
|
||||
// Create a triangle shape. This is cumulative, all meshes created
|
||||
// with this function are added to the same shape. Since the various
|
||||
// parts of a mesh can be differently transformed and we are putting
|
||||
// them all in one shape, we must transform the vertices manually.
|
||||
void bullet_createTriShape(int numFaces,
|
||||
void *triArray,
|
||||
int numVerts,
|
||||
void *vertArray,
|
||||
float *trans,float *matrix);
|
||||
|
||||
// "Flushes" the meshes created with createTriShape, returning the
|
||||
// pointer to the final shape object.
|
||||
BulletShape bullet_getFinalShape();
|
||||
|
||||
// Insert a static mesh with the given translation, quaternion
|
||||
// rotation and scale. The quaternion is assumed to be in Ogre format,
|
||||
// ie. with the W first.
|
||||
void bullet_insertStatic(BulletShape shp, float *pos,
|
||||
float *quat, float scale);
|
||||
|
||||
// Move the physics simulation 'delta' seconds forward in time
|
||||
void cpp_timeStep(float delta);
|
||||
void bullet_timeStep(float delta);
|
||||
|
||||
// Deallocate objects
|
||||
void cpp_cleanupBullet();
|
||||
void bullet_cleanup();
|
||||
|
||||
|
|
|
@ -1,11 +1,34 @@
|
|||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.snaptoad.com/
|
||||
|
||||
This file (bullet.d) is part of the OpenMW package.
|
||||
|
||||
OpenMW is distributed as free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
version 3, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 3 along with this program. If not, see
|
||||
http://www.gnu.org/licenses/ .
|
||||
|
||||
*/
|
||||
|
||||
module bullet.bullet;
|
||||
|
||||
import bullet.bindings;
|
||||
|
||||
void initBullet()
|
||||
{
|
||||
if(cpp_initBullet())
|
||||
if(bullet_init())
|
||||
throw new Exception("Bullet setup failed");
|
||||
}
|
||||
|
||||
void cleanupBullet() { cpp_cleanupBullet(); }
|
||||
void cleanupBullet() { bullet_cleanup(); }
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.snaptoad.com/
|
||||
|
||||
This file (cpp_bullet.cpp) is part of the OpenMW package.
|
||||
|
||||
OpenMW is distributed as free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
version 3, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 3 along with this program. If not, see
|
||||
http://www.gnu.org/licenses/ .
|
||||
|
||||
*/
|
||||
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
|
||||
#include <iostream>
|
||||
|
@ -20,20 +43,24 @@ btConvexShape *g_playerShape;
|
|||
|
||||
// Player position. This is updated automatically by the physics
|
||||
// system based on g_walkDirection and collisions. It is read by D
|
||||
// code through cpp_getPlayerPos().
|
||||
// code through bullet_getPlayerPos().
|
||||
btVector3 g_playerPosition;
|
||||
|
||||
// Walking vector - defines direction and speed that the player
|
||||
// intends to move right now. This is updated from D code each frame
|
||||
// through cpp_setPlayerDir(), based on player input (and later, AI
|
||||
// through bullet_setPlayerDir(), based on player input (and later, AI
|
||||
// decisions.) The units of the vector are points per second.
|
||||
btVector3 g_walkDirection;
|
||||
|
||||
// The current trimesh shape being built. All new inserted meshes are
|
||||
// added into this, until bullet_getFinalShape() is called.
|
||||
btTriangleIndexVertexArray *g_currentMesh;
|
||||
|
||||
// These variables and the class below are used in player collision
|
||||
// detection. The callback is injected into the broadphase and keeps a
|
||||
// continuously updated list of what objects are colliding with the
|
||||
// player (in g_pairCache). This list is used in the function called
|
||||
// recoverFromPenetration() below.
|
||||
// recoverFromPenetration().
|
||||
btHashedOverlappingPairCache* g_pairCache;
|
||||
CustomOverlappingPairCallback *g_customPairCallback;
|
||||
|
||||
|
@ -77,7 +104,7 @@ public:
|
|||
*/
|
||||
};
|
||||
|
||||
extern "C" int32_t cpp_initBullet()
|
||||
extern "C" int32_t bullet_init()
|
||||
{
|
||||
// ------- SET UP THE WORLD -------
|
||||
|
||||
|
@ -89,9 +116,14 @@ extern "C" int32_t cpp_initBullet()
|
|||
|
||||
// TODO: Figure out what to do with this. We need the user callback
|
||||
// function used below (I think), but this is only offered by this
|
||||
// broadphase implementation (as far as I can see.)
|
||||
btVector3 worldMin(-100000,-100000,-100000);
|
||||
btVector3 worldMax(100000,100000,100000);
|
||||
// broadphase implementation (as far as I can see.) Maybe we can
|
||||
// scan through the cell first and find good values that covers all
|
||||
// the objects before we set up the dynamic world. Another option is
|
||||
// to create a custom broadphase designed for our purpose. (We
|
||||
// should probably use different ones for interior and exterior
|
||||
// cells in any case.)
|
||||
btVector3 worldMin(-40000,-40000,-40000);
|
||||
btVector3 worldMax(40000,40000,40000);
|
||||
g_broadphase = new btAxisSweep3(worldMin,worldMax);
|
||||
|
||||
g_dynamicsWorld =
|
||||
|
@ -107,18 +139,18 @@ extern "C" int32_t cpp_initBullet()
|
|||
|
||||
// Create the player collision shape.
|
||||
float width = 50;
|
||||
//float height = 50;
|
||||
/*
|
||||
// One possible shape is the convex hull around two spheres
|
||||
float height = 100;
|
||||
btVector3 spherePositions[2];
|
||||
btScalar sphereRadii[2];
|
||||
sphereRadii[0] = width;
|
||||
sphereRadii[1] = width;
|
||||
spherePositions[0] = btVector3 (0.0, height/2.0, 0.0);
|
||||
spherePositions[1] = btVector3 (0.0, -height/2.0, 0.0);
|
||||
m_shape = new btMultiSphereShape(btVector3(width/2.0, height/2.0, width/2.0),
|
||||
&spherePositions[0], &sphereRadii[0], 2);
|
||||
*/
|
||||
g_playerShape = new btMultiSphereShape(btVector3(width/2.0, height/2.0,
|
||||
width/2.0), &spherePositions[0], &sphereRadii[0], 2);
|
||||
//*/
|
||||
//g_playerShape = new btCylinderShape(btVector3(50, 50, 50));
|
||||
g_playerShape = new btSphereShape(width);
|
||||
|
||||
|
@ -146,13 +178,16 @@ extern "C" int32_t cpp_initBullet()
|
|||
//,btBroadphaseProxy::StaticFilter
|
||||
);
|
||||
|
||||
// Make sure this is zero at startup
|
||||
g_currentMesh = NULL;
|
||||
|
||||
// Success!
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Warp the player to a specific location. We do not bother setting
|
||||
// rotation, since it's completely irrelevant for collision detection.
|
||||
extern "C" void cpp_movePlayer(float x, float y, float z)
|
||||
extern "C" void bullet_movePlayer(float x, float y, float z)
|
||||
{
|
||||
btTransform tr;
|
||||
tr.setIdentity();
|
||||
|
@ -161,20 +196,120 @@ extern "C" void cpp_movePlayer(float x, float y, float z)
|
|||
}
|
||||
|
||||
// Request that the player moves in this direction
|
||||
extern "C" void cpp_setPlayerDir(float x, float y, float z)
|
||||
extern "C" void bullet_setPlayerDir(float x, float y, float z)
|
||||
{ g_walkDirection.setValue(x,y,z); }
|
||||
|
||||
// Get the current player position, after physics and collision have
|
||||
// been applied.
|
||||
extern "C" void cpp_getPlayerPos(float *x, float *y, float *z)
|
||||
extern "C" void bullet_getPlayerPos(float *x, float *y, float *z)
|
||||
{
|
||||
*x = g_playerPosition.getX();
|
||||
*y = g_playerPosition.getY();
|
||||
*z = g_playerPosition.getZ();
|
||||
}
|
||||
|
||||
unsigned char* copyBuffer(void *buf, int elemSize, int len)
|
||||
{
|
||||
int size = elemSize * len;
|
||||
void *res = malloc(size);
|
||||
memcpy(res, buf, size);
|
||||
|
||||
return (unsigned char*)res;
|
||||
}
|
||||
|
||||
// Create a triangle shape and insert it into the current index/vertex
|
||||
// array. If no array is active, create one.
|
||||
extern "C" void bullet_createTriShape(int32_t numFaces,
|
||||
void *triArray,
|
||||
int32_t numVerts,
|
||||
void *vertArray,
|
||||
float *trans,
|
||||
float *matrix)
|
||||
{
|
||||
// This struct holds the index and vertex buffers of a single
|
||||
// trimesh.
|
||||
btIndexedMesh im;
|
||||
|
||||
// Set up the triangles
|
||||
int numTriangles = numFaces / 3;
|
||||
im.m_numTriangles = numTriangles;
|
||||
im.m_triangleIndexStride = 6; // 3 indices * 2 bytes per short
|
||||
im.m_triangleIndexBase = copyBuffer(triArray, 6, numTriangles);
|
||||
|
||||
// Set up the vertices
|
||||
im.m_numVertices = numVerts;
|
||||
im.m_vertexStride = 12; // 4 bytes per float * 3 floats per vertex
|
||||
im.m_vertexBase = copyBuffer(vertArray, 12, numVerts);
|
||||
|
||||
// Transform all the vertex values according to 'trans' and 'matrix'
|
||||
float *vb = (float*) im.m_vertexBase;
|
||||
for(int i=0; i<numVerts; i++)
|
||||
{
|
||||
float x,y,z;
|
||||
|
||||
// Reinventing basic linear algebra for the win!
|
||||
x = matrix[0]*vb[0]+matrix[1]*vb[1]+matrix[2]*vb[2] + trans[0];
|
||||
y = matrix[3]*vb[0]+matrix[4]*vb[1]+matrix[5]*vb[2] + trans[1];
|
||||
z = matrix[6]*vb[0]+matrix[7]*vb[1]+matrix[8]*vb[2] + trans[2];
|
||||
*(vb++) = x;
|
||||
*(vb++) = y;
|
||||
*(vb++) = z;
|
||||
}
|
||||
|
||||
// If no mesh is currently active, create one
|
||||
if(g_currentMesh == NULL)
|
||||
g_currentMesh = new btTriangleIndexVertexArray;
|
||||
|
||||
// Add the mesh. Nif data stores triangle indices as shorts.
|
||||
g_currentMesh->addIndexedMesh(im, PHY_SHORT);
|
||||
}
|
||||
|
||||
// Get the shape built up so far, if any. This clears g_currentMesh,
|
||||
// so the next call to createTriShape will start a new shape.
|
||||
extern "C" btCollisionShape *bullet_getFinalShape()
|
||||
{
|
||||
// Return null if no meshes have been inserted
|
||||
if(g_currentMesh == NULL) return NULL;
|
||||
|
||||
// Create the shape from the completed mesh
|
||||
btBvhTriangleMeshShape *shape =
|
||||
new btBvhTriangleMeshShape(g_currentMesh, false);
|
||||
|
||||
g_currentMesh = NULL;
|
||||
return shape;
|
||||
}
|
||||
|
||||
// Insert a static mesh
|
||||
extern "C" void bullet_insertStatic(btCollisionShape *shape,
|
||||
float *pos,
|
||||
float *quat,
|
||||
float scale)
|
||||
{
|
||||
if(scale != 1.0)
|
||||
{
|
||||
cout << "WARNING: Cannot scale collision meshes yet (wanted "
|
||||
<< scale << ")\n";
|
||||
return;
|
||||
}
|
||||
|
||||
btTransform trafo;
|
||||
trafo.setIdentity();
|
||||
trafo.setOrigin(btVector3(pos[0], pos[1], pos[2]));
|
||||
|
||||
// Ogre uses WXYZ quaternions, Bullet uses XYZW.
|
||||
trafo.setRotation(btQuaternion(quat[1], quat[2], quat[3], quat[0]));
|
||||
|
||||
// Create and insert the collision object
|
||||
btCollisionObject *obj = new btCollisionObject();
|
||||
obj->setCollisionShape(shape);
|
||||
obj->setWorldTransform(trafo);
|
||||
g_dynamicsWorld->addCollisionObject(obj);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Insert a debug collision shape
|
||||
extern "C" void cpp_insertBox(float x, float y, float z)
|
||||
extern "C" void bullet_insertBox(float x, float y, float z)
|
||||
{
|
||||
btCollisionShape* groundShape =
|
||||
new btSphereShape(50);
|
||||
|
@ -184,21 +319,33 @@ extern "C" void cpp_insertBox(float x, float y, float z)
|
|||
btTransform groundTransform;
|
||||
groundTransform.setIdentity();
|
||||
groundTransform.setOrigin(btVector3(x,y,z));
|
||||
|
||||
// Use a simple collision object for static objects
|
||||
btCollisionObject *obj = new btCollisionObject();
|
||||
obj->setCollisionShape(groundShape);
|
||||
obj->setWorldTransform(groundTransform);
|
||||
|
||||
g_dynamicsWorld->addCollisionObject(obj);
|
||||
|
||||
// You can also use a rigid body with a motion state, but this is
|
||||
// overkill for statics.
|
||||
/*
|
||||
btDefaultMotionState* myMotionState =
|
||||
new btDefaultMotionState(groundTransform);
|
||||
|
||||
// Create a rigid body from the motion state. Give it zero mass and
|
||||
// inertia.
|
||||
// zero inertia.
|
||||
btRigidBody::btRigidBodyConstructionInfo
|
||||
rbInfo(0, myMotionState, groundShape, btVector3(0,0,0));
|
||||
btRigidBody* body = new btRigidBody(rbInfo);
|
||||
|
||||
// Add the body to the world
|
||||
g_dynamicsWorld->addRigidBody(body);
|
||||
}
|
||||
*/
|
||||
//}
|
||||
|
||||
// Move the physics simulation 'delta' seconds forward in time
|
||||
extern "C" void cpp_timeStep(float delta)
|
||||
extern "C" void bullet_timeStep(float delta)
|
||||
{
|
||||
// TODO: We might experiment with the number of time steps. Remember
|
||||
// that the function also returns the number of steps performed.
|
||||
|
@ -206,7 +353,7 @@ extern "C" void cpp_timeStep(float delta)
|
|||
}
|
||||
|
||||
// Cleanup in the reverse order of creation/initialization
|
||||
extern "C" void cpp_cleanupBullet()
|
||||
extern "C" void bullet_cleanup()
|
||||
{
|
||||
// Remove the rigidbodies from the dynamics world and delete them
|
||||
for (int i=g_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.snaptoad.com/
|
||||
|
||||
This file (cpp_player.cpp) is part of the OpenMW package.
|
||||
|
||||
OpenMW is distributed as free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
version 3, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 3 along with this program. If not, see
|
||||
http://www.gnu.org/licenses/ .
|
||||
|
||||
*/
|
||||
|
||||
// This file handles player-specific physics and collision detection
|
||||
|
||||
// TODO: Later we might handle various physics modes, eg. dynamic
|
||||
|
@ -10,6 +33,8 @@
|
|||
// player collision, these will be member variables.
|
||||
bool g_touchingContact;
|
||||
btVector3 g_touchingNormal;
|
||||
btScalar g_currentStepOffset;
|
||||
float g_stepHeight = 20;
|
||||
|
||||
// Returns the reflection direction of a ray going 'direction' hitting
|
||||
// a surface with normal 'normal'
|
||||
|
@ -49,11 +74,12 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/* Used to step up small steps and slopes. Not done.
|
||||
void KinematicCharacterController::stepUp (const btCollisionWorld* world)
|
||||
// Used to step up small steps and slopes.
|
||||
void stepUp()
|
||||
{
|
||||
// phase 1: up
|
||||
btVector3 targetPosition = g_playerPosition + btVector3 (btScalar(0.0), m_stepHeight, btScalar(0.0));
|
||||
btVector3 targetPosition = g_playerPosition +
|
||||
btVector3(0.0, 0.0, g_stepHeight);
|
||||
btTransform start, end;
|
||||
|
||||
start.setIdentity ();
|
||||
|
@ -63,23 +89,22 @@ void KinematicCharacterController::stepUp (const btCollisionWorld* world)
|
|||
start.setOrigin (g_playerPosition + btVector3(0.0, 0.1, 0.0));
|
||||
end.setOrigin (targetPosition);
|
||||
|
||||
ClosestNotMeConvexResultCallback callback (g_playerObject);
|
||||
world->convexSweepTest (g_playerShape, start, end, callback);
|
||||
ClosestNotMeConvexResultCallback callback;
|
||||
g_dynamicsWorld->convexSweepTest (g_playerShape, start, end, callback);
|
||||
|
||||
if (callback.hasHit())
|
||||
{
|
||||
// we moved up only a fraction of the step height
|
||||
m_currentStepOffset = m_stepHeight * callback.m_closestHitFraction;
|
||||
g_currentStepOffset = g_stepHeight * callback.m_closestHitFraction;
|
||||
g_playerPosition.setInterpolate3(g_playerPosition, targetPosition,
|
||||
callback.m_closestHitFraction);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_currentStepOffset = m_stepHeight;
|
||||
g_currentStepOffset = g_stepHeight;
|
||||
g_playerPosition = targetPosition;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void updateTargetPositionBasedOnCollision (const btVector3& hitNormal,
|
||||
btVector3 &targetPosition)
|
||||
|
@ -168,15 +193,15 @@ void stepForward(btVector3& walkMove)
|
|||
}
|
||||
}
|
||||
|
||||
/* Not done. Will handle gravity, falling, sliding, etc.
|
||||
void KinematicCharacterController::stepDown (const btCollisionWorld* g_dynamicsWorld, btScalar dt)
|
||||
void stepDown (btScalar dt)
|
||||
{
|
||||
btTransform start, end;
|
||||
|
||||
// phase 3: down
|
||||
btVector3 step_drop = btVector3(btScalar(0.0), m_currentStepOffset, btScalar(0.0));
|
||||
btVector3 gravity_drop = btVector3(btScalar(0.0), m_stepHeight, btScalar(0.0));
|
||||
targetPosition -= (step_drop + gravity_drop);
|
||||
btVector3 step_drop = btVector3(0,0,g_currentStepOffset);
|
||||
btVector3 gravity_drop = btVector3(0,0,g_stepHeight);
|
||||
|
||||
btVector3 targetPosition = g_playerPosition - step_drop - gravity_drop;
|
||||
|
||||
start.setIdentity ();
|
||||
end.setIdentity ();
|
||||
|
@ -184,20 +209,17 @@ void KinematicCharacterController::stepDown (const btCollisionWorld* g_dynamicsW
|
|||
start.setOrigin (g_playerPosition);
|
||||
end.setOrigin (targetPosition);
|
||||
|
||||
ClosestNotMeConvexResultCallback callback (g_playerObject);
|
||||
ClosestNotMeConvexResultCallback callback;
|
||||
g_dynamicsWorld->convexSweepTest(g_playerShape, start, end, callback);
|
||||
|
||||
if (callback.hasHit())
|
||||
{
|
||||
// we dropped a fraction of the height -> hit floor
|
||||
g_playerPosition.setInterpolate3 (g_playerPosition, targetPosition, callback.m_closestHitFraction);
|
||||
} else {
|
||||
g_playerPosition.setInterpolate3(g_playerPosition, targetPosition,
|
||||
callback.m_closestHitFraction);
|
||||
else
|
||||
// we dropped the full height
|
||||
|
||||
g_playerPosition = targetPosition;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Check if the player currently collides with anything, and adjust
|
||||
// its position accordingly. Returns true if collisions were found.
|
||||
|
@ -292,9 +314,9 @@ void playerStepCallback(btDynamicsWorld* dynamicsWorld, btScalar timeStep)
|
|||
|
||||
btVector3 walkStep = g_walkDirection * timeStep;
|
||||
|
||||
//stepUp();
|
||||
stepUp();
|
||||
stepForward(walkStep);
|
||||
//stepDown(dt);
|
||||
stepDown(timeStep);
|
||||
|
||||
// Move the player (but keep rotation)
|
||||
xform = g_playerObject->getWorldTransform ();
|
||||
|
|
|
@ -35,6 +35,8 @@ import util.random;
|
|||
|
||||
import bsa.bsafile;
|
||||
|
||||
import bullet.bindings;
|
||||
|
||||
import core.memory;
|
||||
import core.config;
|
||||
|
||||
|
@ -361,7 +363,7 @@ struct ResourceManager
|
|||
|
||||
// Load and insert nif
|
||||
// TODO: Might add BSA name to the handle name, for clarity
|
||||
mi.node = meshLoader.loadMesh(mi.name);
|
||||
meshLoader.loadMesh(mi.name, mi.node, mi.shape);
|
||||
|
||||
// TODO: We could clear the BSA memory mapping here to free some
|
||||
// mem
|
||||
|
@ -409,6 +411,9 @@ struct MeshResource
|
|||
|
||||
public:
|
||||
|
||||
// Bullet collision shape. Can be null.
|
||||
BulletShape shape;
|
||||
|
||||
NodePtr getNode()
|
||||
in
|
||||
{
|
||||
|
|
|
@ -94,7 +94,7 @@ void toggleBattle()
|
|||
|
||||
void toggleFullscreen()
|
||||
{
|
||||
cpp_toggleFullscreen();
|
||||
ogre_toggleFullscreen();
|
||||
}
|
||||
|
||||
const float volDiff = 0.05;
|
||||
|
@ -126,7 +126,7 @@ void mainVolume(bool increase)
|
|||
void takeScreenShot()
|
||||
{
|
||||
char[] file = format("screenshot_%06d.png", config.screenShotNum++);
|
||||
cpp_screenshot(toStringz(file));
|
||||
ogre_screenshot(toStringz(file));
|
||||
writefln("Wrote '%s'", file);
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ extern(C) void d_handleMouseMove(MouseState *state)
|
|||
state.X.abs, state.Y.abs, state.Z.abs,
|
||||
state.X.rel, state.Y.rel, state.Z.rel);
|
||||
|
||||
cpp_rotateCamera( state.X.rel * effMX,
|
||||
ogre_rotateCamera( state.X.rel * effMX,
|
||||
state.Y.rel * effMY );
|
||||
}
|
||||
|
||||
|
@ -221,7 +221,7 @@ extern(C) void d_handleKey(KC keycode, dchar text = 0)
|
|||
case Keys.Mute: toggleMute(); break;
|
||||
case Keys.Fullscreen: toggleFullscreen(); break;
|
||||
|
||||
case Keys.Debug: cpp_debug(0); break;
|
||||
case Keys.Debug: ogre_debug(0); break;
|
||||
case Keys.ScreenShot: takeScreenShot(); break;
|
||||
case Keys.Pause: togglePause(); break;
|
||||
case Keys.Exit: exitProgram(); break;
|
||||
|
@ -247,16 +247,10 @@ void initializeInput()
|
|||
// at all, and should be moved.
|
||||
with(playerData.position)
|
||||
{
|
||||
// TODO: Think about renaming these functions to ogre_moveCamera
|
||||
// and bullet_movePlayer etc.
|
||||
cpp_moveCamera(position[0], position[1], position[2]);
|
||||
cpp_setCameraRotation(rotation[0], rotation[1], rotation[2]);
|
||||
ogre_moveCamera(position[0], position[1], position[2]);
|
||||
ogre_setCameraRotation(rotation[0], rotation[1], rotation[2]);
|
||||
|
||||
cpp_movePlayer(position[0], position[1], position[2]);
|
||||
|
||||
// Insert a collision shape close to the player
|
||||
cpp_insertBox(position[0], position[1]+500, position[2]);
|
||||
cpp_drawBox(position[0], position[1]+500, position[2]);
|
||||
bullet_movePlayer(position[0], position[1], position[2]);
|
||||
}
|
||||
|
||||
// TODO/FIXME: This should have been in config, but DMD's module
|
||||
|
@ -269,14 +263,14 @@ void initializeInput()
|
|||
float tmpTime = 0;
|
||||
int cnt;
|
||||
|
||||
extern(C) int cpp_isPressed(int keysym);
|
||||
extern(C) int ois_isPressed(int keysym);
|
||||
|
||||
// Check if a key is currently down
|
||||
bool isPressed(Keys key)
|
||||
{
|
||||
KeyBind *b = &keyBindings.bindings[key];
|
||||
foreach(i; b.syms)
|
||||
if(i != 0 && cpp_isPressed(i)) return true;
|
||||
if(i != 0 && ois_isPressed(i)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -321,16 +315,16 @@ extern(C) int d_frameStarted(float time)
|
|||
// This isn't very elegant, but it's simple and it works.
|
||||
|
||||
// Get the current coordinates
|
||||
cpp_getCameraPos(&ox, &oy, &oz);
|
||||
ogre_getCameraPos(&ox, &oy, &oz);
|
||||
|
||||
// Move camera using relative coordinates. TODO: We won't really
|
||||
// need to move the camera here (since it's moved below anyway), we
|
||||
// only want the transformation from camera space to world
|
||||
// space. This can likely be done more efficiently.
|
||||
cpp_moveCameraRel(moveX, moveY, moveZ);
|
||||
ogre_moveCameraRel(moveX, moveY, moveZ);
|
||||
|
||||
// Get the result
|
||||
cpp_getCameraPos(&x, &y, &z);
|
||||
ogre_getCameraPos(&x, &y, &z);
|
||||
|
||||
// The result is the real movement direction, in world coordinates
|
||||
moveX = x-ox;
|
||||
|
@ -338,14 +332,14 @@ extern(C) int d_frameStarted(float time)
|
|||
moveZ = z-oz;
|
||||
|
||||
// Tell Bullet that this is where we want to go
|
||||
cpp_setPlayerDir(moveX, moveY, moveZ);
|
||||
bullet_setPlayerDir(moveX, moveY, moveZ);
|
||||
|
||||
// Perform a Bullet time step
|
||||
cpp_timeStep(time);
|
||||
bullet_timeStep(time);
|
||||
|
||||
// Get the final (actual) player position and update the camera
|
||||
cpp_getPlayerPos(&x, &y, &z);
|
||||
cpp_moveCamera(x,y,z);
|
||||
bullet_getPlayerPos(&x, &y, &z);
|
||||
ogre_moveCamera(x,y,z);
|
||||
|
||||
sndCumTime += time;
|
||||
if(sndCumTime > sndRefresh)
|
||||
|
@ -353,7 +347,7 @@ extern(C) int d_frameStarted(float time)
|
|||
float fx, fy, fz;
|
||||
float ux, uy, uz;
|
||||
|
||||
cpp_getCameraOrientation(&fx, &fy, &fz, &ux, &uy, &uz);
|
||||
ogre_getCameraOrientation(&fx, &fy, &fz, &ux, &uy, &uz);
|
||||
|
||||
soundScene.update(x,y,z,fx,fy,fz,ux,uy,uz);
|
||||
sndCumTime -= sndRefresh;
|
||||
|
|
|
@ -49,49 +49,58 @@ extern(C):
|
|||
|
||||
// Do engine configuration. Returns 0 if we should continue, 1 if
|
||||
// not.
|
||||
int cpp_configure(int showConfig, // Do we show the config dialogue?
|
||||
int ogre_configure(int showConfig, // Do we show the config dialogue?
|
||||
char *plugincfg // Name of 'plugin.cfg' file
|
||||
);
|
||||
|
||||
// Sets up the window
|
||||
void cpp_initWindow();
|
||||
void ogre_initWindow();
|
||||
|
||||
// Set up an empty scene.
|
||||
void cpp_makeScene();
|
||||
void ogre_makeScene();
|
||||
|
||||
// Set the ambient light and "sunlight"
|
||||
void cpp_setAmbient(float r, float g, float b,
|
||||
void ogre_setAmbient(float r, float g, float b,
|
||||
float rs, float gs, float bs);
|
||||
|
||||
// Set fog color and view distance
|
||||
void cpp_setFog(float rf, float gf, float bf,
|
||||
void ogre_setFog(float rf, float gf, float bf,
|
||||
float flow, float fhigh);
|
||||
|
||||
// Create a simple sky dome
|
||||
int cpp_makeSky();
|
||||
int ogre_makeSky();
|
||||
|
||||
// Enter main rendering loop
|
||||
void cpp_startRendering();
|
||||
void ogre_startRendering();
|
||||
|
||||
// Cleans up after ogre
|
||||
void cpp_cleanup();
|
||||
void ogre_cleanup();
|
||||
|
||||
// Gets a child SceneNode from the root node, then detatches it to
|
||||
// hide it from view. Used for creating the "template" node associated
|
||||
// with a NIF mesh.
|
||||
NodePtr cpp_getDetachedNode();
|
||||
NodePtr ogre_getDetachedNode();
|
||||
|
||||
// Convert a Morrowind rotation (3 floats) to a quaternion (4 floats)
|
||||
void ogre_mwToQuaternion(float *mw, float *quat);
|
||||
|
||||
// Create a copy of the given scene node, with the given coordinates
|
||||
// and rotation.
|
||||
NodePtr cpp_insertNode(NodePtr base, char* name,
|
||||
Placement *pos, float scale);
|
||||
// and rotation (as a quaternion.)
|
||||
NodePtr ogre_insertNode(NodePtr base, char* name,
|
||||
float *pos, float *quat, float scale);
|
||||
|
||||
// Get the world transformation of a node, returned as a translation
|
||||
// and a matrix. The matrix includes both rotation and scaling. The
|
||||
// buffers given must be large enough to store the result (3 and 9
|
||||
// floats respectively.)
|
||||
void ogre_getWorldTransform(NodePtr node, float *trans, float *matrix);
|
||||
|
||||
// Create a (very crappy looking) plane to simulate the water level
|
||||
void cpp_createWater(float level);
|
||||
void ogre_createWater(float level);
|
||||
|
||||
// Creates a scene node as a child of 'parent', then translates and
|
||||
// rotates it according to the data in 'trafo'.
|
||||
NodePtr cpp_createNode(
|
||||
NodePtr ogre_createNode(
|
||||
char *name, // Name to give the node
|
||||
Transformation *trafo, // Transformation
|
||||
NodePtr parent, // Parent node
|
||||
|
@ -99,12 +108,12 @@ NodePtr cpp_createNode(
|
|||
|
||||
// Create a light with the given diffuse color. Attach it to SceneNode
|
||||
// 'parent'.
|
||||
NodePtr cpp_attachLight(char* name, NodePtr parent,
|
||||
NodePtr ogre_attachLight(char* name, NodePtr parent,
|
||||
float r, float g, float b,
|
||||
float radius);
|
||||
|
||||
// Create the specified material
|
||||
void cpp_createMaterial(char *name, // Name to give resource
|
||||
void ogre_createMaterial(char *name, // Name to give resource
|
||||
float *ambient, // Ambient RBG value
|
||||
float *diffuse,
|
||||
float *specular,
|
||||
|
@ -115,7 +124,7 @@ void cpp_createMaterial(char *name, // Name to give resource
|
|||
|
||||
// Creates a mesh and gives it a bounding box. Also creates an entity
|
||||
// and attached it to the given SceneNode 'owner'.
|
||||
void cpp_createMesh(
|
||||
void ogre_createMesh(
|
||||
char* name, // Name of the mesh
|
||||
int numVerts, // Number of vertices
|
||||
float* vertices, // Vertex list
|
||||
|
@ -135,21 +144,18 @@ void cpp_createMesh(
|
|||
);
|
||||
|
||||
// Toggle fullscreen mode
|
||||
void cpp_toggleFullscreen();
|
||||
void ogre_toggleFullscreen();
|
||||
|
||||
// Save a screen shot to the given file name
|
||||
void cpp_screenshot(char *filename);
|
||||
void ogre_screenshot(char *filename);
|
||||
|
||||
// Camera control and information
|
||||
void cpp_rotateCamera(float x, float y);
|
||||
void cpp_moveCamera(float x, float y, float z);
|
||||
void cpp_setCameraRotation(float r1, float r2, float r3);
|
||||
void cpp_getCameraPos(float *x, float *y, float *z);
|
||||
void cpp_getCameraOrientation(float *fx, float *fy, float *fz, float *ux, float *uy, float *uz);
|
||||
void cpp_moveCameraRel(float x, float y, float z);
|
||||
void ogre_rotateCamera(float x, float y);
|
||||
void ogre_moveCamera(float x, float y, float z);
|
||||
void ogre_setCameraRotation(float r1, float r2, float r3);
|
||||
void ogre_getCameraPos(float *x, float *y, float *z);
|
||||
void ogre_getCameraOrientation(float *fx, float *fy, float *fz, float *ux, float *uy, float *uz);
|
||||
void ogre_moveCameraRel(float x, float y, float z);
|
||||
|
||||
// Do some debug action. Check the menu for today's specials!
|
||||
void cpp_debug(int i);
|
||||
|
||||
// Insert a 100x100x100 axis-aligned cube at x,y,z
|
||||
void cpp_drawBox(float x, float y, float z);
|
||||
void ogre_debug(int i);
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
// This file inserts an archive manager for .bsa files into the ogre
|
||||
// resource loading system. It uses callbacks to D to interact with
|
||||
// the d-based bsa handling code. The D bindings are in
|
||||
// the D-based bsa handling code. The D bindings are in
|
||||
// core/resource.d.
|
||||
|
||||
// Callbacks to D code
|
||||
|
@ -49,17 +49,19 @@ public:
|
|||
bool isCaseSensitive(void) const { return false; }
|
||||
|
||||
// The archives are already loaded in D code, and they are never
|
||||
// unloaded.
|
||||
// unloaded. Just ignore these.
|
||||
void load() {}
|
||||
void unload() {}
|
||||
|
||||
// Open a file in the archive. We delegate the function to D-code.
|
||||
DataStreamPtr open(const String& filename) const
|
||||
{
|
||||
//std::cout << "open(" << filename << ")\n";
|
||||
void *ptr;
|
||||
uint32_t size;
|
||||
|
||||
// Open the file
|
||||
// Open the file. The BSA archives are memory mapped, D code
|
||||
// returns a pointer and a file size.
|
||||
d_bsaOpenFile(filename.c_str(), &ptr, &size);
|
||||
|
||||
return DataStreamPtr(new MemoryDataStream(ptr, size));
|
||||
|
@ -93,7 +95,7 @@ public:
|
|||
}
|
||||
|
||||
// Gets called once for each of the ogre formats, *.program,
|
||||
// *.material etc. We can ignore that.
|
||||
// *.material etc. We can ignore this.
|
||||
FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true,
|
||||
bool dirs = false)
|
||||
{
|
||||
|
|
|
@ -101,13 +101,13 @@ InputListener mInput;
|
|||
|
||||
// Functions called from D during event handling
|
||||
|
||||
extern "C" int32_t cpp_isPressed(int32_t keysym)
|
||||
extern "C" int32_t ois_isPressed(int32_t keysym)
|
||||
{
|
||||
return mKeyboard->isKeyDown((OIS::KeyCode)keysym);
|
||||
}
|
||||
|
||||
// Dump screen contents to file
|
||||
extern "C" void cpp_screenshot(char* filename)
|
||||
extern "C" void ogre_screenshot(char* filename)
|
||||
{
|
||||
mWindow->writeContentsToFile(filename);
|
||||
|
||||
|
@ -117,14 +117,14 @@ extern "C" void cpp_screenshot(char* filename)
|
|||
}
|
||||
|
||||
// Rotate camera as result of mouse movement
|
||||
extern "C" void cpp_rotateCamera(float x, float y)
|
||||
extern "C" void ogre_rotateCamera(float x, float y)
|
||||
{
|
||||
mCamera->yaw(Degree(-x));
|
||||
mCamera->pitch(Degree(-y));
|
||||
}
|
||||
|
||||
// Get current camera position
|
||||
extern "C" void cpp_getCameraPos(float *x, float *y, float *z)
|
||||
extern "C" void ogre_getCameraPos(float *x, float *y, float *z)
|
||||
{
|
||||
Vector3 pos = mCamera->getPosition();
|
||||
*x = pos[0];
|
||||
|
@ -134,7 +134,7 @@ extern "C" void cpp_getCameraPos(float *x, float *y, float *z)
|
|||
|
||||
// Get current camera orientation, in the form of 'front' and 'up'
|
||||
// vectors.
|
||||
extern "C" void cpp_getCameraOrientation(float *fx, float *fy, float *fz,
|
||||
extern "C" void ogre_getCameraOrientation(float *fx, float *fy, float *fz,
|
||||
float *ux, float *uy, float *uz)
|
||||
{
|
||||
Vector3 front = mCamera->getDirection();
|
||||
|
@ -148,7 +148,7 @@ extern "C" void cpp_getCameraOrientation(float *fx, float *fy, float *fz,
|
|||
}
|
||||
|
||||
// Move camera
|
||||
extern "C" void cpp_moveCamera(float x, float y, float z)
|
||||
extern "C" void ogre_moveCamera(float x, float y, float z)
|
||||
{
|
||||
// Transforms Morrowind coordinates to OGRE coordinates. The camera
|
||||
// is not affected by the rotation of the root node, so we must
|
||||
|
@ -157,7 +157,7 @@ extern "C" void cpp_moveCamera(float x, float y, float z)
|
|||
}
|
||||
|
||||
// Rotate camera using Morrowind rotation specifiers
|
||||
extern "C" void cpp_setCameraRotation(float r1, float r2, float r3)
|
||||
extern "C" void ogre_setCameraRotation(float r1, float r2, float r3)
|
||||
{
|
||||
// TODO: This translation is probably not correct, but for now I
|
||||
// have no reference point. Fix it later when we teleport from one
|
||||
|
@ -175,7 +175,7 @@ extern "C" void cpp_setCameraRotation(float r1, float r2, float r3)
|
|||
}
|
||||
|
||||
// Move camera relative to its own axis set.
|
||||
extern "C" void cpp_moveCameraRel(float x, float y, float z)
|
||||
extern "C" void ogre_moveCameraRel(float x, float y, float z)
|
||||
{
|
||||
mCamera->moveRelative(Vector3(x,y,z));
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
// E X P O R T E D F U N C T I O N S
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
extern "C" void cpp_cleanup()
|
||||
extern "C" void ogre_cleanup()
|
||||
{
|
||||
// Kill the input systems. This will reset input options such as key
|
||||
// repetition.
|
||||
|
@ -41,7 +41,7 @@ extern "C" void cpp_cleanup()
|
|||
}
|
||||
}
|
||||
|
||||
extern "C" int32_t cpp_configure(
|
||||
extern "C" int32_t ogre_configure(
|
||||
int32_t showConfig, // Do we show the config dialogue?
|
||||
char *plugincfg // Name of 'plugin.cfg' file
|
||||
)
|
||||
|
@ -93,9 +93,9 @@ extern "C" int32_t cpp_configure(
|
|||
}
|
||||
|
||||
// Initialize window. This will create and show the actual window.
|
||||
extern "C" void cpp_initWindow()
|
||||
extern "C" void ogre_initWindow()
|
||||
{
|
||||
std::cout << "cpp_initWindow()\n";
|
||||
std::cout << "ogre_initWindow()\n";
|
||||
|
||||
// Initialize OGRE.
|
||||
mWindow = mRoot->initialise(true);
|
||||
|
@ -160,11 +160,11 @@ extern "C" void cpp_initWindow()
|
|||
mKeyboard -> setEventCallback( &mInput );
|
||||
mMouse -> setEventCallback( &mInput );
|
||||
|
||||
std::cout << "cpp_initWindow finished\n";
|
||||
std::cout << "ogre_initWindow finished\n";
|
||||
}
|
||||
|
||||
// Make a scene, set the given ambient light
|
||||
extern "C" void cpp_makeScene()
|
||||
extern "C" void ogre_makeScene()
|
||||
{
|
||||
// Get the SceneManager, in this case a generic one
|
||||
mSceneMgr = mRoot->createSceneManager(ST_GENERIC);
|
||||
|
@ -202,12 +202,12 @@ extern "C" void cpp_makeScene()
|
|||
|
||||
// Create a sky dome. Currently disabled since we aren't including the
|
||||
// Ogre example data (which has the sky material.)
|
||||
extern "C" void cpp_makeSky()
|
||||
extern "C" void ogre_makeSky()
|
||||
{
|
||||
//mSceneMgr->setSkyDome( true, "Examples/CloudySky", 5, 8 );
|
||||
}
|
||||
|
||||
extern "C" Light* cpp_attachLight(char *name, SceneNode* base,
|
||||
extern "C" Light* ogre_attachLight(char *name, SceneNode* base,
|
||||
float r, float g, float b,
|
||||
float radius)
|
||||
{
|
||||
|
@ -225,12 +225,12 @@ extern "C" Light* cpp_attachLight(char *name, SceneNode* base,
|
|||
}
|
||||
|
||||
// Toggle between fullscreen and windowed mode.
|
||||
extern "C" void cpp_toggleFullscreen()
|
||||
extern "C" void ogre_toggleFullscreen()
|
||||
{
|
||||
std::cout << "Not implemented yet\n";
|
||||
}
|
||||
|
||||
extern "C" void cpp_setAmbient(float r, float g, float b, // Ambient light
|
||||
extern "C" void ogre_setAmbient(float r, float g, float b, // Ambient light
|
||||
float rs, float gs, float bs) // "Sunlight"
|
||||
{
|
||||
ColourValue c = ColourValue(r, g, b);
|
||||
|
@ -244,7 +244,7 @@ extern "C" void cpp_setAmbient(float r, float g, float b, // Ambient light
|
|||
l->setDirection(0,-1,0);
|
||||
}
|
||||
|
||||
extern "C" void cpp_setFog(float rf, float gf, float bf, // Fog color
|
||||
extern "C" void ogre_setFog(float rf, float gf, float bf, // Fog color
|
||||
float flow, float fhigh) // Fog distance
|
||||
{
|
||||
ColourValue fogColor( rf, gf, bf );
|
||||
|
@ -257,7 +257,7 @@ extern "C" void cpp_setFog(float rf, float gf, float bf, // Fog color
|
|||
//vp->setBackgroundColour(fogColor);
|
||||
}
|
||||
|
||||
extern "C" void cpp_startRendering()
|
||||
extern "C" void ogre_startRendering()
|
||||
{
|
||||
mRoot->startRendering();
|
||||
}
|
||||
|
@ -292,43 +292,81 @@ void cloneNode(SceneNode *from, SceneNode *to, char* name)
|
|||
}
|
||||
}
|
||||
|
||||
// Convert a Morrowind rotation (3 floats) to a quaternion (4 floats)
|
||||
extern "C" void ogre_mwToQuaternion(float *mw, float *quat)
|
||||
{
|
||||
// Rotate around X axis
|
||||
Quaternion xr(Radian(-mw[0]), Vector3::UNIT_X);
|
||||
|
||||
// Rotate around Y axis
|
||||
Quaternion yr(Radian(-mw[1]), Vector3::UNIT_Y);
|
||||
|
||||
// Rotate around Z axis
|
||||
Quaternion zr(Radian(-mw[2]), Vector3::UNIT_Z);
|
||||
|
||||
// Rotates first around z, then y, then x
|
||||
Quaternion res = xr*yr*zr;
|
||||
|
||||
// Copy result back to caller
|
||||
for(int i=0; i<4; i++)
|
||||
quat[i] = res[i];
|
||||
}
|
||||
|
||||
// Supposed to insert a copy of the node, for now it just inserts the
|
||||
// actual node.
|
||||
extern "C" SceneNode *cpp_insertNode(SceneNode *base, char* name,
|
||||
float *pos, float scale)
|
||||
extern "C" SceneNode *ogre_insertNode(SceneNode *base, char* name,
|
||||
float *pos, float *quat,
|
||||
float scale)
|
||||
{
|
||||
//std::cout << "cpp_insertNode(" << name << ")\n";
|
||||
//std::cout << "ogre_insertNode(" << name << ")\n";
|
||||
SceneNode *node = root->createChildSceneNode(name);
|
||||
|
||||
// Make a copy of the node
|
||||
cloneNode(base, node, name);
|
||||
|
||||
// pos points to a Placement struct, which has the format
|
||||
// float x, y, z; // position
|
||||
// float r1, r2, r3; // rotation
|
||||
|
||||
// Apply transformations
|
||||
node->setPosition(pos[0], pos[1], pos[2]);
|
||||
|
||||
// Rotate around X axis
|
||||
Quaternion xr(Radian(-pos[3]), Vector3::UNIT_X);
|
||||
|
||||
// Rotate around Y axis
|
||||
Quaternion yr(Radian(-pos[4]), Vector3::UNIT_Y);
|
||||
|
||||
// Rotate around Z axis
|
||||
Quaternion zr(Radian(-pos[5]), Vector3::UNIT_Z);
|
||||
|
||||
// Rotates first around z, then y, then x
|
||||
node->setOrientation(xr*yr*zr);
|
||||
node->setOrientation(quat[0], quat[1], quat[2], quat[3]);
|
||||
|
||||
node->setScale(scale, scale, scale);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// Get the world transformation of a node (the total transformation of
|
||||
// this node and all parent nodes). Return it as a translation
|
||||
// (3-vector) and a rotation / scaling part (3x3 matrix)
|
||||
extern "C" void ogre_getWorldTransform(SceneNode *node,
|
||||
float *trans, // Storage for translation
|
||||
float *matrix)// For 3x3 matrix
|
||||
{
|
||||
// Get the world transformation first
|
||||
Matrix4 trafo;
|
||||
node->getWorldTransforms(&trafo);
|
||||
|
||||
// Extract the translation part and pass it to the caller
|
||||
Vector3 tr = trafo.getTrans();
|
||||
trans[0] = tr[0];
|
||||
trans[1] = tr[1];
|
||||
trans[2] = tr[2];
|
||||
|
||||
// Next extract the matrix
|
||||
Matrix3 mat;
|
||||
trafo.extract3x3Matrix(mat);
|
||||
matrix[0] = mat[0][0];
|
||||
matrix[1] = mat[0][1];
|
||||
matrix[2] = mat[0][2];
|
||||
matrix[3] = mat[1][0];
|
||||
matrix[4] = mat[1][1];
|
||||
matrix[5] = mat[1][2];
|
||||
matrix[6] = mat[2][0];
|
||||
matrix[7] = mat[2][1];
|
||||
matrix[8] = mat[2][2];
|
||||
}
|
||||
|
||||
// Create the water plane. It doesn't really resemble "water" yet
|
||||
// though.
|
||||
extern "C" void cpp_createWater(float level)
|
||||
extern "C" void ogre_createWater(float level)
|
||||
{
|
||||
// Create a plane aligned with the xy-plane.
|
||||
MeshManager::getSingleton().createPlane("water",
|
||||
|
@ -362,7 +400,7 @@ public:
|
|||
String LASTNAME;
|
||||
|
||||
// Load the contents of a mesh
|
||||
extern "C" void cpp_createMesh(
|
||||
extern "C" void ogre_createMesh(
|
||||
char* name, // Name of the mesh
|
||||
int32_t numVerts, // Number of vertices
|
||||
float* vertices, // Vertex list
|
||||
|
@ -522,7 +560,7 @@ extern "C" void cpp_createMesh(
|
|||
msh->_setBoundingSphereRadius(radius);
|
||||
}
|
||||
|
||||
extern "C" void cpp_createMaterial(char *name, // Name to give
|
||||
extern "C" void ogre_createMaterial(char *name, // Name to give
|
||||
// resource
|
||||
|
||||
float *ambient, // Ambient RBG
|
||||
|
@ -568,20 +606,20 @@ extern "C" void cpp_createMaterial(char *name, // Name to give
|
|||
LASTNAME = material->getName();
|
||||
}
|
||||
|
||||
extern "C" SceneNode *cpp_getDetachedNode()
|
||||
extern "C" SceneNode *ogre_getDetachedNode()
|
||||
{
|
||||
SceneNode *node = root->createChildSceneNode();
|
||||
root->removeChild(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
extern "C" SceneNode* cpp_createNode(
|
||||
extern "C" SceneNode* ogre_createNode(
|
||||
char *name,
|
||||
float *trafo,
|
||||
SceneNode *parent,
|
||||
int32_t noRot)
|
||||
{
|
||||
//std::cout << "cpp_createNode(" << name << ")";
|
||||
//std::cout << "ogre_createNode(" << name << ")";
|
||||
SceneNode *node = parent->createChildSceneNode(name);
|
||||
//std::cout << " ... done\n";
|
||||
|
||||
|
@ -613,7 +651,7 @@ extern "C" SceneNode* cpp_createNode(
|
|||
/* Code currently not in use
|
||||
|
||||
// We need this later for animated meshes. Boy will this be a mess.
|
||||
extern "C" void* cpp_setupSkeleton(char* name)
|
||||
extern "C" void* ogre_setupSkeleton(char* name)
|
||||
{
|
||||
SkeletonPtr skel = SkeletonManager::getSingleton().create(
|
||||
name, "Closet", true);
|
||||
|
@ -627,7 +665,7 @@ extern "C" void* cpp_setupSkeleton(char* name)
|
|||
}
|
||||
|
||||
// Use this later when loading textures directly from NIF files
|
||||
extern "C" void cpp_createTexture(char* name, uint32_t width, uint32_t height)
|
||||
extern "C" void ogre_createTexture(char* name, uint32_t width, uint32_t height)
|
||||
{
|
||||
TexturePtr texture = TextureManager::getSingleton().createManual(
|
||||
name, // name
|
||||
|
@ -671,7 +709,7 @@ extern "C" void cpp_createTexture(char* name, uint32_t width, uint32_t height)
|
|||
material->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
||||
}
|
||||
|
||||
extern "C" void *cpp_insertBone(char* name, void* rootBone, int32_t index)
|
||||
extern "C" void *ogre_insertBone(char* name, void* rootBone, int32_t index)
|
||||
{
|
||||
return (void*) ( ((Bone*)rootBone)->createChild(index) );
|
||||
}
|
||||
|
|
|
@ -56,23 +56,3 @@ SceneNode *root;
|
|||
#include "cpp_bsaarchive.cpp"
|
||||
#include "cpp_interface.cpp"
|
||||
#include "cpp_overlay.cpp"
|
||||
|
||||
// Testing
|
||||
extern "C" void cpp_drawBox(float x, float y, float z)
|
||||
{
|
||||
// Create a plane aligned with the xy-plane.
|
||||
/*
|
||||
MeshManager::getSingleton().createPlane("box1",
|
||||
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
Plane(Vector3::UNIT_X, 0),
|
||||
100,100);
|
||||
Entity *ent = mSceneMgr->createEntity( "box", "box1" );
|
||||
*/
|
||||
|
||||
Entity *ent = mSceneMgr->createEntity( "box", SceneManager::PT_SPHERE);
|
||||
ent->setCastShadows(false);
|
||||
SceneNode *nd = root->createChildSceneNode();
|
||||
nd->attachObject(ent);
|
||||
//nd->setScale(0.5, 0.5, 0.5);
|
||||
nd->setPosition(x,y,z);
|
||||
}
|
||||
|
|
|
@ -27,14 +27,9 @@ PanelOverlayElement *cont;
|
|||
|
||||
int visible;
|
||||
|
||||
void crap(char *p, ColourValue v)
|
||||
extern "C" void ogre_debug(int32_t i)
|
||||
{
|
||||
std::cerr << p << ": " << v.getAsRGBA() << "\n";
|
||||
}
|
||||
|
||||
extern "C" void cpp_debug(int32_t i)
|
||||
{
|
||||
std::cerr << "Running cpp_debug(" << i << ")\n";
|
||||
std::cerr << "Running ogre_debug(" << i << ")\n";
|
||||
|
||||
if(om)
|
||||
{
|
||||
|
|
|
@ -32,6 +32,8 @@ import nif.record;
|
|||
import core.resource;
|
||||
import ogre.bindings;
|
||||
|
||||
import bullet.bindings;
|
||||
|
||||
import util.uniquename;
|
||||
|
||||
/*
|
||||
|
@ -52,15 +54,15 @@ struct MeshLoader
|
|||
// Not sure how to handle the bounding box, just ignore it for now.
|
||||
|
||||
char[] baseName; // NIF file name. Used in scene node names etc. so
|
||||
// that we can easier identify where they came
|
||||
// from.
|
||||
// that we can identify where they came from in
|
||||
// case of error messages.
|
||||
|
||||
// Load a NIF mesh. Assumes nifMesh is already opened. This creates
|
||||
// a "template" scene node containing this mesh, and removes it from
|
||||
// the main scene. This node can later be "cloned" so that multiple
|
||||
// instances of the object can be inserted into the world without
|
||||
// inserting the mesh more than once.
|
||||
NodePtr loadMesh(char[] name)
|
||||
void loadMesh(char[] name, out NodePtr base, out BulletShape shape)
|
||||
{
|
||||
baseName = name;
|
||||
|
||||
|
@ -72,16 +74,19 @@ struct MeshLoader
|
|||
// TODO: Figure out what to do in this case, we should
|
||||
// probably throw.
|
||||
writefln("NIF '%s' IS NOT A MESH", name);
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get a fresh SceneNode and detatch it from the root. We use this
|
||||
// as the base for our mesh.
|
||||
NodePtr base = cpp_getDetachedNode();
|
||||
base = ogre_getDetachedNode();
|
||||
|
||||
// Recursively insert nodes (don't rotate the first node)
|
||||
insertNode(n, base, true);
|
||||
|
||||
// Get the final shape, if any
|
||||
shape = bullet_getFinalShape();
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
|
@ -99,7 +104,7 @@ struct MeshLoader
|
|||
// problem, I don't know when to do this and when not to. Neither
|
||||
// is always right. Update: It looks like we should always set
|
||||
// noRot to false in exterior cells.
|
||||
NodePtr node = cpp_createNode(UniqueName(data.name).ptr, &data.trafo,
|
||||
NodePtr node = ogre_createNode(UniqueName(data.name).ptr, &data.trafo,
|
||||
parent, cast(int)noRot);
|
||||
|
||||
// Handle any general properties here
|
||||
|
@ -206,7 +211,7 @@ struct MeshLoader
|
|||
|
||||
// Create the material
|
||||
if(material.length)
|
||||
cpp_createMaterial(material.ptr, mp.ambient.array.ptr, mp.diffuse.array.ptr,
|
||||
ogre_createMaterial(material.ptr, mp.ambient.array.ptr, mp.diffuse.array.ptr,
|
||||
mp.specular.array.ptr, mp.emissive.array.ptr,
|
||||
mp.glossiness, mp.alpha, texturePtr);
|
||||
else if(texturePtr)
|
||||
|
@ -218,7 +223,7 @@ struct MeshLoader
|
|||
zero[] = 0.0;
|
||||
one[] = 1.0;
|
||||
|
||||
cpp_createMaterial(newName.ptr, one.ptr, one.ptr, zero.ptr, zero.ptr, 0.0, 1.0,
|
||||
ogre_createMaterial(newName.ptr, one.ptr, one.ptr, zero.ptr, zero.ptr, 0.0, 1.0,
|
||||
texturePtr);
|
||||
}
|
||||
|
||||
|
@ -258,7 +263,23 @@ struct MeshLoader
|
|||
if( vertices[i+2] > maxZ) maxZ = vertices[i+2];
|
||||
}
|
||||
|
||||
cpp_createMesh(newName.ptr, vertices.length, vertices.ptr,
|
||||
// TODO: Get the node world transformation, needed to set up
|
||||
// the collision shape properly.
|
||||
float[3] trans;
|
||||
float[9] matrix;
|
||||
ogre_getWorldTransform(node, trans.ptr, matrix.ptr);
|
||||
|
||||
// Create a bullet collision shape from the trimesh, if there
|
||||
// are any triangles present. Pass along the world
|
||||
// transformation as well, since we must transform the trimesh
|
||||
// data manually.
|
||||
if(facesPtr != null)
|
||||
bullet_createTriShape(triangles.length, facesPtr,
|
||||
vertices.length, vertices.ptr,
|
||||
trans.ptr, matrix.ptr);
|
||||
|
||||
// Create the ogre mesh, associate it with the node
|
||||
ogre_createMesh(newName.ptr, vertices.length, vertices.ptr,
|
||||
normalsPtr, colorsPtr, uvsPtr, triangles.length, facesPtr,
|
||||
radius, material.ptr, minX, minY, minZ, maxX, maxY, maxZ,
|
||||
node);
|
||||
|
@ -267,19 +288,19 @@ struct MeshLoader
|
|||
}
|
||||
/*
|
||||
// Create a skeleton and get the root bone (index 0)
|
||||
BonePtr bone = cpp_setupSkeleton(name);
|
||||
BonePtr bone = ogre_setupSkeleton(name);
|
||||
|
||||
// Reset the bone index. The next bone to be created has index 1.
|
||||
boneIndex = 1;
|
||||
// Create a mesh and assign the skeleton to it
|
||||
MeshPtr mesh = cpp_setupMesh(name);
|
||||
MeshPtr mesh = ogre_setupMesh(name);
|
||||
|
||||
// Loop through the nodes, creating submeshes, materials and
|
||||
// skeleton bones in the process.
|
||||
handleNode(node, bone, mesh);
|
||||
|
||||
// Create the "template" entity
|
||||
EntityPtr entity = cpp_createEntity(name);
|
||||
EntityPtr entity = ogre_createEntity(name);
|
||||
|
||||
// Loop through once again, this time to set the right
|
||||
// transformations on the entity's SkeletonInstance. The order of
|
||||
|
@ -291,20 +312,20 @@ struct MeshLoader
|
|||
if(lastBone != boneIndex) writefln("WARNING: Bone number doesn't match");
|
||||
|
||||
if(!hasBBox)
|
||||
cpp_setMeshBoundingBox(mesh, minX, minY, minZ, maxX, maxY, maxZ);
|
||||
ogre_setMeshBoundingBox(mesh, minX, minY, minZ, maxX, maxY, maxZ);
|
||||
|
||||
return entity;
|
||||
}
|
||||
void handleNode(Node node, BonePtr root, MeshPtr mesh)
|
||||
{
|
||||
// Insert a new bone for this node
|
||||
BonePtr bone = cpp_insertBone(node.name, root, boneIndex++);
|
||||
BonePtr bone = ogre_insertBone(node.name, root, boneIndex++);
|
||||
|
||||
}
|
||||
|
||||
void transformBones(Node node, EntityPtr entity)
|
||||
{
|
||||
cpp_transformBone(entity, &node.trafo, boneIndex++);
|
||||
ogre_transformBone(entity, &node.trafo, boneIndex++);
|
||||
|
||||
NiNode n = cast(NiNode)node;
|
||||
if(n !is null)
|
||||
|
|
42
ogre/ogre.d
42
ogre/ogre.d
|
@ -27,6 +27,7 @@ import core.resource;
|
|||
import core.config;
|
||||
|
||||
import ogre.bindings;
|
||||
import bullet.bindings;
|
||||
import util.uniquename;
|
||||
import std.stdio;
|
||||
|
||||
|
@ -44,7 +45,8 @@ class OgreException : Exception
|
|||
|
||||
// Place a mesh in the 3D scene graph, at the given
|
||||
// location/scale. Returns a node pointer to the inserted object.
|
||||
NodePtr placeObject(MeshIndex mesh, Placement *pos, float scale)
|
||||
NodePtr placeObject(MeshIndex mesh, Placement *pos, float scale,
|
||||
bool collide)
|
||||
{
|
||||
// Get a scene node for this object. mesh.getNode() will either load
|
||||
// it from file or BSA archive, or give us a handle if it is already
|
||||
|
@ -52,22 +54,35 @@ NodePtr placeObject(MeshIndex mesh, Placement *pos, float scale)
|
|||
|
||||
// This must be called BEFORE UniqueName below, because it might
|
||||
// possibly use UniqueName itself and overwrite the data
|
||||
// there. (That was a fun bug to track down...)
|
||||
// there. (That was a fun bug to track down...) Calling getNode()
|
||||
// will load the mesh if it is not already loaded.
|
||||
NodePtr node = mesh.getNode();
|
||||
|
||||
// Let us insert a copy
|
||||
// First, convert the Morrowind rotation to a quaternion
|
||||
float[4] quat;
|
||||
ogre_mwToQuaternion(pos.rotation.ptr, quat.ptr);
|
||||
|
||||
// Insert a mesh copy into Ogre.
|
||||
char[] name = UniqueName(mesh.getName);
|
||||
return cpp_insertNode(node, name.ptr, pos, scale);
|
||||
node = ogre_insertNode(node, name.ptr, pos.position.ptr,
|
||||
quat.ptr, scale);
|
||||
|
||||
// Insert a collision shape too, if the mesh has one.
|
||||
if(collide && mesh.shape !is null)
|
||||
bullet_insertStatic(mesh.shape, pos.position.ptr,
|
||||
quat.ptr, scale);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
NodePtr attachLight(NodePtr parent, Color c, float radius)
|
||||
{
|
||||
return cpp_attachLight(UniqueName("_light").ptr, parent,
|
||||
return ogre_attachLight(UniqueName("_light").ptr, parent,
|
||||
c.red/255.0, c.green/255.0, c.blue/255.0,
|
||||
radius);
|
||||
}
|
||||
|
||||
// If 'true' then we must call cpp_cleanup() on exit.
|
||||
// If 'true' then we must call ogre_cleanup() on exit.
|
||||
bool ogreSetup = false;
|
||||
|
||||
// Make sure we clean up
|
||||
|
@ -91,22 +106,22 @@ void setupOgre()
|
|||
|
||||
// Later we will send more config info from core.config along with
|
||||
// this function
|
||||
if(cpp_configure(config.finalOgreConfig, toStringz(plugincfg)))
|
||||
if(ogre_configure(config.finalOgreConfig, toStringz(plugincfg)))
|
||||
OgreException("Configuration abort");
|
||||
|
||||
cpp_initWindow();
|
||||
ogre_initWindow();
|
||||
|
||||
// We set up the scene manager in a separate function, since we
|
||||
// might have to do that for every new cell later on, and handle
|
||||
// exterior cells differently, etc.
|
||||
cpp_makeScene();
|
||||
ogre_makeScene();
|
||||
|
||||
ogreSetup = true;
|
||||
}
|
||||
|
||||
void setAmbient(Color amb, Color sun, Color fog, float density)
|
||||
{
|
||||
cpp_setAmbient(amb.red/255.0, amb.green/255.0, amb.blue/255.0,
|
||||
ogre_setAmbient(amb.red/255.0, amb.green/255.0, amb.blue/255.0,
|
||||
sun.red/255.0, sun.green/255.0, sun.blue/255.0);
|
||||
|
||||
// Calculate fog distance
|
||||
|
@ -114,7 +129,7 @@ void setAmbient(Color amb, Color sun, Color fog, float density)
|
|||
float fhigh = 4500 + 9000*(1-density);
|
||||
float flow = 200 + 2000*(1-density);
|
||||
|
||||
cpp_setFog(fog.red/255.0, fog.green/255.0, fog.blue/255.0, 200, fhigh);
|
||||
ogre_setFog(fog.red/255.0, fog.green/255.0, fog.blue/255.0, 200, fhigh);
|
||||
}
|
||||
|
||||
// Jump into the OGRE rendering loop. Everything should be loaded and
|
||||
|
@ -122,7 +137,7 @@ void setAmbient(Color amb, Color sun, Color fog, float density)
|
|||
void startRendering()
|
||||
{
|
||||
// Kick OGRE into gear
|
||||
cpp_startRendering();
|
||||
ogre_startRendering();
|
||||
}
|
||||
|
||||
// Cleans up after OGRE. Resets things like screen resolution and
|
||||
|
@ -130,7 +145,7 @@ void startRendering()
|
|||
void cleanupOgre()
|
||||
{
|
||||
if(ogreSetup)
|
||||
cpp_cleanup();
|
||||
ogre_cleanup();
|
||||
|
||||
ogreSetup = false;
|
||||
}
|
||||
|
@ -143,3 +158,4 @@ align(1) struct Placement
|
|||
float[3] position;
|
||||
float[3] rotation;
|
||||
}
|
||||
static assert(Placement.sizeof == 4*6);
|
||||
|
|
19
openmw.d
19
openmw.d
|
@ -207,13 +207,14 @@ void main(char[][] args)
|
|||
}
|
||||
|
||||
// Simple safety hack
|
||||
NodePtr putObject(MeshIndex m, Placement *pos, float scale)
|
||||
NodePtr putObject(MeshIndex m, Placement *pos, float scale,
|
||||
bool collide=false)
|
||||
{
|
||||
if(m == null)
|
||||
writefln("WARNING: CANNOT PUT NULL OBJECT");
|
||||
else if(m.isEmpty)
|
||||
writefln("WARNING: CANNOT INSERT EMPTY MESH '%s'", m.getName);
|
||||
else return placeObject(m, pos, scale);
|
||||
else return placeObject(m, pos, scale, collide);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -235,7 +236,7 @@ void main(char[][] args)
|
|||
|
||||
// Not all interior cells have water
|
||||
if(cd.inCell.flags & CellFlags.HasWater)
|
||||
cpp_createWater(cd.water);
|
||||
ogre_createWater(cd.water);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -246,15 +247,15 @@ void main(char[][] args)
|
|||
setAmbient(c, c, c, 0);
|
||||
|
||||
// Put in the water
|
||||
cpp_createWater(cd.water);
|
||||
ogre_createWater(cd.water);
|
||||
|
||||
// Create an ugly sky
|
||||
cpp_makeSky();
|
||||
ogre_makeSky();
|
||||
}
|
||||
|
||||
// Insert the meshes of statics into the scene
|
||||
foreach(ref LiveStatic ls; cd.statics)
|
||||
putObject(ls.m.model, &ls.base.pos, ls.base.scale);
|
||||
putObject(ls.m.model, &ls.base.pos, ls.base.scale, true);
|
||||
// Inventory lights
|
||||
foreach(ref LiveLight ls; cd.lights)
|
||||
{
|
||||
|
@ -277,7 +278,7 @@ void main(char[][] args)
|
|||
// Static lights
|
||||
foreach(ref LiveLight ls; cd.statLights)
|
||||
{
|
||||
NodePtr n = putObject(ls.m.model, &ls.base.pos, ls.base.scale);
|
||||
NodePtr n = putObject(ls.m.model, &ls.base.pos, ls.base.scale, true);
|
||||
ls.lightNode = attachLight(n, ls.m.data.color, ls.m.data.radius);
|
||||
if(!noSound)
|
||||
{
|
||||
|
@ -303,7 +304,7 @@ void main(char[][] args)
|
|||
*/
|
||||
// Containers
|
||||
foreach(ref LiveContainer ls; cd.containers)
|
||||
putObject(ls.m.model, &ls.base.pos, ls.base.scale);
|
||||
putObject(ls.m.model, &ls.base.pos, ls.base.scale, true);
|
||||
// Doors
|
||||
foreach(ref LiveDoor ls; cd.doors)
|
||||
putObject(ls.m.model, &ls.base.pos, ls.base.scale);
|
||||
|
@ -334,7 +335,7 @@ void main(char[][] args)
|
|||
// Tools
|
||||
foreach(ref LiveTool ls; cd.tools)
|
||||
putObject(ls.m.model, &ls.base.pos, ls.base.scale);
|
||||
// Creatures (these often look like shit
|
||||
// Creatures (not displayed very well yet)
|
||||
foreach(ref LiveCreature ls; cd.creatures)
|
||||
putObject(ls.m.model, &ls.base.pos, ls.base.scale);
|
||||
|
||||
|
|
23
sound/al.d
23
sound/al.d
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.snaptoad.com/
|
||||
|
||||
This file (al.d) is part of the OpenMW package.
|
||||
|
||||
OpenMW is distributed as free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
version 3, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 3 along with this program. If not, see
|
||||
http://www.gnu.org/licenses/ .
|
||||
|
||||
*/
|
||||
|
||||
module sound.al;
|
||||
|
||||
extern(C):
|
||||
|
|
23
sound/alc.d
23
sound/alc.d
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.snaptoad.com/
|
||||
|
||||
This file (alc.d) is part of the OpenMW package.
|
||||
|
||||
OpenMW is distributed as free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
version 3, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 3 along with this program. If not, see
|
||||
http://www.gnu.org/licenses/ .
|
||||
|
||||
*/
|
||||
|
||||
module sound.alc;
|
||||
|
||||
extern(C):
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.snaptoad.com/
|
||||
|
||||
This file (avcodec.d) is part of the OpenMW package.
|
||||
|
||||
OpenMW is distributed as free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
version 3, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 3 along with this program. If not, see
|
||||
http://www.gnu.org/licenses/ .
|
||||
|
||||
*/
|
||||
|
||||
module sound.avcodec;
|
||||
|
||||
extern (C):
|
||||
|
@ -13,19 +36,19 @@ typedef void* AVAudio;
|
|||
|
||||
// Open the named file, and return a unique handle representing it.
|
||||
// Returns NULL on error
|
||||
AVFile cpp_openAVFile(char *fname);
|
||||
AVFile avc_openAVFile(char *fname);
|
||||
|
||||
// Close the file handle, invalidating all streams taken from it
|
||||
void cpp_closeAVFile(AVFile file);
|
||||
void avc_closeAVFile(AVFile file);
|
||||
|
||||
// Get a unique handle to an audio stream in the file. The given number
|
||||
// is for files that can contain multiple audio streams (generally you
|
||||
// would pass 0, for the first audio stream)
|
||||
AVAudio cpp_getAVAudioStream(AVFile file, int streamnum);
|
||||
AVAudio avc_getAVAudioStream(AVFile file, int streamnum);
|
||||
|
||||
// Get audio info representing the current stream. Returns 0 for success
|
||||
// (not likely to fail)
|
||||
int cpp_getAVAudioInfo(AVAudio stream, int *rate, int *channels, int *bits);
|
||||
int avc_getAVAudioInfo(AVAudio stream, int *rate, int *channels, int *bits);
|
||||
|
||||
// Decode the next bit of data for the given audio stream. The function
|
||||
// must provide no less than the requested number of bytes, except for
|
||||
|
@ -34,9 +57,9 @@ int cpp_getAVAudioInfo(AVAudio stream, int *rate, int *channels, int *bits);
|
|||
// any stream that has had a stream handle returned.
|
||||
// eg. if a file has one video stream and 2 audio streams and the app
|
||||
// gets a handle to the video stream and one audio stream, it must
|
||||
// not destroy video data for subsequent calls to cpp_getAVVideoData if
|
||||
// not destroy video data for subsequent calls to avc_getAVVideoData if
|
||||
// it has to read over it while decoding the audio stream. The other
|
||||
// audio stream's data, however, may be discarded.
|
||||
// Returns the number of bytes written to the buffer, which will be no
|
||||
// more than the provided length.
|
||||
int cpp_getAVAudioData(AVAudio stream, void *data, int length);
|
||||
int avc_getAVAudioData(AVAudio stream, void *data, int length);
|
||||
|
|
|
@ -53,11 +53,11 @@ struct MyFile {
|
|||
};
|
||||
|
||||
// TODO:
|
||||
// extern "C" MyFile::MyStream *cpp_getAVVideoStream(MyFile *file, int streamnum);
|
||||
// extern "C" int cpp_getAVVideoInfo(MyFile::MyStream *stream, float *fps, int *width, int * height);
|
||||
// extern "C" int cpp_getAVVideoData(MyFile::MyStream *stream, char *data, int length);
|
||||
// extern "C" MyFile::MyStream *avc_getAVVideoStream(MyFile *file, int streamnum);
|
||||
// extern "C" int avc_getAVVideoInfo(MyFile::MyStream *stream, float *fps, int *width, int * height);
|
||||
// extern "C" int avc_getAVVideoData(MyFile::MyStream *stream, char *data, int length);
|
||||
|
||||
extern "C" MyFile *cpp_openAVFile(char *fname)
|
||||
extern "C" MyFile *avc_openAVFile(char *fname)
|
||||
{
|
||||
static bool done = false;
|
||||
if(!done) { av_register_all();
|
||||
|
@ -75,7 +75,7 @@ extern "C" MyFile *cpp_openAVFile(char *fname)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
extern "C" void cpp_closeAVFile(MyFile *file)
|
||||
extern "C" void avc_closeAVFile(MyFile *file)
|
||||
{
|
||||
if(!file) return;
|
||||
|
||||
|
@ -92,7 +92,7 @@ extern "C" void cpp_closeAVFile(MyFile *file)
|
|||
delete file;
|
||||
}
|
||||
|
||||
extern "C" MyFile::MyStream *cpp_getAVAudioStream(MyFile *file, int streamnum)
|
||||
extern "C" MyFile::MyStream *avc_getAVAudioStream(MyFile *file, int streamnum)
|
||||
{
|
||||
if(!file) return NULL;
|
||||
for(unsigned int i = 0;i < file->FmtCtx->nb_streams;i++)
|
||||
|
@ -122,7 +122,7 @@ extern "C" MyFile::MyStream *cpp_getAVAudioStream(MyFile *file, int streamnum)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
extern "C" int cpp_getAVAudioInfo(MyFile::MyStream *stream,
|
||||
extern "C" int avc_getAVAudioInfo(MyFile::MyStream *stream,
|
||||
int *rate, int *channels, int *bits)
|
||||
{
|
||||
if(!stream) return 1;
|
||||
|
@ -159,7 +159,7 @@ static void getNextPacket(MyFile *file, int streamidx)
|
|||
}
|
||||
}
|
||||
|
||||
extern "C" int cpp_getAVAudioData(MyFile::MyStream *stream, char *data, int length)
|
||||
extern "C" int avc_getAVAudioData(MyFile::MyStream *stream, char *data, int length)
|
||||
{
|
||||
if(!stream) return 0;
|
||||
|
||||
|
|
|
@ -167,7 +167,7 @@ struct MusicManager
|
|||
checkALError("killing current track");
|
||||
}
|
||||
|
||||
if(fileHandle) cpp_closeAVFile(fileHandle);
|
||||
if(fileHandle) avc_closeAVFile(fileHandle);
|
||||
fileHandle = null;
|
||||
audioHandle = null;
|
||||
|
||||
|
@ -185,7 +185,7 @@ struct MusicManager
|
|||
{
|
||||
// This block is only executed if an exception is thrown.
|
||||
|
||||
if(fileHandle) cpp_closeAVFile(fileHandle);
|
||||
if(fileHandle) avc_closeAVFile(fileHandle);
|
||||
|
||||
fileHandle = null;
|
||||
audioHandle = null;
|
||||
|
@ -208,16 +208,16 @@ struct MusicManager
|
|||
if(checkALError())
|
||||
fail("Couldn't generate buffers");
|
||||
|
||||
fileHandle = cpp_openAVFile(toStringz(playlist[index]));
|
||||
fileHandle = avc_openAVFile(toStringz(playlist[index]));
|
||||
if(!fileHandle)
|
||||
fail("Unable to open " ~ playlist[index]);
|
||||
|
||||
audioHandle = cpp_getAVAudioStream(fileHandle, 0);
|
||||
audioHandle = avc_getAVAudioStream(fileHandle, 0);
|
||||
if(!audioHandle)
|
||||
fail("Unable to load music track " ~ playlist[index]);
|
||||
|
||||
int ch, bits, rate;
|
||||
if(cpp_getAVAudioInfo(audioHandle, &rate, &ch, &bits) != 0)
|
||||
if(avc_getAVAudioInfo(audioHandle, &rate, &ch, &bits) != 0)
|
||||
fail("Unable to get info for music track " ~ playlist[index]);
|
||||
|
||||
bufRate = rate;
|
||||
|
@ -248,7 +248,7 @@ struct MusicManager
|
|||
|
||||
foreach(int i, ref b; bIDs)
|
||||
{
|
||||
int length = cpp_getAVAudioData(audioHandle, outData.ptr, outData.length);
|
||||
int length = avc_getAVAudioData(audioHandle, outData.ptr, outData.length);
|
||||
if(length) alBufferData(b, bufFormat, outData.ptr, length, bufRate);
|
||||
if(length == 0 || checkALError())
|
||||
{
|
||||
|
@ -284,7 +284,7 @@ struct MusicManager
|
|||
// Disable music
|
||||
void disableMusic()
|
||||
{
|
||||
if(fileHandle) cpp_closeAVFile(fileHandle);
|
||||
if(fileHandle) avc_closeAVFile(fileHandle);
|
||||
fileHandle = null;
|
||||
audioHandle = null;
|
||||
|
||||
|
@ -333,7 +333,7 @@ struct MusicManager
|
|||
|
||||
for(int i = 0;i < count;i++)
|
||||
{
|
||||
int length = cpp_getAVAudioData(audioHandle, outData.ptr, outData.length);
|
||||
int length = avc_getAVAudioData(audioHandle, outData.ptr, outData.length);
|
||||
if(length <= 0)
|
||||
{
|
||||
if(i == 0)
|
||||
|
|
10
sound/sfx.d
10
sound/sfx.d
|
@ -62,8 +62,8 @@ struct SoundFile
|
|||
bID = 0;
|
||||
|
||||
ubyte[] outData;
|
||||
AVFile fileHandle = cpp_openAVFile(toStringz(file));
|
||||
AVAudio audioHandle = cpp_getAVAudioStream(fileHandle, 0);
|
||||
AVFile fileHandle = avc_openAVFile(toStringz(file));
|
||||
AVAudio audioHandle = avc_getAVAudioStream(fileHandle, 0);
|
||||
|
||||
if(!fileHandle)
|
||||
{
|
||||
|
@ -77,7 +77,7 @@ struct SoundFile
|
|||
}
|
||||
|
||||
int ch, bits, rate;
|
||||
if(cpp_getAVAudioInfo(audioHandle, &rate, &ch, &bits) != 0)
|
||||
if(avc_getAVAudioInfo(audioHandle, &rate, &ch, &bits) != 0)
|
||||
{
|
||||
writefln("Unable to get info for sound %s", file);
|
||||
goto errclose;
|
||||
|
@ -110,7 +110,7 @@ struct SoundFile
|
|||
// whole sound in one or two iterations, but not allocate too much
|
||||
// memory in case its short
|
||||
outData.length = outData.length+8192;
|
||||
int length = cpp_getAVAudioData(audioHandle, outData.ptr+total, outData.length-total);
|
||||
int length = avc_getAVAudioData(audioHandle, outData.ptr+total, outData.length-total);
|
||||
total += length;
|
||||
}
|
||||
while(total == outData.length);
|
||||
|
@ -129,7 +129,7 @@ struct SoundFile
|
|||
}
|
||||
|
||||
errclose:
|
||||
if(fileHandle) cpp_closeAVFile(fileHandle);
|
||||
if(fileHandle) avc_closeAVFile(fileHandle);
|
||||
fileHandle = null;
|
||||
audioHandle = null;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue