- opengl实现以下功能
- 1、用opengl创建一个800*800的窗口
- 2、用蓝色创建半径400的圆
- 3、在圆内布满2*2的正方形,用绿色线画
- 4、鼠标点击正方形,改变其颜色为红色,抬起鼠标回复绿色
- 5、点击正方形,输出其中心坐标

#include<glad/glad.h>
#include<GLFW/glfw3.h>
#include<iostream>
#include<cmath>
#include<vector>
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 800;
const float CIRCLE_RADIUS = 0.5f;
const float SQUARE_SIZE = 0.005f;
float scaleFactor = 1.0f;
const float SCALE_STEP = 0.1f;
float mouseX = 0.0f;
float mouseY = 0.0f;
const char* vertexShaderSource = R"(
#version 330 core
layout (location = 0) in vec2 aPos;
uniform float scale;
uniform vec2 mousePos;
void main()
{
// 先将顶点平移到以鼠标位置为原点
vec2 translated = aPos - mousePos;
// 进行缩放操作
vec2 scaled = translated * scale;
// 再平移回原来的位置
vec2 finalPos = scaled + mousePos;
gl_Position = vec4(finalPos, 0.0, 1.0);
}
)";
const char* fragmentShaderSource = R"(
#version 330 core
out vec4 FragColor;
uniform vec4 color;
void main()
{
FragColor = color;
}
)";
struct Square {
float x, y;
bool isClicked = false;
};
std::vector<Square> squares;
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos);
std::vector<float> generateCircleVertices(float x, float y, float radius, int numSegments);
void generateSquaresInCircle();
void drawCircle(unsigned int shaderProgram, unsigned int VAO, unsigned int VBO);
void drawSquares(unsigned int shaderProgram, unsigned int VAO, unsigned int VBO);
int main()
{
int glfwSate = glfwInit();
if (glfwSate == GLFW_FALSE)
{
std::cout << "GLFW initialize failed!" << std::endl;
exit(EXIT_FAILURE);
}
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, "OpenGL Circle and Squares with Zoom", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
glfwSetScrollCallback(window, scroll_callback);
glfwSetCursorPosCallback(window, cursor_position_callback);
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
glCompileShader(vertexShader);
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
std::vector<float> circleVertices = generateCircleVertices(0.0f, 0.0f, CIRCLE_RADIUS, 100);
unsigned int circleVAO, circleVBO;
glGenVertexArrays(1, &circleVAO);
glGenBuffers(1, &circleVBO);
glBindVertexArray(circleVAO);
glBindBuffer(GL_ARRAY_BUFFER, circleVBO);
glBufferData(GL_ARRAY_BUFFER, circleVertices.size() * sizeof(float), circleVertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
generateSquaresInCircle();
unsigned int squareVAO, squareVBO;
glGenVertexArrays(1, &squareVAO);
glGenBuffers(1, &squareVBO);
while (!glfwWindowShouldClose(window))
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
drawCircle(shaderProgram, circleVAO, circleVBO);
drawSquares(shaderProgram, squareVAO, squareVBO);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &circleVAO);
glDeleteBuffers(1, &circleVBO);
glDeleteVertexArrays(1, &squareVAO);
glDeleteBuffers(1, &squareVBO);
glfwTerminate();
return 0;
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button == GLFW_MOUSE_BUTTON_LEFT) {
if (action == GLFW_PRESS) {
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
float mouseX = (2.0f * xpos) / SCR_WIDTH - 1.0f;
float mouseY = 1.0f - (2.0f * ypos) / SCR_HEIGHT;
for (auto& square : squares) {
if (mouseX >= square.x * scaleFactor && mouseX <= (square.x + SQUARE_SIZE) * scaleFactor &&
mouseY >= square.y * scaleFactor && mouseY <= (square.y + SQUARE_SIZE) * scaleFactor) {
square.isClicked = true;
float centerX = (square.x + SQUARE_SIZE / 2) * scaleFactor;
float centerY = (square.y + SQUARE_SIZE / 2) * scaleFactor;
std::cout << "Clicked square center coordinates: (" << centerX << ", " << centerY << ")" << std::endl;
}
}
}
else if (action == GLFW_RELEASE) {
for (auto& square : squares) {
square.isClicked = false;
}
}
}
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
mouseX = (2.0f * xpos) / SCR_WIDTH - 1.0f;
mouseY = 1.0f - (2.0f * ypos) / SCR_HEIGHT;
if (yoffset > 0) {
scaleFactor += SCALE_STEP;
}
else {
if (scaleFactor > SCALE_STEP) {
scaleFactor -= SCALE_STEP;
}
}
}
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos)
{
}
std::vector<float> generateCircleVertices(float x, float y, float radius, int numSegments) {
std::vector<float> vertices;
for (int i = 0; i < numSegments; i++) {
float angle = 2.0f * 3.1415926f * float(i) / float(numSegments);
float dx = radius * cosf(angle);
float dy = radius * sinf(angle);
vertices.push_back(x + dx);
vertices.push_back(y + dy);
}
return vertices;
}
void generateSquaresInCircle() {
for (float y = -CIRCLE_RADIUS; y < CIRCLE_RADIUS; y += SQUARE_SIZE) {
for (float x = -CIRCLE_RADIUS; x < CIRCLE_RADIUS; x += SQUARE_SIZE) {
if (std::sqrt(x * x + y * y) <= CIRCLE_RADIUS) {
squares.push_back({ x, y });
}
}
}
}
void drawCircle(unsigned int shaderProgram, unsigned int VAO, unsigned int VBO) {
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
int scaleLocation = glGetUniformLocation(shaderProgram, "scale");
glUniform1f(scaleLocation, scaleFactor);
int mousePosLocation = glGetUniformLocation(shaderProgram, "mousePos");
glUniform2f(mousePosLocation, mouseX, mouseY);
int colorLocation = glGetUniformLocation(shaderProgram, "color");
glUniform4f(colorLocation, 0.0f, 0.0f, 1.0f, 1.0f);
glDrawArrays(GL_TRIANGLE_FAN, 0, 100);
glBindVertexArray(0);
}
void drawSquares(unsigned int shaderProgram, unsigned int VAO, unsigned int VBO) {
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
std::vector<float> squareVertices;
for (const auto& square : squares) {
float x = square.x;
float y = square.y;
squareVertices.insert(squareVertices.end(), {
x, y,
x + SQUARE_SIZE, y,
x + SQUARE_SIZE, y + SQUARE_SIZE,
x, y + SQUARE_SIZE
});
}
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, squareVertices.size() * sizeof(float), squareVertices.data(), GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
int scaleLocation = glGetUniformLocation(shaderProgram, "scale");
glUniform1f(scaleLocation, scaleFactor);
int mousePosLocation = glGetUniformLocation(shaderProgram, "mousePos");
glUniform2f(mousePosLocation, mouseX, mouseY);
int colorLocation = glGetUniformLocation(shaderProgram, "color");
for (size_t i = 0; i < squares.size(); ++i) {
if (squares[i].isClicked) {
glUniform4f(colorLocation, 1.0f, 0.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4);
}
else {
glUniform4f(colorLocation, 0.0f, 1.0f, 0.0f, 1.0f);
glDrawArrays(GL_LINE_LOOP, i * 4, 4);
}
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}