#include #include #include #include #include #include #include #include #include GLuint compileShader(GLenum shaderType, const std::string& shaderSource) { GLuint shader = glCreateShader(shaderType); const char* source = shaderSource.c_str(); glShaderSource(shader, 1, &source, nullptr); glCompileShader(shader); GLint success; glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { char infoLog[512]; glGetShaderInfoLog(shader, sizeof(infoLog), nullptr, infoLog); std::cerr << "ERROR::SHADER::COMPILATION_FAILED\n" << infoLog << std::endl; } return shader; } GLuint createShaderProgram(const std::string& vertexShaderSource, const std::string& fragmentShaderSource) { GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource); GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource); GLuint shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram); GLint success; glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success) { char infoLog[512]; glGetProgramInfoLog(shaderProgram, sizeof(infoLog), nullptr, infoLog); std::cerr << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; } glDeleteShader(vertexShader); glDeleteShader(fragmentShader); return shaderProgram; } class OpenGLDebugDrawer : public btIDebugDraw { public: OpenGLDebugDrawer() : m_debugMode(0) { glGenVertexArrays(1, &m_vao); glGenBuffers(1, &m_vbo); glGenBuffers(1, &m_ebo); glGenBuffers(1, &m_colorBuffer); m_shaderProgram = createShaderProgram(vertexShaderSource, fragmentShaderSource); } ~OpenGLDebugDrawer() { glDeleteVertexArrays(1, &m_vao); glDeleteBuffers(1, &m_vbo); glDeleteBuffers(1, &m_ebo); glDeleteBuffers(1, &m_colorBuffer); glDeleteProgram(m_shaderProgram); } void drawLine(const btVector3& from, const btVector3& to, const btVector3& color) override { m_vertices.push_back(from); m_vertices.push_back(to); m_colors.push_back(color); m_colors.push_back(color); m_indices.push_back(m_indices.size()); m_indices.push_back(m_indices.size()); } void drawContactPoint(const btVector3&, const btVector3&, btScalar, int, const btVector3&) override {} void reportErrorWarning(const char*) override {} void draw3dText(const btVector3&, const char*) override {} void setDebugMode(int debugMode) override { m_debugMode = debugMode; } int getDebugMode() const override { return m_debugMode; } void render() { // Create view and projection matrices glm::vec3 cameraPos(0.0f, 5.0f, 10.0f); glm::vec3 cameraTarget(0.0f, 0.0f, 0.0f); glm::vec3 upVector(0.0f, 1.0f, 0.0f); glm::mat4 view = glm::lookAt(cameraPos, cameraTarget, upVector); glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); // Bind the VAO and update buffers // ... glBindVertexArray(m_vao); glBindBuffer(GL_ARRAY_BUFFER, m_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(btVector3) * m_vertices.size(), m_vertices.data(), GL_STATIC_DRAW); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, nullptr); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, m_colorBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(btVector3) * m_colors.size(), m_colors.data(), GL_STATIC_DRAW); glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, nullptr); glEnableVertexAttribArray(1); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * m_indices.size(), m_indices.data(), GL_STATIC_DRAW); // Set view and projection matrices in the shader glUseProgram(m_shaderProgram); glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "uView"), 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "uProjection"), 1, GL_FALSE, glm::value_ptr(projection)); // Draw the debug lines glDrawElements(GL_LINES, static_cast(m_indices.size()), GL_UNSIGNED_INT, nullptr); m_vertices.clear(); m_colors.clear(); m_indices.clear(); } private: int m_debugMode; std::vector m_vertices; std::vector m_colors; std::vector m_indices; GLuint m_vao, m_vbo, m_ebo, m_colorBuffer; GLuint m_shaderProgram; const std::string vertexShaderSource = R"( #version 430 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aColor; uniform mat4 uView; uniform mat4 uProjection; out vec3 vertexColor; void main() { gl_Position = uProjection * uView * vec4(aPos, 1.0); vertexColor = aColor; } )"; const std::string fragmentShaderSource = R"( #version 430 core in vec3 vertexColor; out vec4 FragColor; void main() { FragColor = vec4(vertexColor, 1.0); } )"; }; void APIENTRY glDebugMessageCallbackFunc(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { std::string sourceStr; switch (source) { case GL_DEBUG_SOURCE_API: sourceStr = "API"; break; case GL_DEBUG_SOURCE_WINDOW_SYSTEM: sourceStr = "Window System"; break; case GL_DEBUG_SOURCE_SHADER_COMPILER: sourceStr = "Shader Compiler"; break; case GL_DEBUG_SOURCE_THIRD_PARTY: sourceStr = "Third Party"; break; case GL_DEBUG_SOURCE_APPLICATION: sourceStr = "Application"; break; case GL_DEBUG_SOURCE_OTHER: sourceStr = "Other"; break; default: sourceStr = "Unknown"; } std::string typeStr; switch (type) { case GL_DEBUG_TYPE_ERROR: typeStr = "Error"; break; case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: typeStr = "Deprecated Behavior"; break; case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: typeStr = "Undefined Behavior"; break; case GL_DEBUG_TYPE_PORTABILITY: typeStr = "Portability"; break; case GL_DEBUG_TYPE_PERFORMANCE: typeStr = "Performance"; break; case GL_DEBUG_TYPE_OTHER: typeStr = "Other"; break; default: typeStr = "Unknown"; } std::string severityStr; switch (severity) { case GL_DEBUG_SEVERITY_HIGH: severityStr = "High"; break; case GL_DEBUG_SEVERITY_MEDIUM: severityStr = "Medium"; break; case GL_DEBUG_SEVERITY_LOW: severityStr = "Low"; break; case GL_DEBUG_SEVERITY_NOTIFICATION: severityStr = "Notification"; break; default: severityStr = "Unknown"; } std::cout << "OpenGL Debug Message [" << sourceStr << "][" << typeStr << "][" << severityStr << "] ID: " << id << " - " << message << std::endl; } // compileShader, createShaderProgram and OpenGLDebugDrawer class implementation go here. int main() { // Initialize GLFW if (!glfwInit()) { std::cerr << "Failed to initialize GLFW" << std::endl; return -1; } // Create a GLFW window glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); GLFWwindow* window = glfwCreateWindow(800, 600, "Bullet Physics - GLFW and GLAD", nullptr, nullptr); if (!window) { std::cerr << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } // Make the window's context current glfwMakeContextCurrent(window); // Load OpenGL function pointers using GLAD if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cerr << "Failed to initialize GLAD" << std::endl; glfwTerminate(); return -1; } if (true) { // GLAD_GL_KHR_debug) { glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallback(glDebugMessageCallbackFunc, nullptr); glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); } else { std::cout << "OpenGL KHR_debug extension not available. Debug output disabled." << std::endl; } // Enable depth testing glEnable(GL_DEPTH_TEST); // Set up the Bullet physics world btDefaultCollisionConfiguration collisionConfiguration; btCollisionDispatcher dispatcher(&collisionConfiguration); btDbvtBroadphase overlappingPairCache; btSequentialImpulseConstraintSolver solver; btDiscreteDynamicsWorld dynamicsWorld(&dispatcher, &overlappingPairCache, &solver, &collisionConfiguration); dynamicsWorld.setGravity(btVector3(0, -9.81, 0)); // dynamicsWorld.setGravity(btVector3(0, 0.0, 0)); // Create the ground plane btStaticPlaneShape groundShape(btVector3(0, 1, 0), 1); btDefaultMotionState groundMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, -1, 0))); btRigidBody::btRigidBodyConstructionInfo groundCI(0, &groundMotionState, &groundShape, btVector3(0, 0, 0)); btRigidBody* groundRigidBody = new btRigidBody(groundCI); dynamicsWorld.addRigidBody(groundRigidBody); // Create a box shape btBoxShape boxShape(btVector3(0.5, 0.5, 0.5)); btVector3 boxInertia(0, 0, 0); boxShape.calculateLocalInertia(1.0, boxInertia); btDefaultMotionState boxMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 3, 0))); btRigidBody::btRigidBodyConstructionInfo boxCI(1.0, &boxMotionState, &boxShape, boxInertia); btRigidBody* boxRigidBody = new btRigidBody(boxCI); dynamicsWorld.addRigidBody(boxRigidBody); // Set up the debug drawer OpenGLDebugDrawer debugDrawer; dynamicsWorld.setDebugDrawer(&debugDrawer); debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawWireframe); // Main loop while (!glfwWindowShouldClose(window)) { // Clear the screen glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Step the simulation dynamicsWorld.stepSimulation(1.0 / 60.0, 10); dynamicsWorld.debugDrawWorld(); // Render the debug lines debugDrawer.render(); // Swap the buffers and poll for events glfwSwapBuffers(window); glfwPollEvents(); } // Clean up dynamicsWorld.removeRigidBody(boxRigidBody); delete boxRigidBody; dynamicsWorld.removeRigidBody(groundRigidBody); delete groundRigidBody; glfwDestroyWindow(window); glfwTerminate(); return 0; }