Created
October 19, 2022 02:49
-
-
Save 8Observer8/ae3d00efb8e43ddfb1c1ce1ac34ba912 to your computer and use it in GitHub Desktop.
trigger-bullet-opengl1-freeglut-cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define FREEGLUT_STATIC | |
#include <GL/freeglut.h> | |
#include <GL/glu.h> | |
#include <algorithm> | |
#include <btBulletDynamicsCommon.h> | |
#include <iostream> | |
#include <set> | |
int winW = 350, winH = 350; | |
// Convenient typedefs for collision events | |
typedef std::pair<const btRigidBody *, const btRigidBody *> CollisionPair; | |
typedef std::set<CollisionPair> CollisionPairs; | |
// Collision event variables | |
CollisionPairs pairsLastUpdate; | |
std::string outputText; | |
GLfloat floorMaterialDiffuse[] = { 0.55f, 0.64f, 0.36f, 1.f }; | |
GLfloat sphereMaterialDiffuse[] = { 0.06f, 0.29f, 0.65f, 1.f }; | |
GLfloat platformMaterialDiffuse[] = { 0.74f, 0.53f, 0.19f, 1.f }; | |
GLfloat colliderMaterialDiffuse[] = { 0.f, 1.f, 0.f, 1.f }; | |
GLfloat textMaterialDiffuse[] = { 1.f, 1.f, 1.f, 1.f }; | |
GLfloat light0Diffuse[] = { 1.f, 1.f, 1.0f }; | |
GLfloat light0Direction[] = { 2.f, 5.f, 4.f, 1.f }; | |
btDynamicsWorld *world; | |
btCollisionConfiguration *collisionConfiguration; | |
btConstraintSolver *solver; | |
btBroadphaseInterface *overlappingPairCache; | |
btCollisionDispatcher *dispatcher; | |
float spherePosX = -2.f; | |
float spherePosY = 5.f; | |
float spherePosZ = 0.f; | |
float sphereRadius = 0.5f; | |
float sphereMass = 1.f; | |
btRigidBody *sphereRigidBody; | |
btDefaultMotionState *sphereMotionState; | |
btSphereShape *sphereShape; | |
float floorPosX = 0.f; | |
float floorPosY = 0.f; | |
float floorPosZ = 0.f; | |
float floorWidth = 10.f; | |
float floorHeight = 0.2f; | |
float floorDepth = 10.f; | |
btRigidBody *floorRigidBody; | |
btDefaultMotionState *floorMotionState; | |
btBoxShape *floorShape; | |
float firstPlatformPosX = 3.f; | |
float firstPlatformPosY = 3.f; | |
float firstPlatformPosZ = 0.f; | |
float firstPlatformWidth = 3.f; | |
float firstPlatformHeight = 0.2f; | |
float firstPlatformDepth = 0.5f; | |
btRigidBody *firstPlatformRigidBody; | |
btDefaultMotionState *firstPlatformMotionState; | |
btBoxShape *firstPlatformShape; | |
float secondPlatformPosX = -1.f; | |
float secondPlatformPosY = 4.f; | |
float secondPlatformPosZ = 0.f; | |
float secondPlatformWidth = 3.f; | |
float secondPlatformHeight = 0.2f; | |
float secondPlatformDepth = 0.5f; | |
btRigidBody *secondPlatformRigidBody; | |
btDefaultMotionState *secondPlatformMotionState; | |
btBoxShape *secondPlatformShape; | |
btCollisionObject *trigger; | |
class DebugDrawer : public btIDebugDraw | |
{ | |
public: | |
// Debug mode functions | |
virtual void setDebugMode(int debugMode) override { m_debugMode = debugMode; } | |
virtual int getDebugMode() const override { return m_debugMode; } | |
// Draws a line between two contact points | |
virtual void drawContactPoint(const btVector3 &pointOnB, const btVector3 &normalOnB, | |
btScalar distance, int lifeTime, const btVector3 &color) override | |
{ | |
btVector3 const startPoint = pointOnB; | |
btVector3 const endPoint = pointOnB + normalOnB * distance; | |
drawLine(startPoint, endPoint, color); | |
} | |
// Draws a simple line of pixels between points | |
virtual void drawLine(const btVector3 &from, const btVector3 &to, | |
const btVector3 &color) override | |
{ | |
// Use the GL_LINES primitive to draw lines | |
glBegin(GL_LINES); | |
// glColor3f(color.getX(), color.getY(), color.getZ()); | |
glMaterialfv(GL_FRONT, GL_DIFFUSE, colliderMaterialDiffuse); | |
glVertex3f(from.getX(), from.getY(), from.getZ()); | |
glVertex3f(to.getX(), to.getY(), to.getZ()); | |
glEnd(); | |
} | |
// Unused | |
virtual void reportErrorWarning(const char *warningString) override { } | |
virtual void draw3dText(const btVector3 &location, const char *textString) override { } | |
void toggleDebugFlag(int flag) | |
{ | |
// Checks if a flag is set and enables/disables it | |
if (m_debugMode & flag) | |
{ | |
// Flag is enabled, so disable it | |
m_debugMode = m_debugMode & (~flag); | |
} | |
else | |
{ | |
// Flag is disabled, so enable it | |
m_debugMode |= flag; | |
} | |
} | |
protected: | |
int m_debugMode; | |
}; | |
DebugDrawer *debugDrawer; | |
void initPhysics() | |
{ | |
collisionConfiguration = new btDefaultCollisionConfiguration(); | |
dispatcher = new btCollisionDispatcher(collisionConfiguration); | |
overlappingPairCache = new btDbvtBroadphase(); | |
solver = new btSequentialImpulseConstraintSolver(); | |
world = new btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, | |
solver, collisionConfiguration); | |
// std::cout << world->getGravity().y() << std::endl; | |
world->setGravity(btVector3(0.f, -9.8f, 0.f)); | |
debugDrawer = new DebugDrawer(); | |
debugDrawer->setDebugMode(0); // Set the initial debug level to 0 | |
debugDrawer->toggleDebugFlag(btIDebugDraw::DBG_MAX_DEBUG_DRAW_MODE); | |
world->setDebugDrawer(debugDrawer); | |
float restitution = 0.7f; | |
float friction = 0.9f; | |
sphereShape = new btSphereShape(sphereRadius); | |
btTransform sphereTransform; | |
sphereTransform.setIdentity(); | |
sphereTransform.setOrigin(btVector3(spherePosX, spherePosY, spherePosZ)); | |
sphereTransform.setRotation(btQuaternion(1.f, 0.f, 0.f, 0.f)); | |
btVector3 sphereLocalInertia(0.f, 0.f, 0.f); | |
sphereShape->calculateLocalInertia(sphereMass, sphereLocalInertia); | |
sphereMotionState = new btDefaultMotionState(sphereTransform); | |
btRigidBody::btRigidBodyConstructionInfo sphereRbInfo(sphereMass, sphereMotionState, | |
sphereShape, sphereLocalInertia); | |
sphereRigidBody = new btRigidBody(sphereRbInfo); | |
sphereRigidBody->setActivationState(DISABLE_DEACTIVATION); | |
sphereRigidBody->setFriction(friction); | |
// sphereRigidBody->setRollingFriction(0.5f); | |
sphereRigidBody->setRestitution(restitution); | |
// sphereRigidBody->setCustomDebugColor(btVector3(1.f, 0.f, 0.f)); | |
world->addRigidBody(sphereRigidBody); | |
floorShape = new btBoxShape(btVector3(floorWidth / 2.f, floorHeight / 2.f, | |
floorDepth / 2.f)); | |
btTransform floorTransform; | |
floorTransform.setIdentity(); | |
floorTransform.setOrigin(btVector3(floorPosX, floorPosY, floorPosZ)); | |
floorTransform.setRotation(btQuaternion(1.f, 0.f, 0.f, 0.f)); | |
btVector3 floorLocalInertia(0.f, 0.f, 0.f); | |
float floorMass = 0.f; | |
floorMotionState = new btDefaultMotionState(floorTransform); | |
btRigidBody::btRigidBodyConstructionInfo floorRbInfo(floorMass, floorMotionState, | |
floorShape, floorLocalInertia); | |
floorRigidBody = new btRigidBody(floorRbInfo); | |
floorRigidBody->setActivationState(DISABLE_DEACTIVATION); | |
// std::cout << floorRigidBody->getRestitution() << std::endl; | |
floorRigidBody->setRestitution(restitution); | |
floorRigidBody->setFriction(friction); | |
world->addRigidBody(floorRigidBody); | |
firstPlatformShape = new btBoxShape(btVector3(firstPlatformWidth / 2.f, | |
firstPlatformHeight / 2.f, firstPlatformDepth / 2.f)); | |
btTransform firstPlatformTransform; | |
firstPlatformTransform.setIdentity(); | |
firstPlatformTransform.setOrigin(btVector3(firstPlatformPosX, firstPlatformPosY, | |
firstPlatformPosZ)); | |
firstPlatformTransform.setRotation(btQuaternion(0.985f, 0.174, 0.f, 0.f)); | |
btVector3 firstPlatformLocalInertia(0.f, 0.f, 0.f); | |
float firstPlatformMass = 0.f; | |
firstPlatformMotionState = new btDefaultMotionState(firstPlatformTransform); | |
btRigidBody::btRigidBodyConstructionInfo firstPlatformRbInfo(firstPlatformMass, | |
firstPlatformMotionState, firstPlatformShape, firstPlatformLocalInertia); | |
firstPlatformRigidBody = new btRigidBody(firstPlatformRbInfo); | |
firstPlatformRigidBody->setActivationState(DISABLE_DEACTIVATION); | |
firstPlatformRigidBody->setRestitution(restitution); | |
firstPlatformRigidBody->setFriction(friction); | |
world->addRigidBody(firstPlatformRigidBody); | |
secondPlatformShape = new btBoxShape(btVector3(secondPlatformWidth / 2.f, | |
secondPlatformHeight / 2.f, secondPlatformDepth / 2.f)); | |
btTransform secondPlatformTransform; | |
secondPlatformTransform.setIdentity(); | |
secondPlatformTransform.setOrigin(btVector3(secondPlatformPosX, secondPlatformPosY, | |
secondPlatformPosZ)); | |
secondPlatformTransform.setRotation(btQuaternion(0.985f, -0.174, 0.f, 0.f)); | |
btVector3 secondPlatformLocalInertia(0.f, 0.f, 0.f); | |
float secondPlatformMass = 0.f; | |
secondPlatformMotionState = new btDefaultMotionState(secondPlatformTransform); | |
btRigidBody::btRigidBodyConstructionInfo secondPlatformRbInfo(firstPlatformMass, | |
secondPlatformMotionState, secondPlatformShape, secondPlatformLocalInertia); | |
secondPlatformRigidBody = new btRigidBody(secondPlatformRbInfo); | |
secondPlatformRigidBody->setActivationState(DISABLE_DEACTIVATION); | |
secondPlatformRigidBody->setRestitution(restitution); | |
secondPlatformRigidBody->setFriction(friction); | |
world->addRigidBody(secondPlatformRigidBody); | |
trigger = new btCollisionObject(); | |
trigger->setCollisionShape(new btBoxShape(btVector3(1.f, 0.25f, 1.f))); | |
btTransform triggerTrans; | |
triggerTrans.setIdentity(); | |
triggerTrans.setOrigin(btVector3(0.f, 1.5f, 0.f)); | |
trigger->setWorldTransform(triggerTrans); | |
trigger->setCollisionFlags(btCollisionObject::CF_NO_CONTACT_RESPONSE); | |
world->addCollisionObject(trigger); | |
} | |
void cleanUp() | |
{ | |
delete world; | |
delete solver; | |
delete overlappingPairCache; | |
delete dispatcher; | |
delete collisionConfiguration; | |
delete sphereRigidBody; | |
delete sphereMotionState; | |
delete sphereShape; | |
delete floorRigidBody; | |
delete floorMotionState; | |
delete floorShape; | |
delete firstPlatformRigidBody; | |
delete firstPlatformMotionState; | |
delete firstPlatformShape; | |
delete secondPlatformRigidBody; | |
delete secondPlatformMotionState; | |
delete secondPlatformShape; | |
delete debugDrawer; | |
delete trigger; | |
} | |
void resize(int w, int h) | |
{ | |
glViewport(0, 0, w, h); | |
glMatrixMode(GL_PROJECTION); | |
glLoadIdentity(); | |
gluPerspective(50.f, (GLfloat)w / (GLfloat)h, 0.1f, 100.f); | |
} | |
/* | |
GLUT_BITMAP_8_BY_13 | |
GLUT_BITMAP_9_BY_15 | |
GLUT_BITMAP_TIMES_ROMAN_10 | |
GLUT_BITMAP_TIMES_ROMAN_24 | |
GLUT_BITMAP_HELVETICA_10 | |
GLUT_BITMAP_HELVETICA_12 | |
GLUT_BITMAP_HELVETICA_18 | |
*/ | |
void drawText(float x, float y, std::string text) | |
{ | |
glMatrixMode(GL_PROJECTION); | |
glLoadIdentity(); | |
glOrtho(0, 100, 100, 0, -100, 100); | |
glMatrixMode(GL_MODELVIEW); | |
glLoadIdentity(); | |
gluLookAt( | |
0.f, 0.f, 10.f, | |
0.f, 0.f, 0.f, | |
0.f, 1.f, 0.f); | |
glMaterialfv(GL_FRONT, GL_DIFFUSE, textMaterialDiffuse); | |
glScalef(2.f, 2.f, 2.f); | |
glRasterPos2f(x, y); | |
glutBitmapString(GLUT_BITMAP_9_BY_15, (const unsigned char *)text.c_str()); | |
} | |
void draw() | |
{ | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
glDisable(GL_LIGHTING); | |
drawText(5, 5, outputText); | |
glEnable(GL_LIGHTING); | |
resize(winW, winH); | |
glMatrixMode(GL_MODELVIEW); | |
glLoadIdentity(); | |
gluLookAt( | |
-3.f, 6.f, 7.f, | |
0.f, 3.f, 0.f, | |
0.f, 1.f, 0.f); | |
glPushMatrix(); | |
{ | |
glMaterialfv(GL_FRONT, GL_DIFFUSE, sphereMaterialDiffuse); | |
btScalar transform[16]; | |
btMotionState *motionState = sphereRigidBody->getMotionState(); | |
btTransform tempTransform; | |
motionState->getWorldTransform(tempTransform); | |
tempTransform.getOpenGLMatrix(transform); | |
glMultMatrixf(transform); | |
glutSolidSphere(sphereRadius, 32, 16); | |
} | |
glPopMatrix(); | |
// Draw the floor | |
glPushMatrix(); | |
{ | |
glMaterialfv(GL_FRONT, GL_DIFFUSE, floorMaterialDiffuse); | |
btScalar transform[16]; | |
btMotionState *motionState = floorRigidBody->getMotionState(); | |
btTransform tempTransform; | |
motionState->getWorldTransform(tempTransform); | |
tempTransform.getOpenGLMatrix(transform); | |
glMultMatrixf(transform); | |
glScalef(floorWidth, floorHeight, floorDepth); | |
glutSolidCube(1.f); | |
} | |
glPopMatrix(); | |
// Draw the first platform | |
glPushMatrix(); | |
{ | |
glMaterialfv(GL_FRONT, GL_DIFFUSE, platformMaterialDiffuse); | |
btScalar transform[16]; | |
btMotionState *motionState = firstPlatformRigidBody->getMotionState(); | |
btTransform tempTransform; | |
motionState->getWorldTransform(tempTransform); | |
tempTransform.getOpenGLMatrix(transform); | |
glMultMatrixf(transform); | |
glScalef(firstPlatformWidth, firstPlatformHeight, firstPlatformDepth); | |
glutSolidCube(1.f); | |
} | |
glPopMatrix(); | |
// Draw the second platform | |
glPushMatrix(); | |
{ | |
glMaterialfv(GL_FRONT, GL_DIFFUSE, platformMaterialDiffuse); | |
btScalar transform[16]; | |
btMotionState *motionState = secondPlatformRigidBody->getMotionState(); | |
btTransform tempTransform; | |
motionState->getWorldTransform(tempTransform); | |
tempTransform.getOpenGLMatrix(transform); | |
glMultMatrixf(transform); | |
glScalef(secondPlatformWidth, secondPlatformHeight, secondPlatformDepth); | |
glutSolidCube(1.f); | |
} | |
glPopMatrix(); | |
world->debugDrawWorld(); | |
glutSwapBuffers(); | |
} | |
void collisionEvent(btRigidBody *pBody0, btRigidBody *pBody1) | |
{ | |
// Did the box collide with the trigger? | |
if (pBody0 == sphereRigidBody && pBody1 == trigger || | |
pBody1 == sphereRigidBody && pBody0 == trigger) | |
{ | |
// std::cout << "collision" << std::endl; | |
outputText = "Collision with trigger"; | |
} | |
} | |
void separationEvent(btRigidBody *pBody0, btRigidBody *pBody1) | |
{ | |
// std::cout << "separation" << std::endl; | |
outputText = "Separation"; | |
} | |
void checkForCollisionEvents() | |
{ | |
// Keep a list of the collision pairs we | |
// found during the current update | |
CollisionPairs pairsThisUpdate; | |
// Iterate through all of the manifolds in the dispatcher | |
for (int i = 0; i < dispatcher->getNumManifolds(); ++i) | |
{ | |
// Get the manifold | |
btPersistentManifold *pManifold = dispatcher->getManifoldByIndexInternal(i); | |
// Ignore manifolds that have no contact points | |
if (pManifold->getNumContacts() > 0) | |
{ | |
// Get the two rigid bodies involved in the collision | |
const btRigidBody *pBody0 = static_cast<const btRigidBody *>(pManifold->getBody0()); | |
const btRigidBody *pBody1 = static_cast<const btRigidBody *>(pManifold->getBody1()); | |
// Always create the pair in a predictable order (use the pointer value..) | |
bool const swapped = pBody0 > pBody1; | |
const btRigidBody *pSortedBodyA = swapped ? pBody1 : pBody0; | |
const btRigidBody *pSortedBodyB = swapped ? pBody0 : pBody1; | |
// Create the pair | |
CollisionPair thisPair = std::make_pair(pSortedBodyA, pSortedBodyB); | |
// Insert the pair into the current list | |
pairsThisUpdate.insert(thisPair); | |
// If this pair doesn't exist in the list | |
// from the previous update, it is a new | |
// pair and we must send a collision event | |
if (pairsLastUpdate.find(thisPair) == pairsLastUpdate.end()) | |
{ | |
collisionEvent((btRigidBody *)pBody0, (btRigidBody *)pBody1); | |
} | |
} | |
} | |
// Create another list for pairs that were removed this update | |
CollisionPairs removedPairs; | |
// This handy function gets the difference between | |
// two sets. It takes the difference between | |
// collision pairs from the last update, and this | |
// update and pushes them into the removed pairs list | |
std::set_difference(pairsLastUpdate.begin(), pairsLastUpdate.end(), | |
pairsThisUpdate.begin(), pairsThisUpdate.end(), | |
std::inserter(removedPairs, removedPairs.begin())); | |
// Iterate through all of the removed pairs sending separation events for them | |
for (CollisionPairs::const_iterator iter = removedPairs.begin(); | |
iter != removedPairs.end(); ++iter) | |
{ | |
separationEvent((btRigidBody *)iter->first, (btRigidBody *)iter->second); | |
} | |
// In the next iteration we'll want to compare against the pairs we found | |
// in this iteration | |
pairsLastUpdate = pairsThisUpdate; | |
} | |
void timer(int) | |
{ | |
world->stepSimulation(0.016, 8); | |
checkForCollisionEvents(); | |
glutPostRedisplay(); | |
glutTimerFunc(16.f, timer, 0); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
glutInit(&argc, argv); | |
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); | |
glutInitWindowSize(winW, winH); | |
glutInitWindowPosition(100, 100); | |
int window = glutCreateWindow("OpenGL1, FreeGLUT, C++"); | |
glClearColor(0.2f, 0.2f, 0.2f, 1.f); | |
glEnable(GL_DEPTH_TEST); | |
glEnable(GL_LIGHTING); | |
glEnable(GL_LIGHT0); | |
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0Diffuse); | |
glLightfv(GL_LIGHT0, GL_POSITION, light0Direction); | |
glEnable(GL_NORMALIZE); | |
glutDisplayFunc(draw); | |
initPhysics(); | |
timer(0); | |
glutReshapeFunc(resize); | |
glutMainLoop(); | |
cleanUp(); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# build command: mingw32-make | |
# -mwindows - a key to hide the console | |
INC = -I"E:\Libs\freeglut-3.2.2-mingw-64-bit\include" \ | |
-I"E:\Libs\bullet3-3.24-mingw-64-bit\include" \ | |
-I"E:\Libs\glu\include" | |
LIB = -L"E:\Libs\freeglut-3.2.2-mingw-64-bit\lib" \ | |
-L"E:\Libs\bullet3-3.24-mingw-64-bit\lib" | |
all: main.o | |
g++ main.o $(LIB) -D FREEGLUT_STATIC -lfreeglut_static -lopengl32 \ | |
-lwinmm -lgdi32 -lglu32 -lBulletDynamics -lBulletCollision \ | |
-lLinearMath -o app.exe | |
main.o: main.cpp | |
g++ -c $(INC) main.cpp |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Archive with sources and EXE for Windows 10, 64-bit: https://dl.dropboxusercontent.com/s/7w3b94ion15g7ga/trigger-bullet-opengl1-freeglut-cpp.zip