diff --git a/bsptest.bsp b/BspDemo.bsp similarity index 100% rename from bsptest.bsp rename to BspDemo.bsp diff --git a/Demos/BspDemo/BspConverter.cpp b/Demos/BspDemo/BspConverter.cpp new file mode 100644 index 000000000..e8a472afe --- /dev/null +++ b/Demos/BspDemo/BspConverter.cpp @@ -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 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 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=0) && (modelnr < bspLoader.m_nummodels)) + { + const BSPModel& model = bspLoader.m_dmodels[modelnr]; + for (int n=0;n planeEquations; + bool isValidBrush = false; + + //convert brush + const BSPBrush& brush = bspLoader.m_dbrushes[model.firstBrush+n]; + { + for (int p=0;p 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& planeEquations , std::vector& verticesOut ) +{ + float minimumDotProduct = 1e30f; + + const int numbrushes = planeEquations.size(); + // brute force: + for (int i=0;i 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& planeEquations, const SimdVector3& point, float margin) +{ + int numbrushes = planeEquations.size(); + for (int i=0;i0.f) + { + return false; + } + } + return true; + +} \ No newline at end of file diff --git a/Demos/BspDemo/BspConverter.h b/Demos/BspDemo/BspConverter.h new file mode 100644 index 000000000..01e9c9c5b --- /dev/null +++ b/Demos/BspDemo/BspConverter.h @@ -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 +#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& planeEquations , std::vector& verticesOut ); + bool isInside(const std::vector& planeEquations, const SimdVector3& point, float margin); + + ///this callback is called for each brush that succesfully converted into vertices + virtual void AddConvexVerticesCollider(std::vector& vertices, bool isEntity, const SimdVector3& entityTargetLocation) = 0; + +}; + +#endif //BSP_CONVERTER_H \ No newline at end of file diff --git a/Demos/BspDemo/BspDemo.cpp b/Demos/BspDemo/BspDemo.cpp new file mode 100644 index 000000000..e7adcaa4a --- /dev/null +++ b/Demos/BspDemo/BspDemo.cpp @@ -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 //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 +#endif +//think different +#if defined(__APPLE__) && !defined (VMDMESA) +#include +#include +#include +#else +#include +#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& 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;i1) + { + 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;iGetRigidBody()->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::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;isetPosition(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(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(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(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(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; +} diff --git a/Demos/BspDemo/BspLoader.cpp b/Demos/BspDemo/BspLoader.cpp new file mode 100644 index 000000000..5e62fea71 --- /dev/null +++ b/Demos/BspDemo/BspLoader.cpp @@ -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; +} \ No newline at end of file diff --git a/Demos/BspDemo/BspLoader.h b/Demos/BspDemo/BspLoader.h new file mode 100644 index 000000000..c89a8a125 --- /dev/null +++ b/Demos/BspDemo/BspLoader.h @@ -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 + + +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 m_entities; + + int m_nummodels; + std::vector m_dmodels; + + int m_numShaders; + std::vector m_dshaders; + + int m_entdatasize; + std::vector m_dentdata; + + int m_numleafs; + std::vector m_dleafs; + + int m_numplanes; + std::vector m_dplanes; + + int m_numnodes; + std::vector m_dnodes; + + int m_numleafsurfaces; + std::vector m_dleafsurfaces; + + int m_numleafbrushes; + std::vector m_dleafbrushes; + + int m_numbrushes; + std::vector m_dbrushes; + + int m_numbrushsides; + std::vector m_dbrushsides; + + int m_numLightBytes; + std::vector m_lightBytes; + + int m_numGridPoints; + std::vector m_gridData; + + int m_numVisBytes; + std::vector m_visBytes; + + + int m_numDrawIndexes; + std::vector m_drawIndexes; + + int m_numDrawSurfaces; + std::vector 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 diff --git a/Demos/BspDemo/Jamfile b/Demos/BspDemo/Jamfile new file mode 100644 index 000000000..10a6d3b06 --- /dev/null +++ b/Demos/BspDemo/Jamfile @@ -0,0 +1,3 @@ +SubDir TOP Demos BspDemo ; + +ExtraDemo BspDemo : [ Wildcard *.h *.cpp ] ; diff --git a/Demos/CMakeLists.txt b/Demos/CMakeLists.txt index 808908eb9..0beada0bc 100644 --- a/Demos/CMakeLists.txt +++ b/Demos/CMakeLists.txt @@ -1,2 +1,2 @@ -SUBDIRS( OpenGL CcdPhysicsDemo ) +SUBDIRS( OpenGL CcdPhysicsDemo BspDemo ) diff --git a/Demos/ColladaDemo/BspLoader.cpp b/Demos/ColladaDemo/BspLoader.cpp index 165339473..5e62fea71 100644 --- a/Demos/ColladaDemo/BspLoader.cpp +++ b/Demos/ColladaDemo/BspLoader.cpp @@ -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; } diff --git a/Demos/ColladaDemo/BspLoader.h b/Demos/ColladaDemo/BspLoader.h index 5981a6ea9..c89a8a125 100644 --- a/Demos/ColladaDemo/BspLoader.h +++ b/Demos/ColladaDemo/BspLoader.h @@ -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 diff --git a/Demos/ColladaDemo/ColladaDemo.cpp b/Demos/ColladaDemo/ColladaDemo.cpp index 7081123cf..ffd66d73a 100644 --- a/Demos/ColladaDemo/ColladaDemo.cpp +++ b/Demos/ColladaDemo/ColladaDemo.cpp @@ -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"); } diff --git a/Demos/Jamfile b/Demos/Jamfile index 7b36c0b04..216785da7 100644 --- a/Demos/Jamfile +++ b/Demos/Jamfile @@ -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 ;