some changes related to BspDemo

This commit is contained in:
ejcoumans
2006-08-11 23:01:25 +00:00
parent 22c416dc0c
commit e2b6d4ee65
12 changed files with 2304 additions and 15 deletions

View File

@@ -0,0 +1,282 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "BspConverter.h"
#include "BspLoader.h"
#include "CcdPhysicsEnvironment.h"
#include "SimdVector3.h"
void BspConverter::convertBsp(BspLoader& bspLoader,float scaling)
{
{
SimdVector3 playerStart (0.f, 0.f, 100.f);
if (bspLoader.findVectorByName(&playerStart[0],"info_player_start"))
{
printf("found playerstart\n");
}
else
{
if (bspLoader.findVectorByName(&playerStart[0],"info_player_deathmatch"))
{
printf("found deatchmatch start\n");
}
}
playerStart[2] += 20.f; //start a bit higher
playerStart *= scaling;
//progressBegin("Loading bsp");
for (int i=0;i<bspLoader.m_numleafs;i++)
{
printf("Reading bspLeaf %i from total %i (%f procent)\n",i, bspLoader.m_numleafs,(100.f*(float)i/float(bspLoader.m_numleafs)) );
bool isValid = false;
bool isValidBrush = false;
BSPLeaf& leaf = bspLoader.m_dleafs[i];
for (int b=0;b<leaf.numLeafBrushes;b++)
{
std::vector<SimdVector3> planeEquations;
int brushid = bspLoader.m_dleafbrushes[leaf.firstLeafBrush+b];
BSPBrush& brush = bspLoader.m_dbrushes[brushid];
if (brush.shaderNum!=-1)
{
if (bspLoader.m_dshaders[ brush.shaderNum ].contentFlags & BSPCONTENTS_SOLID)
{
brush.shaderNum = -1;
for (int p=0;p<brush.numSides;p++)
{
int sideid = brush.firstSide+p;
BSPBrushSide& brushside = bspLoader.m_dbrushsides[sideid];
int planeid = brushside.planeNum;
BSPPlane& plane = bspLoader.m_dplanes[planeid];
SimdVector3 planeEq;
planeEq.setValue(
plane.normal[0],
plane.normal[1],
plane.normal[2],
scaling*-plane.dist);
planeEquations.push_back(planeEq);
isValidBrush=true;
}
if (isValidBrush)
{
std::vector<SimdVector3> vertices;
getVerticesFromPlaneEquations(planeEquations,vertices);
printf("getVerticesFromPlaneEquations returned %i\n",vertices.size());
bool isEntity = false;
SimdVector3 entityTarget(0.f,0.f,0.f);
AddConvexVerticesCollider(vertices,isEntity,entityTarget);
}
}
}
else
{
int i=0;
}
}
}
#define USE_ENTITIES
#ifdef USE_ENTITIES
{
int i;
for (i=0;i<bspLoader.m_num_entities;i++)
{
const BSPEntity& entity = bspLoader.m_entities[i];
const char* cl = bspLoader.ValueForKey(&entity,"classname");
if ( !strcmp( cl, "trigger_push" ) ) {
SimdVector3 targetLocation(0.f,0.f,0.f);
cl = bspLoader.ValueForKey(&entity,"target");
if ( strcmp( cl, "" ) ) {
//its not empty so ...
//lookup the target position for the jumppad:
const BSPEntity* targetentity = bspLoader.getEntityByValue( "targetname" , cl );
if (targetentity)
{
if (bspLoader.GetVectorForKey( targetentity , "origin",&targetLocation[0]))
{
}
}
cl = bspLoader.ValueForKey(&entity,"model");
if ( strcmp( cl, "" ) ) {
// add the model as a brush
if (cl[0] == '*')
{
int modelnr = atoi(&cl[1]);
if ((modelnr >=0) && (modelnr < bspLoader.m_nummodels))
{
const BSPModel& model = bspLoader.m_dmodels[modelnr];
for (int n=0;n<model.numBrushes;n++)
{
std::vector<SimdVector3> planeEquations;
bool isValidBrush = false;
//convert brush
const BSPBrush& brush = bspLoader.m_dbrushes[model.firstBrush+n];
{
for (int p=0;p<brush.numSides;p++)
{
int sideid = brush.firstSide+p;
BSPBrushSide& brushside = bspLoader.m_dbrushsides[sideid];
int planeid = brushside.planeNum;
BSPPlane& plane = bspLoader.m_dplanes[planeid];
SimdVector3 planeEq;
planeEq.setValue(
plane.normal[0],
plane.normal[1],
plane.normal[2],
scaling*-plane.dist);
planeEquations.push_back(planeEq);
isValidBrush=true;
}
if (isValidBrush)
{
std::vector<SimdVector3> vertices;
getVerticesFromPlaneEquations(planeEquations,vertices);
bool isEntity=true;
AddConvexVerticesCollider(vertices,isEntity,targetLocation);
}
}
}
}
}
else
{
printf("unsupported trigger_push model, md3 ?\n");
}
}
}
}
}
}
#endif //USE_ENTITIES
//progressEnd();
}
}
void BspConverter::getVerticesFromPlaneEquations(const std::vector<SimdVector3>& planeEquations , std::vector<SimdVector3>& verticesOut )
{
float minimumDotProduct = 1e30f;
const int numbrushes = planeEquations.size();
// brute force:
for (int i=0;i<numbrushes;i++)
{
const SimdVector3& N1 = planeEquations[i];
for (int j=i+1;j<numbrushes;j++)
{
const SimdVector3& N2 = planeEquations[j];
for (int k=j+1;k<numbrushes;k++)
{
const SimdVector3& N3 = planeEquations[k];
SimdVector3 n2n3; n2n3 = N2.cross(N3);
SimdVector3 n3n1; n3n1 = N3.cross(N1);
SimdVector3 n1n2; n1n2 = N1.cross(N2);
if ( ( n2n3.length2() > 0.0001f ) &&
( n3n1.length2() > 0.0001f ) &&
( n1n2.length2() > 0.0001f ) )
{
//point P out of 3 plane equations:
// d1 ( N2 * N3 ) + d2 ( N3 * N1 ) + d3 ( N1 * N2 )
//P = -------------------------------------------------------------------------
// N1 . ( N2 * N3 )
float quotient = (N1.dot(n2n3));
if (SimdFabs(quotient) > 0.000001f)
{
quotient = -1.f / quotient;
n2n3 *= N1[3];
n3n1 *= N2[3];
n1n2 *= N3[3];
SimdVector3 potentialVertex = n2n3;
potentialVertex += n3n1;
potentialVertex += n1n2;
potentialVertex *= quotient;
//check if inside, and replace supportingVertexOut if needed
if (isInside(planeEquations,potentialVertex,0.1f))
{
verticesOut.push_back(potentialVertex);
}
}
}
}
}
}
}
bool BspConverter::isInside(const std::vector<SimdVector3>& planeEquations, const SimdVector3& point, float margin)
{
int numbrushes = planeEquations.size();
for (int i=0;i<numbrushes;i++)
{
const SimdVector3& N1 = planeEquations[i];
float dist = float(N1.dot(point))+float(N1[3])-margin;
if (dist>0.f)
{
return false;
}
}
return true;
}

View File

@@ -0,0 +1,40 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BSP_CONVERTER_H
#define BSP_CONVERTER_H
class BspLoader;
#include <vector>
#include "SimdVector3.h"
///BspConverter turns a loaded bsp level into convex parts (vertices)
class BspConverter
{
public:
void convertBsp(BspLoader& bspLoader,float scaling);
///Utility function to create vertices from a Quake Brush. Brute force but it works.
///Bit overkill to use QHull package
void getVerticesFromPlaneEquations(const std::vector<SimdVector3>& planeEquations , std::vector<SimdVector3>& verticesOut );
bool isInside(const std::vector<SimdVector3>& planeEquations, const SimdVector3& point, float margin);
///this callback is called for each brush that succesfully converted into vertices
virtual void AddConvexVerticesCollider(std::vector<SimdVector3>& vertices, bool isEntity, const SimdVector3& entityTargetLocation) = 0;
};
#endif //BSP_CONVERTER_H

945
Demos/BspDemo/BspDemo.cpp Normal file
View File

@@ -0,0 +1,945 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "CcdPhysicsEnvironment.h"
#include "CcdPhysicsController.h"
//#include "GL_LineSegmentShape.h"
#include "CollisionShapes/BoxShape.h"
#include "CollisionShapes/SphereShape.h"
#include "CollisionShapes/CylinderShape.h"
#include "CollisionShapes/ConeShape.h"
#include "CollisionShapes/StaticPlaneShape.h"
#include "CollisionShapes/ConvexHullShape.h"
#include "CollisionShapes/TriangleMesh.h"
#include "CollisionShapes/ConvexTriangleMeshShape.h"
#include "CollisionShapes/TriangleMeshShape.h"
#include "CollisionShapes/TriangleIndexVertexArray.h"
#include "CollisionShapes/CompoundShape.h"
extern SimdVector3 gCameraUp;
extern int gForwardAxis;
#include "CollisionShapes/Simplex1to4Shape.h"
#include "CollisionShapes/EmptyShape.h"
#include "Dynamics/RigidBody.h"
#include "CollisionDispatch/CollisionDispatcher.h"
#include "BroadphaseCollision/SimpleBroadphase.h"
#include "BroadphaseCollision/AxisSweep3.h"
#include "ConstraintSolver/Point2PointConstraint.h"
#include "ConstraintSolver/HingeConstraint.h"
#include "quickprof.h"
#include "IDebugDraw.h"
#include "GLDebugDrawer.h"
#define QUAKE_BSP_IMPORTING 1
#ifdef QUAKE_BSP_IMPORTING
#include "BspLoader.h"
#include "BspConverter.h"
#endif //QUAKE_BSP_IMPORTING
#include "PHY_Pro.h"
#include "BMF_Api.h"
#include <stdio.h> //printf debugging
float deltaTime = 1.f/60.f;
float bulletSpeed = 40.f;
#ifdef WIN32
#if _MSC_VER >= 1310
//only use SIMD Hull code under Win32
#define USE_HULL 1
#include "NarrowPhaseCollision/Hull.h"
#endif //_MSC_VER
#endif //WIN32
#ifdef WIN32 //needed for glut.h
#include <windows.h>
#endif
//think different
#if defined(__APPLE__) && !defined (VMDMESA)
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include "GL_ShapeDrawer.h"
#include "GlutStuff.h"
extern float eye[3];
extern int glutScreenWidth;
extern int glutScreenHeight;
int numObjects = 0;
const int maxNumObjects = 450;
SimdTransform startTransforms[maxNumObjects];
DefaultMotionState ms[maxNumObjects];
CcdPhysicsController* physObjects[maxNumObjects] = {0,0,0,0};
CcdPhysicsEnvironment* physicsEnvironmentPtr = 0;
#define CUBE_HALF_EXTENTS 1
#define EXTRA_HEIGHT -20.f
CollisionShape* gShapePtr[maxNumObjects];//1 rigidbody has 1 shape (no re-use of shapes)
////////////////////////////////////
///Very basic import
CcdPhysicsController* CreatePhysicsObject(bool isDynamic, float mass, const SimdTransform& startTransform,CollisionShape* shape)
{
startTransforms[numObjects] = startTransform;
PHY_ShapeProps shapeProps;
shapeProps.m_do_anisotropic = false;
shapeProps.m_do_fh = false;
shapeProps.m_do_rot_fh = false;
shapeProps.m_friction_scaling[0] = 1.;
shapeProps.m_friction_scaling[1] = 1.;
shapeProps.m_friction_scaling[2] = 1.;
shapeProps.m_inertia = 1.f;
shapeProps.m_lin_drag = 0.2f;
shapeProps.m_ang_drag = 0.1f;
shapeProps.m_mass = 10.0f;
PHY_MaterialProps materialProps;
materialProps.m_friction = 10.5f;
materialProps.m_restitution = 0.0f;
CcdConstructionInfo ccdObjectCi;
ccdObjectCi.m_friction = 0.5f;
ccdObjectCi.m_linearDamping = shapeProps.m_lin_drag;
ccdObjectCi.m_angularDamping = shapeProps.m_ang_drag;
SimdTransform tr;
tr.setIdentity();
int i = numObjects;
{
gShapePtr[i] = shape;
shapeProps.m_shape = gShapePtr[i];
shapeProps.m_shape->SetMargin(0.05f);
SimdQuaternion orn = startTransform.getRotation();
ms[i].setWorldOrientation(orn[0],orn[1],orn[2],orn[3]);
ms[i].setWorldPosition(startTransform.getOrigin().getX(),startTransform.getOrigin().getY(),startTransform.getOrigin().getZ());
ccdObjectCi.m_MotionState = &ms[i];
ccdObjectCi.m_gravity = SimdVector3(0,-9.8,0);
ccdObjectCi.m_localInertiaTensor =SimdVector3(0,0,0);
if (!isDynamic)
{
shapeProps.m_mass = 0.f;
ccdObjectCi.m_mass = shapeProps.m_mass;
ccdObjectCi.m_collisionFlags = CollisionObject::isStatic;
}
else
{
shapeProps.m_mass = mass;
ccdObjectCi.m_mass = shapeProps.m_mass;
ccdObjectCi.m_collisionFlags = 0;
}
SimdVector3 localInertia(0.f,0.f,0.f);
if (isDynamic)
{
gShapePtr[i]->CalculateLocalInertia(shapeProps.m_mass,localInertia);
}
ccdObjectCi.m_localInertiaTensor = localInertia;
ccdObjectCi.m_collisionShape = gShapePtr[i];
physObjects[i]= new CcdPhysicsController( ccdObjectCi);
// Only do CCD if motion in one timestep (1.f/60.f) exceeds CUBE_HALF_EXTENTS
physObjects[i]->GetRigidBody()->m_ccdSquareMotionTreshold = 0.f;
//Experimental: better estimation of CCD Time of Impact:
//physObjects[i]->GetRigidBody()->m_ccdSweptShereRadius = 0.5*CUBE_HALF_EXTENTS;
physicsEnvironmentPtr->addCcdPhysicsController( physObjects[i]);
}
//return newly created PhysicsController
return physObjects[numObjects++];
}
///BspToBulletConverter extends the BspConverter to convert to Bullet datastructures
class BspToBulletConverter : public BspConverter
{
public:
virtual void AddConvexVerticesCollider(std::vector<SimdVector3>& vertices, bool isEntity, const SimdVector3& entityTargetLocation)
{
///perhaps we can do something special with entities (isEntity)
///like adding a collision Triggering (as example)
if (vertices.size() > 0)
{
bool isDynamic = false;
float mass = 0.f;
SimdTransform startTransform;
//can use a shift
startTransform.setIdentity();
startTransform.setOrigin(SimdVector3(0,0,-10.f));
//this create an internal copy of the vertices
CollisionShape* shape = new ConvexHullShape(&vertices[0],vertices.size());
CreatePhysicsObject(isDynamic, mass, startTransform,shape);
}
}
};
////////////////////////////////////
GLDebugDrawer debugDrawer;
char* makeExeToBspFilename(const char* lpCmdLine);
char* getLastFileName();
int main(int argc,char** argv)
{
char* bspfilename = "BspDemo.bsp";
printf("argc=%i\n",argc);
{
for (int i=0;i<argc;i++)
{
printf("argv[%i]=%s\n",i,argv[i]);
}
bspfilename = makeExeToBspFilename(argv[0]);
printf("new name=%s\n",bspfilename);
}
if (argc>1)
{
bspfilename = argv[1];
}
gCameraUp = SimdVector3(0,0,1);
gForwardAxis = 1;
///Setup a Physics Simulation Environment
CollisionDispatcher* dispatcher = new CollisionDispatcher();
SimdVector3 worldAabbMin(-10000,-10000,-10000);
SimdVector3 worldAabbMax(10000,10000,10000);
OverlappingPairCache* broadphase = new AxisSweep3(worldAabbMin,worldAabbMax);
//BroadphaseInterface* broadphase = new SimpleBroadphase();
physicsEnvironmentPtr = new CcdPhysicsEnvironment(dispatcher,broadphase);
physicsEnvironmentPtr->setDeactivationTime(2.f);
physicsEnvironmentPtr->setGravity(0,0,-10);
physicsEnvironmentPtr->setDebugDrawer(&debugDrawer);
#ifdef QUAKE_BSP_IMPORTING
void* memoryBuffer = 0;
FILE* file = fopen(bspfilename,"r");
if (!file)
{
//try again other path,
//sight... visual studio leaves the current working directory in the projectfiles folder
//instead of executable folder. who wants this default behaviour?!?
bspfilename = "../../bsptest.bsp";
file = fopen(bspfilename,"r");
}
if (file)
{
BspLoader bspLoader;
int size=0;
if (fseek(file, 0, SEEK_END) || (size = ftell(file)) == EOF || fseek(file, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
printf("Error: cannot get filesize from %s\n", bspfilename);
} else
{
//how to detect file size?
memoryBuffer = malloc(size+1);
fread(memoryBuffer,1,size,file);
bspLoader.LoadBSPFile( memoryBuffer);
BspToBulletConverter bsp2bullet;
float bspScaling = 0.1f;
bsp2bullet.convertBsp(bspLoader,bspScaling);
}
fclose(file);
}
#endif
clientResetScene();
setCameraDistance(22.f);
return glutmain(argc, argv,640,480,"Bullet Quake BSP Physics Viewer http://bullet.sourceforge.net");
}
//to be implemented by the demo
void renderme()
{
debugDrawer.SetDebugMode(getDebugMode());
float m[16];
int i;
if (getDebugMode() & IDebugDraw::DBG_DisableBulletLCP)
{
//don't use Bullet, use quickstep
physicsEnvironmentPtr->setSolverType(0);
} else
{
//Bullet LCP solver
physicsEnvironmentPtr->setSolverType(1);
}
if (getDebugMode() & IDebugDraw::DBG_EnableCCD)
{
physicsEnvironmentPtr->setCcdMode(3);
} else
{
physicsEnvironmentPtr->setCcdMode(0);
}
bool isSatEnabled = (getDebugMode() & IDebugDraw::DBG_EnableSatComparison);
physicsEnvironmentPtr->EnableSatCollisionDetection(isSatEnabled);
for (i=0;i<numObjects;i++)
{
SimdTransform transA;
transA.setIdentity();
float pos[3];
float rot[4];
ms[i].getWorldPosition(pos[0],pos[1],pos[2]);
ms[i].getWorldOrientation(rot[0],rot[1],rot[2],rot[3]);
SimdQuaternion q(rot[0],rot[1],rot[2],rot[3]);
transA.setRotation(q);
SimdPoint3 dpos;
dpos.setValue(pos[0],pos[1],pos[2]);
transA.setOrigin( dpos );
transA.getOpenGLMatrix( m );
SimdVector3 wireColor(1.f,1.0f,0.5f); //wants deactivation
if (i & 1)
{
wireColor = SimdVector3(0.f,0.0f,1.f);
}
///color differently for active, sleeping, wantsdeactivation states
if (physObjects[i]->GetRigidBody()->GetActivationState() == 1) //active
{
if (i & 1)
{
wireColor += SimdVector3 (1.f,0.f,0.f);
} else
{
wireColor += SimdVector3 (.5f,0.f,0.f);
}
}
if (physObjects[i]->GetRigidBody()->GetActivationState() == 2) //ISLAND_SLEEPING
{
if (i & 1)
{
wireColor += SimdVector3 (0.f,1.f, 0.f);
} else
{
wireColor += SimdVector3 (0.f,0.5f,0.f);
}
}
char extraDebug[125];
sprintf(extraDebug,"islandId=%i, Body=%i, ShapeType=%s",physObjects[i]->GetRigidBody()->m_islandTag1,physObjects[i]->GetRigidBody()->m_debugBodyId,physObjects[i]->GetRigidBody()->GetCollisionShape()->GetName());
physObjects[i]->GetRigidBody()->GetCollisionShape()->SetExtraDebugInfo(extraDebug);
GL_ShapeDrawer::DrawOpenGL(m,physObjects[i]->GetRigidBody()->GetCollisionShape(),wireColor,getDebugMode());
///this block is just experimental code to show some internal issues with replacing shapes on the fly.
if (getDebugMode()!=0 && (i>0))
{
if (physObjects[i]->GetRigidBody()->GetCollisionShape()->GetShapeType() == EMPTY_SHAPE_PROXYTYPE)
{
physObjects[i]->GetRigidBody()->SetCollisionShape(gShapePtr[1]);
//remove the persistent collision pairs that were created based on the previous shape
BroadphaseProxy* bpproxy = physObjects[i]->GetRigidBody()->m_broadphaseHandle;
physicsEnvironmentPtr->GetBroadphase()->CleanProxyFromPairs(bpproxy);
SimdVector3 newinertia;
SimdScalar newmass = 10.f;
physObjects[i]->GetRigidBody()->GetCollisionShape()->CalculateLocalInertia(newmass,newinertia);
physObjects[i]->GetRigidBody()->setMassProps(newmass,newinertia);
physObjects[i]->GetRigidBody()->updateInertiaTensor();
}
}
}
if (!(getDebugMode() & IDebugDraw::DBG_NoHelpText))
{
float xOffset = 10.f;
float yStart = 20.f;
float yIncr = -2.f;
SimdVector3 offset(xOffset,0,0);
SimdVector3 up = gCameraUp;
char buf[124];
glColor3f(0, 0, 0);
#ifdef USE_QUICKPROF
if ( getDebugMode() & IDebugDraw::DBG_ProfileTimings)
{
static int counter = 0;
counter++;
std::map<std::string, hidden::ProfileBlock*>::iterator iter;
for (iter = Profiler::mProfileBlocks.begin(); iter != Profiler::mProfileBlocks.end(); ++iter)
{
char blockTime[128];
sprintf(blockTime, "%s: %lf",&((*iter).first[0]),Profiler::getBlockTime((*iter).first, Profiler::BLOCK_CYCLE_SECONDS));//BLOCK_TOTAL_PERCENT));
glRasterPos3f(xOffset,yStart,0);
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),blockTime);
yStart += yIncr;
}
}
#endif //USE_QUICKPROF
//profiling << Profiler::createStatsString(Profiler::BLOCK_TOTAL_PERCENT);
//<< std::endl;
SimdVector3 textPos = offset + up*yStart;
glRasterPos3f(textPos.getX(),textPos.getY(),textPos.getZ());
sprintf(buf,"leftmouse to pick");
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
yStart += yIncr;
textPos = offset + up*yStart;
glRasterPos3f(textPos.getX(),textPos.getY(),textPos.getZ());
sprintf(buf,"rightmouse or . to shoot box");
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
yStart += yIncr;
textPos = offset + up*yStart;
glRasterPos3f(textPos.getX(),textPos.getY(),textPos.getZ());
sprintf(buf,"space to reset");
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
yStart += yIncr;
textPos = offset + up*yStart;
glRasterPos3f(textPos.getX(),textPos.getY(),textPos.getZ());
sprintf(buf,"cursor keys and z,x to navigate");
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
yStart += yIncr;
textPos = offset + up*yStart ;
glRasterPos3f(textPos.getX(),textPos.getY(),textPos.getZ());
sprintf(buf,"i to toggle simulation, s single step");
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
yStart += yIncr;
textPos = offset + up*yStart ;
glRasterPos3f(textPos.getX(),textPos.getY(),textPos.getZ());
sprintf(buf,"q to quit");
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
yStart += yIncr;
textPos = offset + up*yStart ;
glRasterPos3f(textPos.getX(),textPos.getY(),textPos.getZ());
sprintf(buf,"d to toggle deactivation");
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
yStart += yIncr;
textPos = offset + up*yStart ;
glRasterPos3f(textPos.getX(),textPos.getY(),textPos.getZ());
sprintf(buf,"a to draw temporal AABBs");
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
yStart += yIncr;
textPos = offset + up*yStart ;
glRasterPos3f(textPos.getX(),textPos.getY(),textPos.getZ());
sprintf(buf,"c to show contact points (wireframe more)");
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
yStart += yIncr;
textPos = offset + up*yStart ;
glRasterPos3f(textPos.getX(),textPos.getY(),textPos.getZ());
sprintf(buf,"h to toggle help text");
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
yStart += yIncr;
bool useBulletLCP = !(getDebugMode() & IDebugDraw::DBG_DisableBulletLCP);
bool useCCD = (getDebugMode() & IDebugDraw::DBG_EnableCCD);
textPos = offset + up*yStart ;
glRasterPos3f(textPos.getX(),textPos.getY(),textPos.getZ());
sprintf(buf,"m Bullet GJK = %i",!isSatEnabled);
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
yStart += yIncr;
textPos = offset + up*yStart ;
glRasterPos3f(textPos.getX(),textPos.getY(),textPos.getZ());
sprintf(buf,"n Bullet LCP = %i",useBulletLCP);
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
yStart += yIncr;
textPos = offset + up*yStart ;
glRasterPos3f(textPos.getX(),textPos.getY(),textPos.getZ());
sprintf(buf,"1 CCD mode (adhoc) = %i",useCCD);
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
yStart += yIncr;
textPos = offset + up*yStart ;
glRasterPos3f(textPos.getX(),textPos.getY(),textPos.getZ());
sprintf(buf,"+- shooting speed = %10.2f",bulletSpeed);
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
yStart += yIncr;
}
}
void clientMoveAndDisplay()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
physicsEnvironmentPtr->proceedDeltaTime(0.f,deltaTime);
renderme();
glFlush();
glutSwapBuffers();
}
void clientDisplay(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
physicsEnvironmentPtr->UpdateAabbs(deltaTime);
renderme();
glFlush();
glutSwapBuffers();
}
///make this positive to show stack falling from a distance
///this shows the penalty tresholds in action, springy/spungy look
void clientResetScene()
{
for (int i=0;i<numObjects;i++)
{
ms[i].m_worldTransform = startTransforms[i];
physObjects[i]->setPosition(startTransforms[i].getOrigin().getX(),startTransforms[i].getOrigin().getY(),startTransforms[i].getOrigin().getZ());
physObjects[i]->SetLinearVelocity(0,0,0,0);
physObjects[i]->SetAngularVelocity(0,0,0,0);
SimdQuaternion orn;
startTransforms[i].getBasis().getRotation(orn);
physObjects[i]->setOrientation(orn.x(),orn.y(),orn.z(),orn[3]);
}
//delete and reload, or keep transforms ready?
}
void shootBox(const SimdVector3& destination)
{
bool isDynamic = true;
float mass = 1.f;
SimdTransform startTransform;
startTransform.setIdentity();
startTransform.setOrigin(SimdVector3(eye[0],eye[1],eye[2]));
CollisionShape* boxShape = new BoxShape(SimdVector3(1.f,1.f,1.f));
CreatePhysicsObject(isDynamic, mass, startTransform,boxShape);
int i = numObjects-1;
SimdVector3 linVel(destination[0]-eye[0],destination[1]-eye[1],destination[2]-eye[2]);
linVel.normalize();
linVel*=bulletSpeed;
physObjects[i]->setPosition(eye[0],eye[1],eye[2]);
physObjects[i]->setOrientation(0,0,0,1);
physObjects[i]->SetLinearVelocity(linVel[0],linVel[1],linVel[2],false);
physObjects[i]->SetAngularVelocity(0,0,0,false);
}
void clientKeyboard(unsigned char key, int x, int y)
{
if (key == '.')
{
shootBox(SimdVector3(0,0,0));
}
if (key == '+')
{
bulletSpeed += 10.f;
}
if (key == '-')
{
bulletSpeed -= 10.f;
}
defaultKeyboard(key, x, y);
}
int gPickingConstraintId = 0;
SimdVector3 gOldPickingPos;
float gOldPickingDist = 0.f;
RigidBody* pickedBody = 0;//for deactivation state
SimdVector3 GetRayTo(int x,int y)
{
float top = 1.f;
float bottom = -1.f;
float nearPlane = 1.f;
float tanFov = (top-bottom)*0.5f / nearPlane;
float fov = 2.0 * atanf (tanFov);
SimdVector3 rayFrom(eye[0],eye[1],eye[2]);
SimdVector3 rayForward = -rayFrom;
rayForward.normalize();
float farPlane = 600.f;
rayForward*= farPlane;
SimdVector3 rightOffset;
SimdVector3 vertical = gCameraUp;
SimdVector3 hor;
hor = rayForward.cross(vertical);
hor.normalize();
vertical = hor.cross(rayForward);
vertical.normalize();
float tanfov = tanf(0.5f*fov);
hor *= 2.f * farPlane * tanfov;
vertical *= 2.f * farPlane * tanfov;
SimdVector3 rayToCenter = rayFrom + rayForward;
SimdVector3 dHor = hor * 1.f/float(glutScreenWidth);
SimdVector3 dVert = vertical * 1.f/float(glutScreenHeight);
SimdVector3 rayTo = rayToCenter - 0.5f * hor + 0.5f * vertical;
rayTo += x * dHor;
rayTo -= y * dVert;
return rayTo;
}
void clientMouseFunc(int button, int state, int x, int y)
{
//printf("button %i, state %i, x=%i,y=%i\n",button,state,x,y);
//button 0, state 0 means left mouse down
SimdVector3 rayTo = GetRayTo(x,y);
switch (button)
{
case 2:
{
if (state==0)
{
shootBox(rayTo);
}
break;
};
case 1:
{
if (state==0)
{
//apply an impulse
if (physicsEnvironmentPtr)
{
float hit[3];
float normal[3];
PHY_IPhysicsController* hitObj = physicsEnvironmentPtr->rayTest(0,eye[0],eye[1],eye[2],rayTo.getX(),rayTo.getY(),rayTo.getZ(),hit[0],hit[1],hit[2],normal[0],normal[1],normal[2]);
if (hitObj)
{
CcdPhysicsController* physCtrl = static_cast<CcdPhysicsController*>(hitObj);
RigidBody* body = physCtrl->GetRigidBody();
if (body)
{
body->SetActivationState(ACTIVE_TAG);
SimdVector3 impulse = rayTo;
impulse.normalize();
float impulseStrength = 10.f;
impulse *= impulseStrength;
SimdVector3 relPos(
hit[0] - body->getCenterOfMassPosition().getX(),
hit[1] - body->getCenterOfMassPosition().getY(),
hit[2] - body->getCenterOfMassPosition().getZ());
body->applyImpulse(impulse,relPos);
}
}
}
} else
{
}
break;
}
case 0:
{
if (state==0)
{
//add a point to point constraint for picking
if (physicsEnvironmentPtr)
{
float hit[3];
float normal[3];
PHY_IPhysicsController* hitObj = physicsEnvironmentPtr->rayTest(0,eye[0],eye[1],eye[2],rayTo.getX(),rayTo.getY(),rayTo.getZ(),hit[0],hit[1],hit[2],normal[0],normal[1],normal[2]);
if (hitObj)
{
CcdPhysicsController* physCtrl = static_cast<CcdPhysicsController*>(hitObj);
RigidBody* body = physCtrl->GetRigidBody();
if (body && !body->IsStatic())
{
pickedBody = body;
pickedBody->SetActivationState(DISABLE_DEACTIVATION);
SimdVector3 pickPos(hit[0],hit[1],hit[2]);
SimdVector3 localPivot = body->getCenterOfMassTransform().inverse() * pickPos;
gPickingConstraintId = physicsEnvironmentPtr->createConstraint(physCtrl,0,PHY_POINT2POINT_CONSTRAINT,
localPivot.getX(),
localPivot.getY(),
localPivot.getZ(),
0,0,0);
//printf("created constraint %i",gPickingConstraintId);
//save mouse position for dragging
gOldPickingPos = rayTo;
SimdVector3 eyePos(eye[0],eye[1],eye[2]);
gOldPickingDist = (pickPos-eyePos).length();
Point2PointConstraint* p2p = static_cast<Point2PointConstraint*>(physicsEnvironmentPtr->getConstraintById(gPickingConstraintId));
if (p2p)
{
//very weak constraint for picking
p2p->m_setting.m_tau = 0.1f;
}
}
}
}
} else
{
if (gPickingConstraintId && physicsEnvironmentPtr)
{
physicsEnvironmentPtr->removeConstraint(gPickingConstraintId);
//printf("removed constraint %i",gPickingConstraintId);
gPickingConstraintId = 0;
pickedBody->ForceActivationState(ACTIVE_TAG);
pickedBody->m_deactivationTime = 0.f;
pickedBody = 0;
}
}
break;
}
default:
{
}
}
}
void clientMotionFunc(int x,int y)
{
if (gPickingConstraintId && physicsEnvironmentPtr)
{
//move the constraint pivot
Point2PointConstraint* p2p = static_cast<Point2PointConstraint*>(physicsEnvironmentPtr->getConstraintById(gPickingConstraintId));
if (p2p)
{
//keep it at the same picking distance
SimdVector3 newRayTo = GetRayTo(x,y);
SimdVector3 eyePos(eye[0],eye[1],eye[2]);
SimdVector3 dir = newRayTo-eyePos;
dir.normalize();
dir *= gOldPickingDist;
SimdVector3 newPos = eyePos + dir;
p2p->SetPivotB(newPos);
}
}
}
//some code that de-mangles the windows filename passed in as argument
char cleaned_filename[512];
char* getLastFileName()
{
return cleaned_filename;
}
char* makeExeToBspFilename(const char* lpCmdLine)
{
// We might get a windows-style path on the command line, this can mess up the DOM which expects
// all paths to be URI's. This block of code does some conversion to try and make the input
// compliant without breaking the ability to accept a properly formatted URI. Right now this only
// displays the first filename
const char *in = lpCmdLine;
char* out = cleaned_filename;
*out = NULL;
// If the first character is a ", skip it (filenames with spaces in them are quoted)
if(*in == '\"')
{
in++;
}
if(*(in+1) == ':')
{
// Second character is a :, assume we have a path with a drive letter and add a slash at the beginning
*(out++) = '/';
}
int i;
for(i =0; i<512; i++)
{
//if we get '.' we stop as well, unless it's the first character. Then we add .bsp as extension
// If we hit a null or a quote, stop copying. This will get just the first filename.
if(i && (*in == '.'))
break;
// If we hit a null or a quote, stop copying. This will get just the first filename.
if(*in == NULL || *in == '\"')
break;
// Copy while swapping backslashes for forward ones
if(*in == '\\')
{
*out = '/';
}
else
{
*out = *in;
}
in++;
out++;
}
*(out++) = '.';
*(out++) = 'b';
*(out++) = 's';
*(out++) = 'p';
*(out++) = 0;
return cleaned_filename;
}

713
Demos/BspDemo/BspLoader.cpp Normal file
View File

@@ -0,0 +1,713 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code 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
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "BspLoader.h"
typedef struct
{
char filename[1024];
char *buffer,*script_p,*end_p;
int line;
} BSPScript;
#define MAX_INCLUDES 8
BSPScript scriptstack[MAX_INCLUDES];
BSPScript *script;
int scriptline;
char token[BSPMAXTOKEN];
bool endofscript;
bool tokenready; // only true if UnGetToken was just called
//
//LoadBSPFile
//
int extrasize = 100;
bool BspLoader::LoadBSPFile( void* memoryBuffer) {
BSPHeader *header = (BSPHeader*) memoryBuffer;
// load the file header
if (header)
{
// swap the header
SwapBlock( (int *)header, sizeof(*header) );
int length = (header->lumps[BSPLUMP_SHADERS].filelen) / sizeof(BSPShader);
m_dshaders.resize(length+extrasize);
m_numShaders = CopyLump( header, BSPLUMP_SHADERS, &m_dshaders[0], sizeof(BSPShader) );
length = (header->lumps[LUMP_MODELS].filelen) / sizeof(BSPModel);
m_dmodels.resize(length+extrasize);
m_nummodels = CopyLump( header, LUMP_MODELS, &m_dmodels[0], sizeof(BSPModel) );
length = (header->lumps[BSPLUMP_PLANES].filelen) / sizeof(BSPPlane);
m_dplanes.resize(length+extrasize);
m_numplanes = CopyLump( header, BSPLUMP_PLANES, &m_dplanes[0], sizeof(BSPPlane) );
length = (header->lumps[BSPLUMP_LEAFS].filelen) / sizeof(BSPLeaf);
m_dleafs.resize(length+extrasize);
m_numleafs = CopyLump( header, BSPLUMP_LEAFS, &m_dleafs[0], sizeof(BSPLeaf) );
length = (header->lumps[BSPLUMP_NODES].filelen) / sizeof(BSPNode);
m_dnodes.resize(length+extrasize);
m_numnodes = CopyLump( header, BSPLUMP_NODES, &m_dnodes[0], sizeof(BSPNode) );
length = (header->lumps[BSPLUMP_LEAFSURFACES].filelen) / sizeof(m_dleafsurfaces[0]);
m_dleafsurfaces.resize(length+extrasize);
m_numleafsurfaces = CopyLump( header, BSPLUMP_LEAFSURFACES, &m_dleafsurfaces[0], sizeof(m_dleafsurfaces[0]) );
length = (header->lumps[BSPLUMP_LEAFBRUSHES].filelen) / sizeof(m_dleafbrushes[0]) ;
m_dleafbrushes.resize(length+extrasize);
m_numleafbrushes = CopyLump( header, BSPLUMP_LEAFBRUSHES, &m_dleafbrushes[0], sizeof(m_dleafbrushes[0]) );
length = (header->lumps[LUMP_BRUSHES].filelen) / sizeof(BSPBrush);
m_dbrushes.resize(length+extrasize);
m_numbrushes = CopyLump( header, LUMP_BRUSHES, &m_dbrushes[0], sizeof(BSPBrush) );
length = (header->lumps[LUMP_BRUSHSIDES].filelen) / sizeof(BSPBrushSide);
m_dbrushsides.resize(length+extrasize);
m_numbrushsides = CopyLump( header, LUMP_BRUSHSIDES, &m_dbrushsides[0], sizeof(BSPBrushSide) );
length = (header->lumps[LUMP_SURFACES].filelen) / sizeof(BSPSurface);
m_drawSurfaces.resize(length+extrasize);
m_numDrawSurfaces = CopyLump( header, LUMP_SURFACES, &m_drawSurfaces[0], sizeof(BSPSurface) );
length = (header->lumps[LUMP_DRAWINDEXES].filelen) / sizeof(m_drawIndexes[0]);
m_drawIndexes.resize(length+extrasize);
m_numDrawIndexes = CopyLump( header, LUMP_DRAWINDEXES, &m_drawIndexes[0], sizeof(m_drawIndexes[0]) );
length = (header->lumps[LUMP_VISIBILITY].filelen) / 1;
m_visBytes.resize(length+extrasize);
m_numVisBytes = CopyLump( header, LUMP_VISIBILITY, &m_visBytes[0], 1 );
length = (header->lumps[LUMP_LIGHTMAPS].filelen) / 1;
m_lightBytes.resize(length+extrasize);
m_numLightBytes = CopyLump( header, LUMP_LIGHTMAPS, &m_lightBytes[0], 1 );
length = (header->lumps[BSPLUMP_ENTITIES].filelen) / 1;
m_dentdata.resize(length+extrasize);
m_entdatasize = CopyLump( header, BSPLUMP_ENTITIES, &m_dentdata[0], 1);
length = (header->lumps[LUMP_LIGHTGRID].filelen) / 1;
m_gridData.resize(length+extrasize);
m_numGridPoints = CopyLump( header, LUMP_LIGHTGRID, &m_gridData[0], 8 );
// swap everything
SwapBSPFile();
return true;
}
return false;
}
const char* BspLoader::ValueForKey( const BSPEntity* ent, const char* key ) const {
const BSPKeyValuePair* ep;
for (ep=ent->epairs ; ep ; ep=ep->next) {
if (!strcmp(ep->key, key) ) {
return ep->value;
}
}
return "";
}
float BspLoader::FloatForKey( const BSPEntity *ent, const char *key ) {
const char *k;
k = ValueForKey( ent, key );
return float(atof(k));
}
bool BspLoader::GetVectorForKey( const BSPEntity *ent, const char *key, BSPVector3 vec ) {
const char *k;
k = ValueForKey (ent, key);
if (strcmp(k, ""))
{
sscanf (k, "%f %f %f", &vec[0], &vec[1], &vec[2]);
return true;
}
return false;
}
/*
==============
ParseFromMemory
==============
*/
void BspLoader::ParseFromMemory (char *buffer, int size)
{
script = scriptstack;
script++;
if (script == &scriptstack[MAX_INCLUDES])
{
//printf("script file exceeded MAX_INCLUDES");
}
strcpy (script->filename, "memory buffer" );
script->buffer = buffer;
script->line = 1;
script->script_p = script->buffer;
script->end_p = script->buffer + size;
endofscript = false;
tokenready = false;
}
bool BspLoader::EndOfScript (bool crossline)
{
if (!crossline)
//printf("Line %i is incomplete\n",scriptline);
if (!strcmp (script->filename, "memory buffer"))
{
endofscript = true;
return false;
}
//free (script->buffer);
if (script == scriptstack+1)
{
endofscript = true;
return false;
}
script--;
scriptline = script->line;
//printf ("returning to %s\n", script->filename);
return GetToken (crossline);
}
/*
==============
GetToken
==============
*/
bool BspLoader::GetToken (bool crossline)
{
char *token_p;
if (tokenready) // is a token allready waiting?
{
tokenready = false;
return true;
}
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
//
// skip space
//
skipspace:
while (*script->script_p <= 32)
{
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
if (*script->script_p++ == '\n')
{
if (!crossline)
{
//printf("Line %i is incomplete\n",scriptline);
}
scriptline = script->line++;
}
}
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
// ; # // comments
if (*script->script_p == ';' || *script->script_p == '#'
|| ( script->script_p[0] == '/' && script->script_p[1] == '/') )
{
if (!crossline)
{
//printf("Line %i is incomplete\n",scriptline);
}
while (*script->script_p++ != '\n')
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
scriptline = script->line++;
goto skipspace;
}
// /* */ comments
if (script->script_p[0] == '/' && script->script_p[1] == '*')
{
if (!crossline)
{
//printf("Line %i is incomplete\n",scriptline);
}
script->script_p+=2;
while (script->script_p[0] != '*' && script->script_p[1] != '/')
{
if ( *script->script_p == '\n' ) {
scriptline = script->line++;
}
script->script_p++;
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
}
script->script_p += 2;
goto skipspace;
}
//
// copy token
//
token_p = token;
if (*script->script_p == '"')
{
// quoted token
script->script_p++;
while (*script->script_p != '"')
{
*token_p++ = *script->script_p++;
if (script->script_p == script->end_p)
break;
if (token_p == &token[BSPMAXTOKEN])
{
//printf ("Token too large on line %i\n",scriptline);
}
}
script->script_p++;
}
else // regular token
while ( *script->script_p > 32 && *script->script_p != ';')
{
*token_p++ = *script->script_p++;
if (script->script_p == script->end_p)
break;
if (token_p == &token[BSPMAXTOKEN])
{
//printf ("Token too large on line %i\n",scriptline);
}
}
*token_p = 0;
if (!strcmp (token, "$include"))
{
//GetToken (false);
//AddScriptToStack (token);
return false;//GetToken (crossline);
}
return true;
}
char *BspLoader::copystring(const char *s)
{
char *b;
b = (char*) malloc( strlen(s)+1);
strcpy (b, s);
return b;
}
void BspLoader::StripTrailing( char *e ) {
char *s;
s = e + strlen(e)-1;
while (s >= e && *s <= 32)
{
*s = 0;
s--;
}
}
/*
=================
ParseEpair
=================
*/
BSPKeyValuePair *BspLoader::ParseEpair( void ) {
BSPKeyValuePair *e;
e = (struct BSPPair*) malloc( sizeof(BSPKeyValuePair));
memset( e, 0, sizeof(BSPKeyValuePair) );
if ( strlen(token) >= BSPMAX_KEY-1 ) {
//printf ("ParseEpar: token too long");
}
e->key = copystring( token );
GetToken( false );
if ( strlen(token) >= BSPMAX_VALUE-1 ) {
//printf ("ParseEpar: token too long");
}
e->value = copystring( token );
// strip trailing spaces that sometimes get accidentally
// added in the editor
StripTrailing( e->key );
StripTrailing( e->value );
return e;
}
/*
================
ParseEntity
================
*/
bool BspLoader::ParseEntity( void ) {
BSPKeyValuePair *e;
BSPEntity *mapent;
if ( !GetToken (true) ) {
return false;
}
if ( strcmp (token, "{") ) {
//printf ("ParseEntity: { not found");
}
BSPEntity bla;
bla.brushes = 0;
bla.epairs = 0;
bla.firstDrawSurf = 0;
bla.origin[0] = 0.f;
bla.origin[1] = 0.f;
bla.origin[2] = 0.f;
bla.patches = 0;
m_entities.push_back(bla);
mapent = &m_entities[m_entities.size()-1];
m_num_entities++;
do {
if ( !GetToken (true) ) {
//printf("ParseEntity: EOF without closing brace");
}
if ( !strcmp (token, "}") ) {
break;
}
e = (struct BSPPair*)ParseEpair ();
e->next = mapent->epairs;
mapent->epairs = e;
} while (1);
return true;
}
/*
================
ParseEntities
Parses the dentdata string into entities
================
*/
void BspLoader::ParseEntities( void ) {
m_num_entities = 0;
m_entities.clear();
ParseFromMemory( &m_dentdata[0], m_entdatasize );
while ( ParseEntity () ) {
}
}
int BspLoader::getMachineEndianness()
{
long int i = 1;
const char *p = (const char *) &i;
if (p[0] == 1) // Lowest address contains the least significant byte
return LITTLE_ENDIAN;
else
return BIG_ENDIAN;
}
short BspLoader::LittleShort (short l)
{
if (machineEndianness() == BSP_BIG_ENDIAN)
{
unsigned char b1,b2;
b1 = l&255;
b2 = (l>>8)&255;
return (b1<<8) + b2;
}
//little endian
return l;
}
short BspLoader::BigShort (short l)
{
if (machineEndianness() == BSP_BIG_ENDIAN)
{
return l;
}
unsigned char b1,b2;
b1 = l&255;
b2 = (l>>8)&255;
return (b1<<8) + b2;
}
int BspLoader::LittleLong (int l)
{
if (machineEndianness() == BSP_BIG_ENDIAN)
{
unsigned char b1,b2,b3,b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}
//little endian
return l;
}
int BspLoader::BigLong (int l)
{
if (machineEndianness() == BSP_BIG_ENDIAN)
{
return l;
}
unsigned char b1,b2,b3,b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}
float BspLoader::LittleFloat (float l)
{
if (machineEndianness() == BSP_BIG_ENDIAN)
{
union {unsigned char b[4]; float f;} in, out;
in.f = l;
out.b[0] = in.b[3];
out.b[1] = in.b[2];
out.b[2] = in.b[1];
out.b[3] = in.b[0];
return out.f;
}
//little endian
return l;
}
float BspLoader::BigFloat (float l)
{
if (machineEndianness() == BSP_BIG_ENDIAN)
{
return l;
}
//little endian
union {unsigned char b[4]; float f;} in, out;
in.f = l;
out.b[0] = in.b[3];
out.b[1] = in.b[2];
out.b[2] = in.b[1];
out.b[3] = in.b[0];
return out.f;
}
//
// SwapBlock
// If all values are 32 bits, this can be used to swap everything
//
void BspLoader::SwapBlock( int *block, int sizeOfBlock ) {
int i;
sizeOfBlock >>= 2;
for ( i = 0 ; i < sizeOfBlock ; i++ ) {
block[i] = LittleLong( block[i] );
}
}
//
// CopyLump
//
int BspLoader::CopyLump( BSPHeader *header, int lump, void *dest, int size ) {
int length, ofs;
length = header->lumps[lump].filelen;
ofs = header->lumps[lump].fileofs;
//if ( length % size ) {
// printf ("LoadBSPFile: odd lump size");
//}
memcpy( dest, (unsigned char *)header + ofs, length );
return length / size;
}
//
// SwapBSPFile
//
void BspLoader::SwapBSPFile( void ) {
int i;
// models
SwapBlock( (int *) &m_dmodels[0], m_nummodels * sizeof( m_dmodels[0] ) );
// shaders (don't swap the name)
for ( i = 0 ; i < m_numShaders ; i++ ) {
m_dshaders[i].contentFlags = LittleLong( m_dshaders[i].contentFlags );
m_dshaders[i].surfaceFlags = LittleLong( m_dshaders[i].surfaceFlags );
}
// planes
SwapBlock( (int *)&m_dplanes[0], m_numplanes * sizeof( m_dplanes[0] ) );
// nodes
SwapBlock( (int *)&m_dnodes[0], m_numnodes * sizeof( m_dnodes[0] ) );
// leafs
SwapBlock( (int *)&m_dleafs[0], m_numleafs * sizeof( m_dleafs[0] ) );
// leaffaces
SwapBlock( (int *)&m_dleafsurfaces[0], m_numleafsurfaces * sizeof( m_dleafsurfaces[0] ) );
// leafbrushes
SwapBlock( (int *)&m_dleafbrushes[0], m_numleafbrushes * sizeof( m_dleafbrushes[0] ) );
// brushes
SwapBlock( (int *)&m_dbrushes[0], m_numbrushes * sizeof( m_dbrushes[0] ) );
// brushsides
SwapBlock( (int *)&m_dbrushsides[0], m_numbrushsides * sizeof( m_dbrushsides[0] ) );
// vis
((int *)&m_visBytes)[0] = LittleLong( ((int *)&m_visBytes)[0] );
((int *)&m_visBytes)[1] = LittleLong( ((int *)&m_visBytes)[1] );
// drawindexes
SwapBlock( (int *)&m_drawIndexes[0], m_numDrawIndexes * sizeof( m_drawIndexes[0] ) );
// drawsurfs
SwapBlock( (int *)&m_drawSurfaces[0], m_numDrawSurfaces * sizeof( m_drawSurfaces[0] ) );
}
bool BspLoader::findVectorByName(float* outvec,const char* name)
{
const char *cl;
BSPVector3 origin;
bool found = false;
ParseEntities();
for ( int i = 1; i < m_num_entities; i++ ) {
cl = ValueForKey (&m_entities[i], "classname");
if ( !strcmp( cl, "info_player_start" ) ) {
GetVectorForKey( &m_entities[i], "origin", origin );
found = true;
break;
}
if ( !strcmp( cl, "info_player_deathmatch" ) ) {
GetVectorForKey( &m_entities[i], "origin", origin );
found = true;
break;
}
}
if (found)
{
outvec[0] = origin[0];
outvec[1] = origin[1];
outvec[2] = origin[2];
}
return found;
}
const BSPEntity * BspLoader::getEntityByValue( const char* name, const char* value)
{
const BSPEntity* entity = NULL;
for ( int i = 1; i < m_num_entities; i++ ) {
const BSPEntity& ent = m_entities[i];
const char* cl = ValueForKey (&m_entities[i], name);
if ( !strcmp( cl, value ) ) {
entity = &ent;
break;
}
}
return entity;
}

304
Demos/BspDemo/BspLoader.h Normal file
View File

@@ -0,0 +1,304 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code 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
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifndef BSP_LOADER_H
#define BSP_LOADER_H
#define BSPMAXTOKEN 1024
#define BSPMAX_KEY 32
#define BSPMAX_VALUE 1024
#define BSPCONTENTS_SOLID 1
#define BSPCONTENTS_AREAPORTAL 0x8000
#define BSPLUMP_ENTITIES 0
#define BSPLUMP_SHADERS 1
#define BSPLUMP_PLANES 2
#define BSPLUMP_NODES 3
#define BSPLUMP_LEAFS 4
#define BSPLUMP_LEAFSURFACES 5
#define BSPLUMP_LEAFBRUSHES 6
#define LUMP_MODELS 7
#define LUMP_BRUSHES 8
#define LUMP_BRUSHSIDES 9
#define LUMP_DRAWVERTS 10
#define LUMP_DRAWINDEXES 11
#define LUMP_SURFACES 13
#define LUMP_LIGHTMAPS 14
#define LUMP_LIGHTGRID 15
#define LUMP_VISIBILITY 16
#define HEADER_LUMPS 17
#define MAX_QPATH 64
#include <vector>
typedef struct {
int fileofs, filelen;
} BSPLump;
typedef float BSPVector3[3];
typedef struct {
int ident;
int version;
BSPLump lumps[HEADER_LUMPS];
} BSPHeader;
typedef struct {
float mins[3], maxs[3];
int firstSurface, numSurfaces;
int firstBrush, numBrushes;
} BSPModel;
typedef struct {
char shader[MAX_QPATH];
int surfaceFlags;
int contentFlags;
} BSPShader;
typedef struct {
float normal[3];
float dist;
} BSPPlane;
typedef struct {
int planeNum;
int children[2];
int mins[3];
int maxs[3];
} BSPNode;
typedef struct {
int cluster;
int area;
int mins[3];
int maxs[3];
int firstLeafSurface;
int numLeafSurfaces;
int firstLeafBrush;
int numLeafBrushes;
} BSPLeaf;
typedef struct {
int planeNum;
int shaderNum;
} BSPBrushSide;
typedef struct {
int firstSide;
int numSides;
int shaderNum;
} BSPBrush;
typedef struct BSPPair {
struct BSPPair *next;
char *key;
char *value;
} BSPKeyValuePair;
typedef struct {
BSPVector3 origin;
struct bspbrush_s *brushes;
struct parseMesh_s *patches;
int firstDrawSurf;
BSPKeyValuePair *epairs;
} BSPEntity;
typedef enum {
MST_BAD,
MST_PLANAR,
MST_PATCH,
MST_TRIANGLE_SOUP,
MST_FLARE
} BSPMapSurface;
typedef struct {
int shaderNum;
int fogNum;
int surfaceType;
int firstVert;
int numVerts;
int firstIndex;
int numIndexes;
int lightmapNum;
int lightmapX, lightmapY;
int lightmapWidth, lightmapHeight;
BSPVector3 lightmapOrigin;
BSPVector3 lightmapVecs[3];
int patchWidth;
int patchHeight;
} BSPSurface;
///GPL code from IdSofware to parse a Quake 3 BSP file
///check that your platform define __BIG_ENDIAN__ correctly (in BspLoader.cpp)
class BspLoader
{
int m_Endianness;
public:
BspLoader()
:m_num_entities(0)
{
m_Endianness = getMachineEndianness();
if (m_Endianness == BSP_BIG_ENDIAN)
{
printf("Machine is BIG_ENDIAN\n");
} else
{
printf("Machine is Little Endian\n");
}
}
bool LoadBSPFile( void* memoryBuffer);
const char* ValueForKey( const BSPEntity *ent, const char *key ) const;
bool GetVectorForKey( const BSPEntity *ent, const char *key, BSPVector3 vec );
float FloatForKey( const BSPEntity *ent, const char *key );
void ParseEntities( void );
bool findVectorByName(float* outvec,const char* name);
const BSPEntity * getEntityByValue( const char* name, const char* value);
protected:
void ParseFromMemory (char *buffer, int size);
bool EndOfScript (bool crossline);
bool GetToken (bool crossline);
char *copystring(const char *s);
void StripTrailing( char *e );
BSPKeyValuePair * ParseEpair( void );
bool ParseEntity( void );
short LittleShort (short l);
int LittleLong (int l);
float LittleFloat (float l);
int BigLong (int l);
short BigShort (short l);
float BigFloat (float l);
void SwapBlock( int *block, int sizeOfBlock );
int CopyLump( BSPHeader *header, int lump, void *dest, int size );
void SwapBSPFile( void );
public: //easier for conversion
int m_num_entities;
std::vector<BSPEntity> m_entities;
int m_nummodels;
std::vector<BSPModel> m_dmodels;
int m_numShaders;
std::vector<BSPShader> m_dshaders;
int m_entdatasize;
std::vector<char> m_dentdata;
int m_numleafs;
std::vector<BSPLeaf> m_dleafs;
int m_numplanes;
std::vector<BSPPlane> m_dplanes;
int m_numnodes;
std::vector<BSPNode> m_dnodes;
int m_numleafsurfaces;
std::vector<int> m_dleafsurfaces;
int m_numleafbrushes;
std::vector<int> m_dleafbrushes;
int m_numbrushes;
std::vector<BSPBrush> m_dbrushes;
int m_numbrushsides;
std::vector<BSPBrushSide> m_dbrushsides;
int m_numLightBytes;
std::vector<unsigned char> m_lightBytes;
int m_numGridPoints;
std::vector<unsigned char> m_gridData;
int m_numVisBytes;
std::vector<unsigned char> m_visBytes;
int m_numDrawIndexes;
std::vector<int> m_drawIndexes;
int m_numDrawSurfaces;
std::vector<BSPSurface> m_drawSurfaces;
enum
{
BSP_LITTLE_ENDIAN = 0,
BSP_BIG_ENDIAN = 1,
};
//returns machines big endian / little endian
//
int getMachineEndianness();
inline int machineEndianness()
{
return m_Endianness;
}
};
#endif //BSP_LOADER_H

3
Demos/BspDemo/Jamfile Normal file
View File

@@ -0,0 +1,3 @@
SubDir TOP Demos BspDemo ;
ExtraDemo BspDemo : [ Wildcard *.h *.cpp ] ;

View File

@@ -1,2 +1,2 @@
SUBDIRS( OpenGL CcdPhysicsDemo )
SUBDIRS( OpenGL CcdPhysicsDemo BspDemo )

View File

@@ -458,7 +458,7 @@ int BspLoader::getMachineEndianness()
short BspLoader::LittleShort (short l)
{
if (machineEndianness() == BIG_ENDIAN)
if (machineEndianness() == BSP_BIG_ENDIAN)
{
unsigned char b1,b2;
@@ -473,7 +473,7 @@ short BspLoader::LittleShort (short l)
short BspLoader::BigShort (short l)
{
if (machineEndianness() == BIG_ENDIAN)
if (machineEndianness() == BSP_BIG_ENDIAN)
{
return l;
}
@@ -492,7 +492,7 @@ short BspLoader::BigShort (short l)
int BspLoader::LittleLong (int l)
{
if (machineEndianness() == BIG_ENDIAN)
if (machineEndianness() == BSP_BIG_ENDIAN)
{
unsigned char b1,b2,b3,b4;
@@ -511,7 +511,7 @@ int BspLoader::LittleLong (int l)
int BspLoader::BigLong (int l)
{
if (machineEndianness() == BIG_ENDIAN)
if (machineEndianness() == BSP_BIG_ENDIAN)
{
return l;
}
@@ -531,7 +531,7 @@ int BspLoader::BigLong (int l)
float BspLoader::LittleFloat (float l)
{
if (machineEndianness() == BIG_ENDIAN)
if (machineEndianness() == BSP_BIG_ENDIAN)
{
union {unsigned char b[4]; float f;} in, out;
@@ -550,7 +550,7 @@ float BspLoader::LittleFloat (float l)
float BspLoader::BigFloat (float l)
{
if (machineEndianness() == BIG_ENDIAN)
if (machineEndianness() == BSP_BIG_ENDIAN)
{
return l;
}

View File

@@ -176,7 +176,7 @@ class BspLoader
:m_num_entities(0)
{
m_Endianness = getMachineEndianness();
if (m_Endianness == BIG_ENDIAN)
if (m_Endianness == BSP_BIG_ENDIAN)
{
printf("Machine is BIG_ENDIAN\n");
} else
@@ -286,8 +286,8 @@ class BspLoader
enum
{
LITTLE_ENDIAN = 0,
BIG_ENDIAN = 1
BSP_LITTLE_ENDIAN = 0,
BSP_BIG_ENDIAN = 1,
};
//returns machines big endian / little endian

View File

@@ -48,8 +48,8 @@ extern int gForwardAxis;
#include "GLDebugDrawer.h"
#define QUAKE_BSP_IMPORTING 1
//in future make it a bsp2dae
//#define QUAKE_BSP_IMPORTING 1
#ifdef QUAKE_BSP_IMPORTING
#include "BspLoader.h"
@@ -308,6 +308,7 @@ CcdPhysicsController* CreatePhysicsObject(bool isDynamic, float mass, const Sim
}
#ifdef QUAKE_BSP_IMPORTING
///BspToBulletConverter extends the BspConverter to convert to Bullet datastructures
class BspToBulletConverter : public BspConverter
@@ -334,7 +335,7 @@ public:
}
}
};
#endif //QUAKE_BSP_IMPORTING
#ifdef USE_FCOLLADA
@@ -1851,7 +1852,7 @@ int main(int argc,char** argv)
#endif
clientResetScene();
setCameraDistance(16.f);
setCameraDistance(26.f);
return glutmain(argc, argv,640,480,"Bullet COLLADA Physics Viewer http://bullet.sourceforge.net");
}

View File

@@ -72,7 +72,8 @@ else
"../../Extras/PhysicsInterface/Common" ;
}
SubInclude TOP Demos CcdPhysicsDemo ;
SubInclude TOP Demos CcdPhysicsDemo ;
SubInclude TOP Demos BspDemo ;
SubInclude TOP Demos ConvexDecompositionDemo ;
SubInclude TOP Demos ColladaDemo ;
SubInclude TOP Demos CollisionDemo ;