First alpha release of REAL collision detection.

git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@48 ea6a568a-9f4f-0410-981a-c910a81bb256
pull/7/head
nkorslund 16 years ago
parent 5fad8ea459
commit c094324ef2

@ -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. ####

@ -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);
// Insert a debug collision object
void cpp_insertBox(float x, float y, float z);
void bullet_getPlayerPos(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);
g_dynamicsWorld->convexSweepTest (g_playerShape, start, end, callback);
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 {
// we dropped the full height
g_playerPosition = targetPosition;
}
// we dropped a fraction of the height -> hit floor
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,8 +161,8 @@ 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,
state.Y.rel * effMY );
ogre_rotateCamera( state.X.rel * effMX,
state.Y.rel * effMY );
}
extern(C) void d_handleMouseButton(MouseState *state, int button)
@ -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?
char *plugincfg // Name of 'plugin.cfg' file
);
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,23 +108,23 @@ NodePtr cpp_createNode(
// Create a light with the given diffuse color. Attach it to SceneNode
// 'parent'.
NodePtr cpp_attachLight(char* name, NodePtr parent,
float r, float g, float b,
float radius);
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
float *ambient, // Ambient RBG value
float *diffuse,
float *specular,
float *emissive,// Self illumination
float glossiness,// Same as shininess?
float alpha, // Use this in all alpha values?
char *texture); // Texture name
void ogre_createMaterial(char *name, // Name to give resource
float *ambient, // Ambient RBG value
float *diffuse,
float *specular,
float *emissive,// Self illumination
float glossiness,// Same as shininess?
float alpha, // Use this in all alpha values?
char *texture); // Texture name
// 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)

@ -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);

@ -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);

@ -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):

@ -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)

@ -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…
Cancel
Save