完整的GLFW应用程序示例
/* * 完整的GLFW应用程序示例 * 包含窗口创建、输入处理、渲染循环等所有主要功能 * 每行代码都有详细注释,便于学习GLFW的使用 */ #include <GLFW/glfw3.h> // GLFW主头文件 #include <iostream> // 用于控制台输出 #include <cmath> // 用于数学计算 // 全局变量定义 GLFWwindow* g_window = nullptr; // 全局窗口指针 int g_windowWidth = 800; // 窗口宽度 int g_windowHeight = 600; // 窗口高度 float g_backgroundColor[3] = {0.2f, 0.3f, 0.3f}; // 背景颜色(RGB) bool g_wireframeMode = false; // 线框模式标志 /* * 错误回调函数 * 当GLFW发生错误时自动调用 */ void errorCallback(int error, const char* description) { std::cerr << "GLFW错误 " << error << ": " << description << std::endl; } /* * 窗口大小改变回调函数 * 当用户调整窗口大小时自动调用 */ void framebufferSizeCallback(GLFWwindow* window, int width, int height) { g_windowWidth = width; g_windowHeight = height; // 设置视口大小,匹配窗口大小 glViewport(0, 0, width, height); std::cout << "窗口大小改变: " << width << " x " << height << std::endl; } /* * 键盘按键回调函数 * 当用户按下或释放键盘按键时调用 */ void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { // 只处理按键按下事件,忽略重复和释放事件 if (action == GLFW_PRESS) { switch (key) { case GLFW_KEY_ESCAPE: // ESC键:关闭窗口 std::cout << "ESC键按下,关闭窗口" << std::endl; glfwSetWindowShouldClose(window, true); break; case GLFW_KEY_SPACE: // 空格键:切换背景颜色 g_backgroundColor[0] = static_cast<float>(rand()) / RAND_MAX; g_backgroundColor[1] = static_cast<float>(rand()) / RAND_MAX; g_backgroundColor[2] = static_cast<float>(rand()) / RAND_MAX; std::cout << "空格键按下,切换背景颜色" << std::endl; break; case GLFW_KEY_W: // W键:切换线框模式 g_wireframeMode = !g_wireframeMode; if (g_wireframeMode) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); std::cout << "线框模式: 开启" << std::endl; } else { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); std::cout << "线框模式: 关闭" << std::endl; } break; case GLFW_KEY_F: // F键:切换全屏/窗口模式 static bool fullscreen = false; fullscreen = !fullscreen; if (fullscreen) { // 获取主显示器模式 GLFWmonitor* monitor = glfwGetPrimaryMonitor(); const GLFWvidmode* mode = glfwGetVideoMode(monitor); // 切换到全屏模式 glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); std::cout << "切换到全屏模式" << std::endl; } else { // 切换到窗口模式 glfwSetWindowMonitor(window, nullptr, 100, 100, g_windowWidth, g_windowHeight, 0); std::cout << "切换到窗口模式" << std::endl; } break; case GLFW_KEY_P: // P键:打印窗口信息 int x, y; glfwGetWindowPos(window, &x, &y); std::cout << "窗口位置: (" << x << ", " << y << ")" << std::endl; std::cout << "窗口大小: " << g_windowWidth << " x " << g_windowHeight << std::endl; break; } } } /* * 鼠标移动回调函数 * 当鼠标移动时调用 */ void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { // 可以在这里处理鼠标移动逻辑 // 示例:每100次调用打印一次位置(避免过于频繁的输出) static int callCount = 0; if (callCount++ % 100 == 0) { std::cout << "鼠标位置: (" << xpos << ", " << ypos << ")" << std::endl; } } /* * 鼠标按钮回调函数 * 当鼠标按钮按下或释放时调用 */ void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { if (action == GLFW_PRESS) { double xpos, ypos; glfwGetCursorPos(window, &xpos, &ypos); switch (button) { case GLFW_MOUSE_BUTTON_LEFT: std::cout << "左键点击位置: (" << xpos << ", " << ypos << ")" << std::endl; break; case GLFW_MOUSE_BUTTON_RIGHT: std::cout << "右键点击位置: (" << xpos << ", " << ypos << ")" << std::endl; break; case GLFW_MOUSE_BUTTON_MIDDLE: std::cout << "中键点击位置: (" << xpos << ", " << ypos << ")" << std::endl; break; } } } /* * 鼠标滚轮回调函数 * 当鼠标滚轮滚动时调用 */ void scrollCallback(GLFWwindow* window, double xoffset, double yoffset) { std::cout << "鼠标滚轮: X=" << xoffset << ", Y=" << yoffset << std::endl; } /* * 窗口焦点回调函数 * 当窗口获得或失去焦点时调用 */ void windowFocusCallback(GLFWwindow* window, int focused) { if (focused) { std::cout << "窗口获得焦点" << std::endl; } else { std::cout << "窗口失去焦点" << std::endl; } } /* * 窗口图标化回调函数 * 当窗口被最小化或恢复时调用 */ void windowIconifyCallback(GLFWwindow* window, int iconified) { if (iconified) { std::cout << "窗口被最小化" << std::endl; } else { std::cout << "窗口恢复" << std::endl; } } /* * 初始化GLFW和创建窗口 * 返回true表示成功,false表示失败 */ bool initializeGLFW() { // 设置错误回调函数 glfwSetErrorCallback(errorCallback); // 初始化GLFW库 if (!glfwInit()) { std::cerr << "GLFW初始化失败!" << std::endl; return false; } // 配置GLFW窗口属性 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // OpenGL主版本号 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // OpenGL次版本号 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 使用核心模式 glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // 窗口可调整大小 glfwWindowHint(GLFW_SAMPLES, 4); // 4倍多重采样抗锯齿 #ifdef __APPLE__ // macOS需要额外的配置 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif // 创建窗口和OpenGL上下文 g_window = glfwCreateWindow(g_windowWidth, g_windowHeight, "GLFW完整示例 - 学习OpenGL", nullptr, nullptr); if (!g_window) { std::cerr << "创建GLFW窗口失败!" << std::endl; glfwTerminate(); return false; } // 将窗口的上下文设置为当前线程的主上下文 glfwMakeContextCurrent(g_window); // 设置垂直同步(1表示开启,0表示关闭) glfwSwapInterval(1); // 设置各种回调函数 glfwSetFramebufferSizeCallback(g_window, framebufferSizeCallback); glfwSetKeyCallback(g_window, keyCallback); glfwSetCursorPosCallback(g_window, cursorPosCallback); glfwSetMouseButtonCallback(g_window, mouseButtonCallback); glfwSetScrollCallback(g_window, scrollCallback); glfwSetWindowFocusCallback(g_window, windowFocusCallback); glfwSetWindowIconifyCallback(g_window, windowIconifyCallback); // 设置输入模式 glfwSetInputMode(g_window, GLFW_STICKY_KEYS, GLFW_TRUE); // 启用粘性键 glfwSetInputMode(g_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); // 正常光标模式 std::cout << "GLFW初始化成功!" << std::endl; std::cout << "控制说明:" << std::endl; std::cout << " ESC - 退出程序" << std::endl; std::cout << " 空格 - 随机改变背景颜色" << std::endl; std::cout << " W - 切换线框模式" << std::endl; std::cout << " F - 切换全屏/窗口模式" << std::endl; std::cout << " P - 打印窗口信息" << std::endl; return true; } /* * 渲染一个简单的旋转三角形 */ void renderTriangle(float time) { // 开始绘制三角形 glBegin(GL_TRIANGLES); // 计算旋转角度(随时间变化) float angle = time * 50.0f; // 每秒旋转50度 // 第一个顶点(红色) glColor3f(1.0f, 0.0f, 0.0f); // 红色 glVertex2f(0.0f * cos(angle) - 0.5f * sin(angle), 0.0f * sin(angle) + 0.5f * cos(angle)); // 第二个顶点(绿色) glColor3f(0.0f, 1.0f, 0.0f); // 绿色 glVertex2f(-0.5f * cos(angle) - (-0.5f) * sin(angle), -0.5f * sin(angle) + (-0.5f) * cos(angle)); // 第三个顶点(蓝色) glColor3f(0.0f, 0.0f, 1.0f); // 蓝色 glVertex2f(0.5f * cos(angle) - (-0.5f) * sin(angle), 0.5f * sin(angle) + (-0.5f) * cos(angle)); glEnd(); } /* * 渲染场景 */ void renderScene(float time) { // 清除颜色缓冲区 glClear(GL_COLOR_BUFFER_BIT); // 设置投影矩阵为正交投影 glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); // 设置模型视图矩阵 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // 渲染旋转三角形 renderTriangle(time); } /* * 主函数 - 程序入口点 */ int main() { std::cout << "启动GLFW应用程序..." << std::endl; // 初始化GLFW if (!initializeGLFW()) { return -1; } // 设置初始视口 glViewport(0, 0, g_windowWidth, g_windowHeight); // 获取时间基准 double lastTime = glfwGetTime(); int frameCount = 0; // 主渲染循环 while (!glfwWindowShouldClose(g_window)) { // 计算帧率 double currentTime = glfwGetTime(); frameCount++; // 每秒更新一次帧率显示 if (currentTime - lastTime >= 1.0) { std::string title = "GLFW示例 - FPS: " + std::to_string(frameCount); glfwSetWindowTitle(g_window, title.c_str()); frameCount = 0; lastTime = currentTime; } // 设置清除颜色(背景色) glClearColor(g_backgroundColor[0], g_backgroundColor[1], g_backgroundColor[2], 1.0f); // 渲染场景 renderScene(static_cast<float>(currentTime)); // 交换前后缓冲区(双缓冲技术) glfwSwapBuffers(g_window); // 处理事件(输入、窗口事件等) glfwPollEvents(); // 检查某些特定按键状态(持续按下的处理) if (glfwGetKey(g_window, GLFW_KEY_R) == GLFW_PRESS) { // R键持续按下时重置背景颜色 g_backgroundColor[0] = 0.2f; g_backgroundColor[1] = 0.3f; g_backgroundColor[2] = 0.3f; } } // 清理资源 glfwDestroyWindow(g_window); glfwTerminate(); std::cout << "程序正常退出" << std::endl; return 0; }