惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
The Exploit Database - CXSecurity.com
F
Fortinet All Blogs
U
Unit 42
F
Full Disclosure
雷峰网
雷峰网
博客园 - 司徒正美
云风的 BLOG
云风的 BLOG
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
The Cloudflare Blog
Last Week in AI
Last Week in AI
罗磊的独立博客
D
DataBreaches.Net
C
Check Point Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
O
OpenAI News
C
CXSECURITY Database RSS Feed - CXSecurity.com
aimingoo的专栏
aimingoo的专栏
S
Security @ Cisco Blogs
大猫的无限游戏
大猫的无限游戏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
SegmentFault 最新的问题
NISL@THU
NISL@THU
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Hacker News
The Hacker News
Webroot Blog
Webroot Blog
Security Latest
Security Latest
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Google DeepMind News
Google DeepMind News
酷 壳 – CoolShell
酷 壳 – CoolShell
N
News | PayPal Newsroom
P
Proofpoint News Feed
B
Blog RSS Feed
MongoDB | Blog
MongoDB | Blog
C
Cybersecurity and Infrastructure Security Agency CISA
N
News and Events Feed by Topic
Google Online Security Blog
Google Online Security Blog
H
Help Net Security
Spread Privacy
Spread Privacy
T
Threat Research - Cisco Blogs
GbyAI
GbyAI
I
Intezer
Application and Cybersecurity Blog
Application and Cybersecurity Blog
M
MIT News - Artificial intelligence
Vercel News
Vercel News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
IT之家
IT之家
MyScale Blog
MyScale Blog
腾讯CDC

博客园 - 华腾智算

smart-water 融合多端协同总体架构设计方案 现代前端架构的核心思想 极简设计框架 跨平台弹性栅格理念设计 多端统一设计理念 一套规则,多端伸缩的UI设计理念 现代栅格设计之一 设计中的栅格系统 智慧水利顶层设计之何为“水利矩阵”与“数字孪生” 从古典Web到AI原生超级应用:团队学习路线与未来架构蓝图 最新架构设计 前端代码规范 v1.0 树型菜单全功能代码 最终最佳实践操作文档:统信UOS VSCode 全栈开发环境配置(基于 Chromium 浏览器) vscode-setting.json配置 VSCode 全栈开发环境初始化设置与跨平台配置指南(Windows/macOS 通用) VScode完整的跨平台适配方案 完整的跨平台 settings.json(飞雪飘鸿优化版) 数字孪生破局之道 完整的GLFW应用程序示例 程序方向 web三维 第一步,第一行,开始 绘制三角形 明确目标 从文本文件加载指令到模拟内存中,并显示前11个内存单元的内容 使用Python的pydub库播放音乐并打印二进制数据 python的音频处理 python加密与解密 mainwindows.cpp 十进制数213转换为二进制数的完整过程,使用除2取余法(也称为“重复除法法”) 二进制数 \((-1101.101)_2\) 转换为十进制数 - 华腾智算
雏形
华腾智算 · 2025-09-24 · via 博客园 - 华腾智算
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <vector>
#include <string>

// 窗口尺寸
const unsigned int SCR_WIDTH = 1280;
const unsigned int SCR_HEIGHT = 720;

// 菜单栏常量
const int MENU_HEIGHT = 30;
const int MENU_ITEM_WIDTH = 100;

// 相机参数
glm::vec3 cameraPos = glm::vec3(0.0f, 50.0f, 150.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
float yaw = -90.0f;    // 偏航角
float pitch = 0.0f;    // 俯仰角
float fov = 75.0f;     // 视野角
bool firstMouse = true;
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
float deltaTime = 0.0f;
float lastFrame = 0.0f;
bool mousePressed = false;
bool isDragging = false;
glm::vec2 dragStart;

// 菜单状态
enum MenuItem {
    MENU_NONE,
    MENU_FILE,
    MENU_VIEW,
    MENU_HELP
};

enum FileSubmenu {
    FILE_NONE,
    FILE_NEW,
    FILE_EXIT
};

enum ViewSubmenu {
    VIEW_NONE,
    VIEW_RESET_CAMERA,
    VIEW_WIREFRAME,
    VIEW_SOLID
};

MenuItem activeMenu = MENU_NONE;
FileSubmenu activeFileSubmenu = FILE_NONE;
ViewSubmenu activeViewSubmenu = VIEW_NONE;
bool wireframeMode = false;

// 物体选择相关
enum SelectedObject {
    SELECT_NONE,
    SELECT_DAM,
    SELECT_WATER,
    SELECT_MOUNTAIN
};
SelectedObject selectedObject = SELECT_NONE;
std::string objectInfo = "未选择任何物体";

// 鼠标回调函数
void mouseCallback(GLFWwindow* window, double xpos, double ypos) {
    // 检查是否在菜单栏区域
    if (ypos < MENU_HEIGHT) {
        // 处理菜单鼠标移动
        int x = static_cast<int>(xpos);
        int y = static_cast<int>(ypos);
        
        if (mousePressed) {
            // 处理菜单点击
            if (x < MENU_ITEM_WIDTH) {
                activeMenu = MENU_FILE;
                activeViewSubmenu = VIEW_NONE;
            } else if (x < 2 * MENU_ITEM_WIDTH) {
                activeMenu = MENU_VIEW;
                activeFileSubmenu = FILE_NONE;
            } else if (x < 3 * MENU_ITEM_WIDTH) {
                activeMenu = MENU_HELP;
                activeFileSubmenu = FILE_NONE;
                activeViewSubmenu = VIEW_NONE;
            } else {
                activeMenu = MENU_NONE;
                activeFileSubmenu = FILE_NONE;
                activeViewSubmenu = VIEW_NONE;
            }
        }
        return;
    }

    // 处理3D场景鼠标交互
    if (firstMouse) {
        lastX = xpos;
        lastY = ypos;
        firstMouse = false;
    }

    if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) {
        if (!isDragging) {
            isDragging = true;
            dragStart = glm::vec2(xpos, ypos);
        } else {
            float xoffset = xpos - lastX;
            float yoffset = lastY - ypos;
            lastX = xpos;
            lastY = ypos;

            float sensitivity = 0.1f;
            xoffset *= sensitivity;
            yoffset *= sensitivity;

            yaw += xoffset;
            pitch += yoffset;

            if (pitch > 89.0f) pitch = 89.0f;
            if (pitch < -89.0f) pitch = -89.0f;

            glm::vec3 front;
            front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
            front.y = sin(glm::radians(pitch));
            front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
            cameraFront = glm::normalize(front);
        }
    } else {
        if (isDragging) {
            isDragging = false;
            // 检测点击选择(简化版)
            glm::vec2 dragEnd(xpos, ypos);
            if (glm::length(dragEnd - dragStart) < 5.0f) {
                // 这里使用简单的位置判断模拟射线检测
                float clickX = (2.0f * xpos) / SCR_WIDTH - 1.0f;
                float clickY = 1.0f - (2.0f * ypos) / SCR_HEIGHT;
                
                // 简化的物体选择逻辑
                if (clickY > -0.5f && clickY < 0.5f && clickX > -0.3f && clickX < 0.3f) {
                    selectedObject = SELECT_DAM;
                    objectInfo = "大坝: 混凝土结构,高度50米";
                } else if (clickY < -0.2f && clickX > -0.6f && clickX < 0.6f) {
                    selectedObject = SELECT_WATER;
                    objectInfo = "水体: 库容约500万立方米";
                } else if ((clickX < -0.5f || clickX > 0.5f) && clickY < 0.3f) {
                    selectedObject = SELECT_MOUNTAIN;
                    objectInfo = "山体: 岩石结构,高度80米";
                } else {
                    selectedObject = SELECT_NONE;
                    objectInfo = "未选择任何物体";
                }
            }
        }
        firstMouse = true;
    }
}

// 鼠标按钮回调
void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) {
    if (button == GLFW_MOUSE_BUTTON_LEFT) {
        if (action == GLFW_PRESS) {
            mousePressed = true;
        } else if (action == GLFW_RELEASE) {
            mousePressed = false;
            
            // 检查子菜单点击
            double xpos, ypos;
            glfwGetCursorPos(window, &xpos, &ypos);
            int x = static_cast<int>(xpos);
            int y = static_cast<int>(ypos);
            
            if (activeMenu == MENU_FILE && y > MENU_HEIGHT && y < MENU_HEIGHT + 30 * 2) {
                if (x < MENU_ITEM_WIDTH) {
                    if (y < MENU_HEIGHT + 30) {
                        activeFileSubmenu = FILE_NEW;
                        // 重置场景
                        cameraPos = glm::vec3(0.0f, 50.0f, 150.0f);
                        cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
                        yaw = -90.0f;
                        pitch = 0.0f;
                        fov = 75.0f;
                        selectedObject = SELECT_NONE;
                        objectInfo = "未选择任何物体";
                    } else {
                        activeFileSubmenu = FILE_EXIT;
                        glfwSetWindowShouldClose(window, true);
                    }
                }
            } else if (activeMenu == MENU_VIEW && y > MENU_HEIGHT && y < MENU_HEIGHT + 30 * 3) {
                if (x < MENU_ITEM_WIDTH) {
                    if (y < MENU_HEIGHT + 30) {
                        activeViewSubmenu = VIEW_RESET_CAMERA;
                        cameraPos = glm::vec3(0.0f, 50.0f, 150.0f);
                        cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
                        yaw = -90.0f;
                        pitch = 0.0f;
                        fov = 75.0f;
                    } else if (y < MENU_HEIGHT + 60) {
                        activeViewSubmenu = VIEW_WIREFRAME;
                        wireframeMode = true;
                        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
                    } else {
                        activeViewSubmenu = VIEW_SOLID;
                        wireframeMode = false;
                        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                    }
                }
            }
            
            // 点击其他区域关闭菜单
            if (y > MENU_HEIGHT + 30 || x > MENU_ITEM_WIDTH * (activeMenu == MENU_FILE ? 1 : 1)) {
                activeMenu = MENU_NONE;
                activeFileSubmenu = FILE_NONE;
                activeViewSubmenu = VIEW_NONE;
            }
        }
    }
}

// 滚轮回调函数
void scrollCallback(GLFWwindow* window, double xoffset, double yoffset) {
    fov -= (float)yoffset;
    if (fov < 1.0f) fov = 1.0f;
    if (fov > 120.0f) fov = 120.0f;
}

// 处理键盘输入
void processInput(GLFWwindow* window) {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);

    float cameraSpeed = 2.5f * deltaTime;
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
        cameraPos += cameraSpeed * cameraFront;
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
        cameraPos -= cameraSpeed * cameraFront;
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
        cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
    if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
        cameraPos += cameraSpeed * cameraUp;
    if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
        cameraPos -= cameraSpeed * cameraUp;
}

// 编译着色器
unsigned int compileShader(unsigned int type, const char* source) {
    unsigned int id = glCreateShader(type);
    glShaderSource(id, 1, &source, nullptr);
    glCompileShader(id);

    int result;
    glGetShaderiv(id, GL_COMPILE_STATUS, &result);
    if (result == GL_FALSE) {
        int length;
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
        char* message = (char*)alloca(length * sizeof(char));
        glGetShaderInfoLog(id, length, &length, message);
        std::cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader!" << std::endl;
        std::cout << message << std::endl;
        glDeleteShader(id);
        return 0;
    }

    return id;
}

// 创建着色器程序
unsigned int createShaderProgram(const char* vertexSource, const char* fragmentSource) {
    unsigned int vertexShader = compileShader(GL_VERTEX_SHADER, vertexSource);
    unsigned int fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentSource);

    unsigned int program = glCreateProgram();
    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);
    glLinkProgram(program);

    int result;
    glGetProgramiv(program, GL_LINK_STATUS, &result);
    if (result == GL_FALSE) {
        int length;
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
        char* message = (char*)alloca(length * sizeof(char));
        glGetProgramInfoLog(program, length, &length, message);
        std::cout << "Failed to link shader program!" << std::endl;
        std::cout << message << std::endl;
        glDeleteProgram(program);
        return 0;
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    return program;
}

// 创建立方体
unsigned int createCube(float width, float height, float depth, const glm::vec3& color) {
    float w = width / 2.0f;
    float h = height / 2.0f;
    float d = depth / 2.0f;

    float vertices[] = {
        // 位置                // 颜色
        -w, -h, -d,  color.r, color.g, color.b,
         w, -h, -d,  color.r, color.g, color.b,
         w,  h, -d,  color.r, color.g, color.b,
         w,  h, -d,  color.r, color.g, color.b,
        -w,  h, -d,  color.r, color.g, color.b,
        -w, -h, -d,  color.r, color.g, color.b,

        -w, -h,  d,  color.r, color.g, color.b,
         w, -h,  d,  color.r, color.g, color.b,
         w,  h,  d,  color.r, color.g, color.b,
         w,  h,  d,  color.r, color.g, color.b,
        -w,  h,  d,  color.r, color.g, color.b,
        -w, -h,  d,  color.r, color.g, color.b,

        -w,  h,  d,  color.r, color.g, color.b,
        -w,  h, -d,  color.r, color.g, color.b,
        -w, -h, -d,  color.r, color.g, color.b,
        -w, -h, -d,  color.r, color.g, color.b,
        -w, -h,  d,  color.r, color.g, color.b,
        -w,  h,  d,  color.r, color.g, color.b,

         w,  h,  d,  color.r, color.g, color.b,
         w,  h, -d,  color.r, color.g, color.b,
         w, -h, -d,  color.r, color.g, color.b,
         w, -h, -d,  color.r, color.g, color.b,
         w, -h,  d,  color.r, color.g, color.b,
         w,  h,  d,  color.r, color.g, color.b,

        -w, -h, -d,  color.r, color.g, color.b,
         w, -h, -d,  color.r, color.g, color.b,
         w, -h,  d,  color.r, color.g, color.b,
         w, -h,  d,  color.r, color.g, color.b,
        -w, -h,  d,  color.r, color.g, color.b,
        -w, -h, -d,  color.r, color.g, color.b,

        -w,  h, -d,  color.r, color.g, color.b,
         w,  h, -d,  color.r, color.g, color.b,
         w,  h,  d,  color.r, color.g, color.b,
         w,  h,  d,  color.r, color.g, color.b,
        -w,  h,  d,  color.r, color.g, color.b,
        -w,  h, -d,  color.r, color.g, color.b
    };

    unsigned int VAO, VBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 位置属性
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    
    // 颜色属性
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    return VAO;
}

// 创建平面
unsigned int createPlane(float width, float height, const glm::vec3& color) {
    float w = width / 2.0f;
    float h = height / 2.0f;

    float vertices[] = {
        // 位置                // 颜色
        -w, 0.0f, -h,  color.r, color.g, color.b,
         w, 0.0f, -h,  color.r, color.g, color.b,
         w, 0.0f,  h,  color.r, color.g, color.b,
         w, 0.0f,  h,  color.r, color.g, color.b,
        -w, 0.0f,  h,  color.r, color.g, color.b,
        -w, 0.0f, -h,  color.r, color.g, color.b
    };

    unsigned int VAO, VBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 位置属性
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    
    // 颜色属性
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    return VAO;
}

// 创建锥体(简化版山体)
unsigned int createCone(float radius, float height, int segments, const glm::vec3& color) {
    std::vector<float> vertices;

    // 底部中心
    vertices.insert(vertices.end(), {0.0f, 0.0f, 0.0f, color.r, color.g, color.b});

    // 底部边缘
    for (int i = 0; i < segments; i++) {
        float angle = 2.0f * glm::pi<float>() * (float)i / (float)segments;
        float x = radius * cos(angle);
        float z = radius * sin(angle);
        vertices.insert(vertices.end(), {x, 0.0f, z, color.r, color.g, color.b});
    }

    // 顶部点
    vertices.insert(vertices.end(), {0.0f, height, 0.0f, color.r, color.g, color.b});

    // 底部三角形
    for (int i = 0; i < segments; i++) {
        int next = (i + 1) % segments;
        vertices.insert(vertices.end(), {
            0.0f, 0.0f, 0.0f, color.r, color.g, color.b,
            radius * cos(2.0f * glm::pi<float>() * (float)next / (float)segments), 0.0f, radius * sin(2.0f * glm::pi<float>() * (float)next / (float)segments), color.r, color.g, color.b,
            radius * cos(2.0f * glm::pi<float>() * (float)i / (float)segments), 0.0f, radius * sin(2.0f * glm::pi<float>() * (float)i / (float)segments), color.r, color.g, color.b
        });
    }

    // 侧面三角形
    for (int i = 0; i < segments; i++) {
        int next = (i + 1) % segments;
        vertices.insert(vertices.end(), {
            0.0f, height, 0.0f, color.r, color.g, color.b,
            radius * cos(2.0f * glm::pi<float>() * (float)i / (float)segments), 0.0f, radius * sin(2.0f * glm::pi<float>() * (float)i / (float)segments), color.r, color.g, color.b,
            radius * cos(2.0f * glm::pi<float>() * (float)next / (float)segments), 0.0f, radius * sin(2.0f * glm::pi<float>() * (float)next / (float)segments), color.r, color.g, color.b
        });
    }

    unsigned int VAO, VBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW);

    // 位置属性
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    
    // 颜色属性
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    return VAO;
}

// 渲染2D矩形(用于菜单)
void renderRect(float x, float y, float width, float height, const glm::vec3& color, unsigned int shaderProgram) {
    float vertices[] = {
        x, y, 0.0f, color.r, color.g, color.b,
        x + width, y, 0.0f, color.r, color.g, color.b,
        x + width, y + height, 0.0f, color.r, color.g, color.b,
        x + width, y + height, 0.0f, color.r, color.g, color.b,
        x, y + height, 0.0f, color.r, color.g, color.b,
        x, y, 0.0f, color.r, color.g, color.b
    };

    unsigned int VAO, VBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    glDrawArrays(GL_TRIANGLES, 0, 6);

    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
}

// 渲染菜单
void renderMenu(unsigned int shaderProgram) {
    // 保存当前矩阵状态
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    glOrtho(0, SCR_WIDTH, SCR_HEIGHT, 0, -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();

    // 禁用深度测试以正确显示UI
    glDisable(GL_DEPTH_TEST);

    // 渲染主菜单条
    renderRect(0, 0, SCR_WIDTH, MENU_HEIGHT, glm::vec3(0.3f, 0.3f, 0.3f), shaderProgram);
    
    // 渲染菜单项
    renderRect(0, 0, MENU_ITEM_WIDTH, MENU_HEIGHT, glm::vec3(0.4f, 0.4f, 0.4f), shaderProgram);
    renderRect(MENU_ITEM_WIDTH, 0, MENU_ITEM_WIDTH, MENU_HEIGHT, glm::vec3(0.4f, 0.4f, 0.4f), shaderProgram);
    renderRect(2 * MENU_ITEM_WIDTH, 0, MENU_ITEM_WIDTH, MENU_HEIGHT, glm::vec3(0.4f, 0.4f, 0.4f), shaderProgram);

    // 恢复着色器程序的模型矩阵
    glm::mat4 model = glm::mat4(1.0f);
    glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
    glm::mat4 view = glm::mat4(1.0f);
    glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, glm::value_ptr(view));
    glm::mat4 projection = glm::ortho(0.0f, (float)SCR_WIDTH, (float)SCR_HEIGHT, 0.0f, -1.0f, 1.0f);
    glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));

    // 渲染文件子菜单
    if (activeMenu == MENU_FILE) {
        renderRect(0, MENU_HEIGHT, MENU_ITEM_WIDTH, 60, glm::vec3(0.4f, 0.4f, 0.4f), shaderProgram);
        renderRect(0, MENU_HEIGHT, MENU_ITEM_WIDTH, 30, glm::vec3(0.5f, 0.5f, 0.5f), shaderProgram);
        renderRect(0, MENU_HEIGHT + 30, MENU_ITEM_WIDTH, 30, glm::vec3(0.5f, 0.5f, 0.5f), shaderProgram);
    }
    
    // 渲染视图子菜单
    if (activeMenu == MENU_VIEW) {
        renderRect(MENU_ITEM_WIDTH, MENU_HEIGHT, MENU_ITEM_WIDTH, 90, glm::vec3(0.4f, 0.4f, 0.4f), shaderProgram);
        renderRect(MENU_ITEM_WIDTH, MENU_HEIGHT, MENU_ITEM_WIDTH, 30, glm::vec3(0.5f, 0.5f, 0.5f), shaderProgram);
        renderRect(MENU_ITEM_WIDTH, MENU_HEIGHT + 30, MENU_ITEM_WIDTH, 30, glm::vec3(0.5f, 0.5f, 0.5f), shaderProgram);
        renderRect(MENU_ITEM_WIDTH, MENU_HEIGHT + 60, MENU_ITEM_WIDTH, 30, glm::vec3(0.5f, 0.5f, 0.5f), shaderProgram);
    }

    // 渲染帮助子菜单
    if (activeMenu == MENU_HELP) {
        renderRect(2 * MENU_ITEM_WIDTH, MENU_HEIGHT, MENU_ITEM_WIDTH, 30, glm::vec3(0.4f, 0.4f, 0.4f), shaderProgram);
    }

    // 渲染物体信息面板
    renderRect(SCR_WIDTH - 300, MENU_HEIGHT, 300, 30, glm::vec3(0.2f, 0.2f, 0.2f), shaderProgram);

    // 恢复深度测试
    glEnable(GL_DEPTH_TEST);

    // 恢复矩阵状态
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
}

int main() {
    // 初始化GLFW
    if (!glfwInit()) {
        std::cerr << "Failed to initialize GLFW" << std::endl;
        return -1;
    }

    // 设置OpenGL版本
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // 创建窗口
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "大坝3D模型", NULL, NULL);
    if (!window) {
        std::cerr << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);

    // 设置回调函数
    glfwSetCursorPosCallback(window, mouseCallback);
    glfwSetMouseButtonCallback(window, mouseButtonCallback);
    glfwSetScrollCallback(window, scrollCallback);
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);

    // 初始化GLEW
    if (glewInit() != GLEW_OK) {
        std::cerr << "Failed to initialize GLEW" << std::endl;
        return -1;
    }

    // 启用深度测试
    glEnable(GL_DEPTH_TEST);
    // 启用混合(用于半透明效果)
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // 顶点着色器代码
    const char* vertexShaderSource = "#version 330 core\n"
        "layout (location = 0) in vec3 aPos;\n"
        "layout (location = 1) in vec3 aColor;\n"
        "out vec3 ourColor;\n"
        "uniform mat4 model;\n"
        "uniform mat4 view;\n"
        "uniform mat4 projection;\n"
        "void main()\n"
        "{\n"
        "   gl_Position = projection * view * model * vec4(aPos, 1.0);\n"
        "   ourColor = aColor;\n"
        "}\0";

    // 片段着色器代码
    const char* fragmentShaderSource = "#version 330 core\n"
        "in vec3 ourColor;\n"
        "out vec4 FragColor;\n"
        "void main()\n"
        "{\n"
        "   FragColor = vec4(ourColor, 1.0);\n"
        "}\0";

    // 创建着色器程序
    unsigned int shaderProgram = createShaderProgram(vertexShaderSource, fragmentShaderSource);
    if (!shaderProgram) return -1;

    // 创建场景元素
    // 地面
    unsigned int groundVAO = createPlane(500, 500, glm::vec3(0.545f, 0.271f, 0.075f)); // 棕色

    // 水体
    unsigned int waterVAO = createPlane(300, 200, glm::vec3(0.275f, 0.509f, 0.706f)); // 钢蓝色

    // 左侧山体
    unsigned int leftMountainVAO = createCone(100, 80, 4, glm::vec3(0.133f, 0.545f, 0.133f)); // 绿色

    // 右侧山体
    unsigned int rightMountainVAO = createCone(100, 70, 4, glm::vec3(0.133f, 0.545f, 0.133f)); // 绿色

    // 远处山体
    unsigned int farMountainVAO = createCone(135, 50, 4, glm::vec3(0.133f, 0.4f, 0.133f)); // 深绿色

    // 大坝基础
    unsigned int damBaseVAO = createCube(100, 20, 40, glm::vec3(0.533f, 0.533f, 0.533f)); // 灰色

    // 大坝正面倾斜部分
    unsigned int damSlopeVAO = createCube(100, 30, 20, glm::vec3(0.533f, 0.533f, 0.533f)); // 灰色

    // 坝顶结构
    unsigned int damTopVAO = createCube(100, 5, 10, glm::vec3(0.533f, 0.533f, 0.533f)); // 灰色

    // 水闸塔(使用浅灰色)
    glm::vec3 towerColor = glm::vec3(0.8f, 0.8f, 0.8f);
    unsigned int leftTower1VAO = createCube(6, 20, 10, towerColor);
    unsigned int leftTower2VAO = createCube(6, 20, 10, towerColor);
    unsigned int centerTower1VAO = createCube(6, 25, 10, towerColor);
    unsigned int centerTower2VAO = createCube(6, 25, 10, towerColor);
    unsigned int rightTower1VAO = createCube(6, 20, 10, towerColor);
    unsigned int rightTower2VAO = createCube(6, 20, 10, towerColor);

    // 右侧建筑
    unsigned int rightBuildingVAO = createCube(15, 15, 10, towerColor);

    // 渲染循环
    while (!glfwWindowShouldClose(window)) {
        // 计算时间差
        float currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;

        // 处理输入
        processInput(window);

        // 清空颜色缓冲和深度缓冲
        glClearColor(0.533f, 0.808f, 0.922f, 1.0f); // 天空蓝
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // 使用着色器程序
        glUseProgram(shaderProgram);

        // 视图矩阵
        glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, glm::value_ptr(view));

        // 投影矩阵
        glm::mat4 projection = glm::perspective(glm::radians(fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 2000.0f);
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));

        // 绘制地面
        glm::mat4 model = glm::mat4(1.0f);
        model = glm::rotate(model, glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(groundVAO);
        glDrawArrays(GL_TRIANGLES, 0, 6);

        // 绘制远处山体
        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(0, 0, -200));
        model = glm::rotate(model, glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
        model = glm::rotate(model, glm::radians(180.0f), glm::vec3(0.0f, 1.0f, 0.0f));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(farMountainVAO);
        glDrawArrays(GL_TRIANGLES, 0, 4*3 + 4*3); // 底部4个三角形 + 侧面4个三角形

        // 绘制左侧山体
        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(-150, 20, -50));
        model = glm::rotate(model, glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
        model = glm::rotate(model, glm::radians(45.0f), glm::vec3(0.0f, 1.0f, 0.0f));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(leftMountainVAO);
        glDrawArrays(GL_TRIANGLES, 0, 4*3 + 4*3);

        // 绘制右侧山体
        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(150, 15, -50));
        model = glm::rotate(model, glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
        model = glm::rotate(model, glm::radians(-45.0f), glm::vec3(0.0f, 1.0f, 0.0f));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(rightMountainVAO);
        glDrawArrays(GL_TRIANGLES, 0, 4*3 + 4*3);

        // 绘制水体(半透明)
        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(0, 5, -100));
        model = glm::rotate(model, glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(waterVAO);
        glDrawArrays(GL_TRIANGLES, 0, 6);

        // 绘制大坝基础
        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(0, 10, 0));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(damBaseVAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);

        // 绘制大坝倾斜部分
        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(0, 25, -10));
        model = glm::rotate(model, glm::radians(-17.19f), glm::vec3(1.0f, 0.0f, 0.0f)); // -0.3弧度 ≈ -17.19度
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(damSlopeVAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);

        // 绘制坝顶结构
        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(0, 30, 20));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(damTopVAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);

        // 绘制水闸塔
        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(-30, 40, 20));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(leftTower1VAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);

        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(-15, 40, 20));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(leftTower2VAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);

        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(-5, 45, 20));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(centerTower1VAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);

        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(5, 45, 20));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(centerTower2VAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);

        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(15, 40, 20));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(rightTower1VAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);

        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(30, 40, 20));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(rightTower2VAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);

        // 绘制右侧建筑
        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(55, 35, 20));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glBindVertexArray(rightBuildingVAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);

        // 渲染菜单
        renderMenu(shaderProgram);

        // 交换缓冲并轮询事件
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 清理资源
    glDeleteVertexArrays(1, &groundVAO);
    glDeleteVertexArrays(1, &waterVAO);
    glDeleteVertexArrays(1, &leftMountainVAO);
    glDeleteVertexArrays(1, &rightMountainVAO);
    glDeleteVertexArrays(1, &farMountainVAO);
    glDeleteVertexArrays(1, &damBaseVAO);
    glDeleteVertexArrays(1, &damSlopeVAO);
    glDeleteVertexArrays(1, &damTopVAO);
    glDeleteVertexArrays(1, &leftTower1VAO);
    glDeleteVertexArrays(1, &leftTower2VAO);
    glDeleteVertexArrays(1, &centerTower1VAO);
    glDeleteVertexArrays(1, &centerTower2VAO);
    glDeleteVertexArrays(1, &rightTower1VAO);
    glDeleteVertexArrays(1, &rightTower2VAO);
    glDeleteVertexArrays(1, &rightBuildingVAO);
    glDeleteProgram(shaderProgram);

    // 终止GLFW
    glfwTerminate();
    return 0;
}