#include "lopenglprogram.h" #include "camera.h" #include #include #include #include #include #include #include #include #include #include class GLWidget { public: struct ViewPort { int width; int height; }; GLWidget(ViewPort port) : viewport_(port) , window_(nullptr, [](GLFWwindow* w){if(w) glfwDestroyWindow(w);}) , deinit_(false) { lastX_ = port.width / 2; lastY_ = port.height / 2; initGeometry(); } ~GLWidget() { if (!deinit_) { // OpenGL objects should be deleted while a valid context still exists. if (window_) { glfwMakeContextCurrent(window_.get()); } if (panelIbo_) { glDeleteBuffers(1, &panelIbo_); } if (panelVbo_) { glDeleteBuffers(1, &panelVbo_); } if (panelVao_) { glDeleteVertexArrays(1, &panelVao_); } if (bgVao_) { glDeleteVertexArrays(1, &bgVao_); } if (bgVbo_) { glDeleteBuffers(1, &bgVbo_); } deinit_ = true; } } void setViewPort(int width, int height) { viewport_ = {width, height}; } bool initGeometry() { if (!glfwInit()) { std::cout << "Failed to initialize GLFW" << std::endl; return false; } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #if __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif window_.reset(glfwCreateWindow(viewport_.width, viewport_.height, "3dviewer", nullptr, nullptr)); if (!window_) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return false; } glfwMakeContextCurrent(window_.get()); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return false; } glViewport(0, 0, viewport_.width, viewport_.height); glEnable(GL_DEPTH_TEST); glfwSetInputMode(window_.get(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetWindowUserPointer(window_.get(), this); glfwSetFramebufferSizeCallback(window_.get(), &GLWidget::framebufferSizeCallback); glfwSetCursorPosCallback(window_.get(), &GLWidget::mouseCallback); glfwSetScrollCallback(window_.get(), &GLWidget::scrollCallback); return true; } void setBgShaderPath(std::string vp, std::string fp) { bgVertShaderPath_ = vp; bgFragShaderPath_ = fp; } void setPanelShaderPath(std::string vp, std::string fp) { panelVertShaderPath_ = vp; panelFragShaderPath_ = fp; } private: void initBgGeometry() { if (bgVbo_) { glDeleteBuffers(1, &bgVbo_); bgVbo_ = 0; } if (bgVao_) { glDeleteVertexArrays(1, &bgVao_); bgVao_ = 0; } const float verts[] = { -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, }; glGenVertexArrays(1, &bgVao_); glBindVertexArray(bgVao_); glGenBuffers(1, &bgVbo_); glBindBuffer(GL_ARRAY_BUFFER, bgVbo_); glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0); glBindVertexArray(0); } void initPanelGeometry_() { if (panelVbo_) { glDeleteBuffers(1, &panelVbo_); panelVbo_ = 0; } if (panelVao_) { glDeleteVertexArrays(1, &panelVao_); panelVao_ = 0; } if (panelIbo_) { glDeleteBuffers(1, &panelIbo_); panelIbo_ = 0; } const float y = panelHeight_ * 0.5f; const float x = panelWidth_ * 0.5f; const float z = panelDepth_ * 0.5f; struct V { float x, y, z; float nx, ny, nz; }; const V verts[24] = { // 顶面 {-x, y, -z, 0, 1, 0}, {x, y, -z, 0, 1, 0}, {x, y, z, 0, 1, 0 }, {-x, y, z, 0, 1, 0}, // 前面 {-x, y, z, 0, 0, 1}, {x, y, z, 0, 0, 1}, {x, -y, z, 0, 0, 1}, {-x, -y, z, 0, 0, 1}, // 底面 {-x, -y, -z, 0, -1, 0}, {x, -y, -z, 0, -1, 0}, {x, -y, z, 0, -1, 0}, {-x, -y, z, 0, -1, 0}, // 后面 {-x, y, -z, 0, 0, -1}, {x, y, -z, 0, 0, -1}, {x, -y, -z, 0, 0, -1}, {-x, -y, -z, 0, 0, -1}, // 左面 {-x, y, z, -1, 0, 0}, {-x, y, -z, -1, 0, 0}, {-x, -y, -z, -1, 0, 0}, {-x, -y, z, -1, 0, 0}, // 右面 {x, y, -z, 1, 0, 0}, {x, y, z, 1, 0, 0}, {x, -y, z, 1, 0, 0}, {x, -y, -z, 1, 0, 0}, }; unsigned int idx[36] = { 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23, }; glGenVertexArrays(1, &panelVao_); glBindVertexArray(panelVao_); glGenBuffers(1, &panelVbo_); glBindBuffer(GL_ARRAY_BUFFER, panelVbo_); glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); glGenBuffers(1, &panelIbo_); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, panelIbo_); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idx), idx, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(V), (void*)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(V), (void*)(3 * sizeof(float))); glBindVertexArray(0); } void initHeatmapGeometry_() { } bool initBgProgram() { auto vshader = std::make_unique(LOpenGLShader::ShaderType::Vertex); auto fshader = std::make_unique(LOpenGLShader::ShaderType::Fragment); if (!vshader->compileShaderFromFile(bgVertShaderPath_)) { std::cout << "Vertex shader compile failed: " << bgVertShaderPath_ << "\n" << vshader->Log() << std::endl; return false; } if (!fshader->compileShaderFromFile(bgFragShaderPath_)) { std::cout << "Fragment shader compile failed: " << bgFragShaderPath_ << "\n" << fshader->Log() << std::endl; return false; } bgProg_ = std::make_unique(); if (!bgProg_->addShader(std::move(vshader))) { std::cout << "Failed to attach vertex shader\n"; return false; } if (!bgProg_->addShader(std::move(fshader))) { std::cout << "Failed to attach fragment shader\n"; return false; } bool ret = bgProg_->Link(); if (!ret) { std::cout << "Failed to link background program\n"; return false; } return true; } bool initPanelProgram() { auto vshader = std::make_unique(LOpenGLShader::ShaderType::Vertex); auto fshader = std::make_unique(LOpenGLShader::ShaderType::Fragment); if (!vshader->compileShaderFromFile(panelVertShaderPath_)) { std::cout << "Vertex shader compile failed: " << panelVertShaderPath_ << "\n" << vshader->Log() << std::endl; return false; } if (!fshader->compileShaderFromFile(panelFragShaderPath_)) { std::cout << "Fragment shader compile failed: " << panelFragShaderPath_ << "\n" << fshader->Log() << std::endl; return false; } panelProg_ = std::make_unique(); if (!panelProg_->addShader(std::move(vshader))) { std::cout << "Failed to attach vertex shader\n"; return false; } if (!panelProg_->addShader(std::move(fshader))) { std::cout << "Failed to attach fragment shader\n"; return false; } bool ret = panelProg_->Link(); if (!ret) { std::cout << "Failed to link panel program\n"; return false; } return true; } bool initHeatmapProgram() { auto vshader = std::make_unique(LOpenGLShader::ShaderType::Vertex); auto fshader = std::make_unique(LOpenGLShader::ShaderType::Fragment); } void drawBg() { if (!bgProg_ || !bgVao_ || !bgVbo_) { std::cout << "check !bgProg_ || !bgVao_ || !bgVbo_ failed\n"; return; } bgProg_->Use(); bgProg_->setUniformValue("uViewport", glm::vec2(viewport_.width, viewport_.height)); bgProg_->setUniformValue("uMajorStep", 120.0f); bgProg_->setUniformValue("uMinorStep", 24.0f); bgProg_->setUniformValue("uLightMode", lightMode_); glDisable(GL_DEPTH_TEST); glBindVertexArray(bgVao_); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); glEnable(GL_DEPTH_TEST); } void drawPanel() { if (!panelProg_ || !panelVao_ || !panelVbo_ || !panelIbo_) { std:: cout << "check !panelProg_ || !panelVao || !panelVbo || !panelIbo\n"; return; } auto [model, view, projection] = getMVP(); panelProg_->Use(); panelProg_->setUniformValue("model", model); panelProg_->setUniformValue("view", view); panelProg_->setUniformValue("projection", projection); panelProg_->setUniformValue("uLightMode", lightMode_); glBindVertexArray(panelVao_); glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, nullptr); glBindVertexArray(0); } std::tuple getMVP() { auto model = glm::mat4(1.0f); auto view = camera_.getViewMatrix(); auto projection = glm::perspective(glm::radians(camera_.Zoom()), (float)viewport_.width / (float)viewport_.height, 0.1f, 100.0f); return {model, view, projection}; } public: void eventLoop() { if (!window_) { return; } initBgGeometry(); if (!initBgProgram()) { return; } initPanelGeometry_(); if (!initPanelProgram()) { return; } while (!glfwWindowShouldClose(window_.get())) { const float now = static_cast(glfwGetTime()); const float deltaTime = now - lastFrame_; lastFrame_ = now; processInput(window_.get(), deltaTime); glClearColor(0.08f, 0.08f, 0.10f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); drawBg(); drawPanel(); glfwSwapBuffers(window_.get()); glfwPollEvents(); } } private: static void framebufferSizeCallback(GLFWwindow* window, int width, int height) { auto* self = static_cast(glfwGetWindowUserPointer(window)); if (!self) { return; } self->onFramebufferSize(width, height); } void onFramebufferSize(int width, int height) { viewport_ = {width, height}; glViewport(0, 0, width, height); } void processInput(GLFWwindow* window, float deltaTime) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); } if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { camera_.keyboardCallback(Camera::FORWARD, deltaTime); } if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { camera_.keyboardCallback(Camera::BACKWARD, deltaTime); } if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { camera_.keyboardCallback(Camera::LEFT, deltaTime); } if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) { camera_.keyboardCallback(Camera::RIGHT, deltaTime); } lightMode_ = glfwGetKey(window, GLFW_KEY_L) == GLFW_PRESS; } static void mouseCallback(GLFWwindow* window, double x, double y) { auto* self = static_cast(glfwGetWindowUserPointer(window)); if (!self) { return; } self->onMouseMove(x, y); } void onMouseMove(double x, double y) { float xpos = static_cast(x); float ypos = static_cast(y); if (camera_.firstMouse()) { lastX_ = x; lastY_ = y; camera_.triggleFirstMouse(); } float xoffset = xpos - lastX_; float yoffset = lastY_ - ypos; lastX_ = xpos; lastY_ = ypos; camera_.mouseMoveCallback(xoffset, yoffset); } static void scrollCallback(GLFWwindow* window, double xoffset, double yoffset) { auto* self = static_cast(glfwGetWindowUserPointer(window)); if (!self) { return; } self->onScrollRoll(xoffset, yoffset); } void onScrollRoll(double xoffset, double yoffset) { camera_.mouseScrollCallback(yoffset); } private: std::unique_ptr bgProg_; std::unique_ptr> window_; std::string bgFragShaderPath_; std::string bgVertShaderPath_; unsigned int bgVao_ = 0; unsigned int bgVbo_ = 0; std::unique_ptr panelProg_; std::string panelVertShaderPath_; std::string panelFragShaderPath_; unsigned int panelVao_ = 0; unsigned int panelVbo_ = 0; unsigned int panelIbo_ = 0; float panelWidth_ = 0.25; float panelHeight_ = 0.35; float panelDepth_ = 0.05; std::unique_ptr heatmapProg_; std::string heatmapVertShaderPath_; std::string heatmapFragShaderPath_; unsigned int heatmapVao_ = 0; unsigned int heatmapVbo_ = 0; ViewPort viewport_{800, 600}; Camera camera_{glm::vec3(0.0f, 0.0f, 2.0f)}; bool firstMouse_ = true; float lastX_; float lastY_; float lastFrame_ = 0.0f; bool lightMode_ = false; bool deinit_; }; int main() { { GLWidget glw({800, 600}); glw.setBgShaderPath("../shader/bg.vert", "../shader/bg.frag"); glw.setPanelShaderPath("../shader/panel.vert", "../shader/panel.frag"); glw.eventLoop(); } glfwTerminate(); return 0; }