forked from mirror/openmw-tes3mp
More updates on Bullet code and other things
git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@49 ea6a568a-9f4f-0410-981a-c910a81bb256
This commit is contained in:
parent
c094324ef2
commit
6277c7f17c
16 changed files with 184 additions and 59 deletions
|
@ -122,6 +122,9 @@ Changelog:
|
|||
- working on collision detection with Bullet
|
||||
- working on fixing sound issues for windows (running out of sound
|
||||
resources, music playback doesn't good)
|
||||
- new key bindings:
|
||||
t - toggle physics mode (walking, flying, ghost)
|
||||
n - nighteye, toggle full ambient light
|
||||
- added build files for CMake (with CMakeD) and Code::Blocks (neither
|
||||
are tested yet)
|
||||
- various minor changes and updates
|
||||
|
|
|
@ -35,6 +35,9 @@ extern(C):
|
|||
// Initialize the dynamic world. Returns non-zero if an error occurs.
|
||||
int bullet_init();
|
||||
|
||||
// Switch to the next physics mode
|
||||
void bullet_nextMode();
|
||||
|
||||
// Warp the player to a specific location.
|
||||
void bullet_movePlayer(float x, float y, float z);
|
||||
|
||||
|
|
|
@ -64,6 +64,16 @@ btTriangleIndexVertexArray *g_currentMesh;
|
|||
btHashedOverlappingPairCache* g_pairCache;
|
||||
CustomOverlappingPairCallback *g_customPairCallback;
|
||||
|
||||
// Three physics modes: walking (with gravity and collision), flying
|
||||
// (collision but no gravity) and ghost mode (fly through walls)
|
||||
enum
|
||||
{
|
||||
PHYS_WALK,
|
||||
PHYS_FLY,
|
||||
PHYS_GHOST
|
||||
};
|
||||
int g_physMode;
|
||||
|
||||
// Include the player physics
|
||||
#include "cpp_player.cpp"
|
||||
|
||||
|
@ -181,10 +191,34 @@ extern "C" int32_t bullet_init()
|
|||
// Make sure this is zero at startup
|
||||
g_currentMesh = NULL;
|
||||
|
||||
// Start out walking
|
||||
g_physMode = PHYS_WALK;
|
||||
|
||||
// Success!
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Switch to the next physics mode
|
||||
extern "C" void bullet_nextMode()
|
||||
{
|
||||
g_physMode++;
|
||||
if(g_physMode > PHYS_GHOST)
|
||||
g_physMode = PHYS_WALK;
|
||||
|
||||
switch(g_physMode)
|
||||
{
|
||||
case PHYS_WALK:
|
||||
cout << "Entering walking mode\n";
|
||||
break;
|
||||
case PHYS_FLY:
|
||||
cout << "Entering flying mode\n";
|
||||
break;
|
||||
case PHYS_GHOST:
|
||||
cout << "Entering ghost mode\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Warp the player to a specific location. We do not bother setting
|
||||
// rotation, since it's completely irrelevant for collision detection.
|
||||
extern "C" void bullet_movePlayer(float x, float y, float z)
|
||||
|
@ -285,6 +319,8 @@ extern "C" void bullet_insertStatic(btCollisionShape *shape,
|
|||
float *quat,
|
||||
float scale)
|
||||
{
|
||||
// TODO: Good test case for scaled meshes: Aharunartus, some of the
|
||||
// stairs inside the cavern currently don't collide
|
||||
if(scale != 1.0)
|
||||
{
|
||||
cout << "WARNING: Cannot scale collision meshes yet (wanted "
|
||||
|
|
|
@ -232,8 +232,6 @@ bool recoverFromPenetration()
|
|||
g_dynamicsWorld->getDispatchInfo(),
|
||||
g_dispatcher);
|
||||
|
||||
g_playerPosition = g_playerObject->getWorldTransform().getOrigin();
|
||||
|
||||
btScalar maxPen = 0.0;
|
||||
for (int i = 0; i < g_pairCache->getNumOverlappingPairs(); i++)
|
||||
{
|
||||
|
@ -285,8 +283,24 @@ bool recoverFromPenetration()
|
|||
// main function is responsible for player movement.
|
||||
void playerStepCallback(btDynamicsWorld* dynamicsWorld, btScalar timeStep)
|
||||
{
|
||||
// Before moving, recover from current penetrations
|
||||
// The walking direction is set from D code each frame, and the
|
||||
// final player position is read back from D code after the
|
||||
// simulation.
|
||||
btVector3 walkStep = g_walkDirection * timeStep;
|
||||
|
||||
// Get the player position
|
||||
g_playerPosition = g_playerObject->getWorldTransform().getOrigin();
|
||||
|
||||
if(g_physMode == PHYS_GHOST)
|
||||
{
|
||||
// Ghost mode - just move, no collision
|
||||
g_playerPosition += walkStep;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Collision detection is active
|
||||
|
||||
// Before moving, recover from current penetrations
|
||||
int numPenetrationLoops = 0;
|
||||
g_touchingContact = false;
|
||||
while (recoverFromPenetration())
|
||||
|
@ -299,27 +313,26 @@ void playerStepCallback(btDynamicsWorld* dynamicsWorld, btScalar timeStep)
|
|||
break;
|
||||
}
|
||||
|
||||
// Get the player position
|
||||
btTransform xform;
|
||||
xform = g_playerObject->getWorldTransform ();
|
||||
g_playerPosition = xform.getOrigin();
|
||||
// recoverFromPenetration updates g_playerPosition and the
|
||||
// collision mesh, so they are still in sync at this point
|
||||
|
||||
// Next, do the walk.
|
||||
|
||||
// TODO: Walking direction should be set from D code, and the final
|
||||
// position should be retrieved back from C++. The walking direction
|
||||
// always reflects the intentional action of an agent (ie. the
|
||||
// player or the AI), but the end result comes from collision and
|
||||
// physics.
|
||||
|
||||
btVector3 walkStep = g_walkDirection * timeStep;
|
||||
// Next, do the walk. The following functions only updates
|
||||
// g_playerPosition, they do not move the collision object.
|
||||
|
||||
if(g_physMode == PHYS_WALK)
|
||||
{
|
||||
stepUp();
|
||||
stepForward(walkStep);
|
||||
stepDown(timeStep);
|
||||
}
|
||||
else if(g_physMode == PHYS_FLY)
|
||||
stepForward(walkStep);
|
||||
else
|
||||
cout << "WARNING: Unknown physics mode " << g_physMode << "!\n";
|
||||
}
|
||||
|
||||
// Move the player (but keep rotation)
|
||||
xform = g_playerObject->getWorldTransform ();
|
||||
// Move the player collision mesh
|
||||
btTransform xform = g_playerObject->getWorldTransform ();
|
||||
xform.setOrigin (g_playerPosition);
|
||||
g_playerObject->setWorldTransform (xform);
|
||||
}
|
||||
|
|
|
@ -240,6 +240,8 @@ struct ConfigManager
|
|||
bind(Keys.Fullscreen, KC.F);
|
||||
|
||||
bind(Keys.ToggleBattleMusic, KC.SPACE);
|
||||
bind(Keys.PhysMode, KC.T);
|
||||
bind(Keys.Nighteye, KC.N);
|
||||
bind(Keys.Debug, KC.G);
|
||||
|
||||
bind(Keys.Pause, KC.PAUSE, KC.P);
|
||||
|
|
|
@ -221,6 +221,9 @@ extern(C) void d_handleKey(KC keycode, dchar text = 0)
|
|||
case Keys.Mute: toggleMute(); break;
|
||||
case Keys.Fullscreen: toggleFullscreen(); break;
|
||||
|
||||
case Keys.PhysMode: bullet_nextMode(); break;
|
||||
case Keys.Nighteye: ogre_toggleLight(); break;
|
||||
|
||||
case Keys.Debug: ogre_debug(0); break;
|
||||
case Keys.ScreenShot: takeScreenShot(); break;
|
||||
case Keys.Pause: togglePause(); break;
|
||||
|
|
|
@ -65,6 +65,8 @@ enum Keys
|
|||
// These will not be part of the finished product
|
||||
Fullscreen,
|
||||
ToggleBattleMusic,
|
||||
PhysMode, // Toggle physics mode between walking, flying and ghost
|
||||
Nighteye, // Full ambient lighting
|
||||
Debug,
|
||||
|
||||
// Misc
|
||||
|
@ -248,6 +250,8 @@ struct KeyBindings
|
|||
|
||||
keyToString[Keys.Fullscreen] = "Toggle Fullscreen Mode";
|
||||
keyToString[Keys.ToggleBattleMusic] = "Toggle Battle Music";
|
||||
keyToString[Keys.PhysMode] = "Toggle Physics Mode";
|
||||
keyToString[Keys.Nighteye] = "Toggle Nighteye";
|
||||
keyToString[Keys.Debug] = "OGRE Test Action";
|
||||
|
||||
keyToString[Keys.Pause] = "Pause";
|
||||
|
|
|
@ -49,11 +49,10 @@ abstract class Controlled : Extra
|
|||
// Record with name and controller/extra data link
|
||||
abstract class Named : Controlled
|
||||
{
|
||||
// Name of this object. This is used to refer to the object from .kf
|
||||
// files.
|
||||
char[] name;
|
||||
|
||||
//Extra extra;
|
||||
//Controller controller;
|
||||
|
||||
override:
|
||||
char[] toString()
|
||||
{
|
||||
|
@ -68,23 +67,8 @@ abstract class Named : Controlled
|
|||
//super.read(f);
|
||||
name = nifFile.getString();
|
||||
debug(verbose) writefln("Name: %s", name);
|
||||
/*
|
||||
debug(verbose) writef("Extra ");
|
||||
getIndex(f);
|
||||
debug(verbose) writef("Controller ");
|
||||
getIndex(f);
|
||||
*/
|
||||
super.read();
|
||||
}
|
||||
|
||||
/*
|
||||
void sortOut(Record[] list)
|
||||
{
|
||||
super.sortOut(list);
|
||||
extra = lookup!(Extra)(list);
|
||||
controller = lookup!(Controller)(list);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
class NiSequenceStreamHelper : Named {}
|
||||
|
|
10
nif/data.d
10
nif/data.d
|
@ -147,6 +147,15 @@ class ShapeData : Record
|
|||
if(nifFile.getInt != 0)
|
||||
{
|
||||
if(uvs == 0) nifFile.warn("Empty UV list");
|
||||
|
||||
// Only the 6 first bits are used as a count, the rest are
|
||||
// (unknown) flags.
|
||||
if(uvs > 0b111111)
|
||||
{
|
||||
nifFile.warn("UV count contains (unknown) flags");
|
||||
uvs = uvs & 0b111111;
|
||||
}
|
||||
|
||||
uvlist = nifFile.getArraySize!(float)(uvs*verts*2);
|
||||
}
|
||||
else if(uvs != 0) nifFile.warn("UV list was unexpectedly missing");
|
||||
|
@ -528,6 +537,7 @@ class NiTriShapeData : ShapeData
|
|||
debug(verbose) writefln("Number of faces: ", tris);
|
||||
if(tris)
|
||||
{
|
||||
// Must have three times as many vertices as triangles
|
||||
int cnt = nifFile.getIntIs(tris*3);
|
||||
triangles = nifFile.getArraySize!(short)(cnt);
|
||||
}
|
||||
|
|
|
@ -70,6 +70,9 @@ void ogre_setFog(float rf, float gf, float bf,
|
|||
// Create a simple sky dome
|
||||
int ogre_makeSky();
|
||||
|
||||
// Toggle full ambient lighting on and off
|
||||
void ogre_toggleLight();
|
||||
|
||||
// Enter main rendering loop
|
||||
void ogre_startRendering();
|
||||
|
||||
|
|
|
@ -121,6 +121,8 @@ extern "C" void ogre_rotateCamera(float x, float y)
|
|||
{
|
||||
mCamera->yaw(Degree(-x));
|
||||
mCamera->pitch(Degree(-y));
|
||||
|
||||
//g_light->setDirection(mCamera->getDirection());
|
||||
}
|
||||
|
||||
// Get current camera position
|
||||
|
@ -154,6 +156,8 @@ extern "C" void ogre_moveCamera(float x, float y, float z)
|
|||
// is not affected by the rotation of the root node, so we must
|
||||
// transform this manually.
|
||||
mCamera->setPosition(Vector3(x,z,-y));
|
||||
|
||||
//g_light->setPosition(mCamera->getPosition());
|
||||
}
|
||||
|
||||
// Rotate camera using Morrowind rotation specifiers
|
||||
|
|
|
@ -163,7 +163,7 @@ extern "C" void ogre_initWindow()
|
|||
std::cout << "ogre_initWindow finished\n";
|
||||
}
|
||||
|
||||
// Make a scene, set the given ambient light
|
||||
// Make a scene
|
||||
extern "C" void ogre_makeScene()
|
||||
{
|
||||
// Get the SceneManager, in this case a generic one
|
||||
|
@ -198,6 +198,53 @@ extern "C" void ogre_makeScene()
|
|||
SceneNode *rt = mSceneMgr->getRootSceneNode();
|
||||
root = rt->createChildSceneNode();
|
||||
root->pitch(Degree(-90));
|
||||
|
||||
/*
|
||||
g_light = mSceneMgr->createLight("carry");
|
||||
g_light->setDiffuseColour(1,0.7,0.3);
|
||||
g_light->setAttenuation(2000, 0, 0.008, 0);
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
// Toggle carryable light
|
||||
extern "C" void ogre_toggleCarryLight()
|
||||
{
|
||||
if(g_spotOn == 0)
|
||||
{
|
||||
g_light->setVisible(true);
|
||||
g_spotOn = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_light->setVisible(false);
|
||||
g_spotOn = 0;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Toggle ambient light
|
||||
extern "C" void ogre_toggleLight()
|
||||
{
|
||||
if(g_lightOn == 0)
|
||||
{
|
||||
std::cout << "Turning the lights up\n";
|
||||
ColourValue half = 0.7*g_ambient + 0.3*ColourValue(1,1,1);
|
||||
mSceneMgr->setAmbientLight(half);
|
||||
g_lightOn = 1;
|
||||
}
|
||||
else if(g_lightOn == 1)
|
||||
{
|
||||
std::cout << "Turning the lights to full\n";
|
||||
g_lightOn = 2;
|
||||
mSceneMgr->setAmbientLight(ColourValue(1,1,1));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Setting lights to normal\n";
|
||||
g_lightOn = 0;
|
||||
mSceneMgr->setAmbientLight(g_ambient);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a sky dome. Currently disabled since we aren't including the
|
||||
|
@ -217,6 +264,7 @@ extern "C" Light* ogre_attachLight(char *name, SceneNode* base,
|
|||
|
||||
// This seems to look reasonably ok.
|
||||
l->setAttenuation(3*radius, 0, 0, 12.0/(radius*radius));
|
||||
//l->setAttenuation(5*radius, 0, 0, 8.0/(radius*radius));
|
||||
|
||||
// base might be null, sometimes lights don't have meshes
|
||||
if(base) base->attachObject(l);
|
||||
|
@ -233,8 +281,8 @@ extern "C" void ogre_toggleFullscreen()
|
|||
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);
|
||||
mSceneMgr->setAmbientLight(c);
|
||||
g_ambient = ColourValue(r, g, b);
|
||||
mSceneMgr->setAmbientLight(g_ambient);
|
||||
|
||||
// Create a "sun" that shines light downwards. It doesn't look
|
||||
// completely right, but leave it for now.
|
||||
|
|
|
@ -42,6 +42,14 @@ SceneManager *mSceneMgr;
|
|||
Camera *mCamera;
|
||||
Viewport *vp;
|
||||
|
||||
ColourValue g_ambient;
|
||||
int g_lightOn = 0;
|
||||
|
||||
/*
|
||||
int g_spotOn = 0;
|
||||
Light *g_light;
|
||||
*/
|
||||
|
||||
OIS::InputManager *mInputManager;
|
||||
OIS::Mouse *mMouse;
|
||||
OIS::Keyboard *mKeyboard;
|
||||
|
|
|
@ -102,8 +102,8 @@ struct MeshLoader
|
|||
// names later, in order to attach arms and legs on NPCs
|
||||
// etc. Always ignore transformation of the first node? This is a
|
||||
// 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.
|
||||
// is always right. Update: I originally thought noRot should be
|
||||
// false for exteriors and true for interiors, but this isn't so.
|
||||
NodePtr node = ogre_createNode(UniqueName(data.name).ptr, &data.trafo,
|
||||
parent, cast(int)noRot);
|
||||
|
||||
|
|
4
openmw.d
4
openmw.d
|
@ -308,9 +308,9 @@ void main(char[][] args)
|
|||
// Doors
|
||||
foreach(ref LiveDoor ls; cd.doors)
|
||||
putObject(ls.m.model, &ls.base.pos, ls.base.scale);
|
||||
// Activators
|
||||
// Activators (including beds etc)
|
||||
foreach(ref LiveActivator ls; cd.activators)
|
||||
putObject(ls.m.model, &ls.base.pos, ls.base.scale);
|
||||
putObject(ls.m.model, &ls.base.pos, ls.base.scale, true);
|
||||
// Potions
|
||||
foreach(ref LivePotion ls; cd.potions)
|
||||
putObject(ls.m.model, &ls.base.pos, ls.base.scale);
|
||||
|
|
|
@ -31,6 +31,7 @@ Decrease SFX Volume=3
|
|||
Mute Sound=m
|
||||
Toggle Fullscreen Mode=f
|
||||
Toggle Battle Music=space
|
||||
Toggle Physics Mode=t
|
||||
OGRE Test Action=g
|
||||
Pause=pause,p
|
||||
Screen Shot=print_screen
|
||||
|
@ -41,3 +42,6 @@ Main Volume=0.7
|
|||
Music Volume=0.5
|
||||
SFX Volume=0.5
|
||||
Enable Music=yes
|
||||
|
||||
[Game Files]
|
||||
GameFile[0]=Morrowind.esm
|
||||
|
|
Loading…
Reference in a new issue