Azemmmm
Azemmmm

Reputation: 39

How to use OpenGL3 + (VAO, VBO) to draw lines with mouse click?

I'm trying to use glfw+glad to draw lines with mouse click input coordinates. At first i tried to use glBegin, glVertex2f but they seems to be no longer supported in OpenGL3+. So i tried to use VAO, VBO to draw lines, but the actual program doesn't react on my click.

Program Running:

Program Running

Here is my code:

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <iostream>
#include <vector>
#include <cmath>


class Vec3 {
public:
    float x, y, z;

    Vec3() : x(0), y(0), z(0) {}
    Vec3(float x, float y, float z) : x(x), y(y), z(z) {}

    Vec3 operator+(const Vec3& other) const {
        return Vec3(x + other.x, y + other.y, z + other.z);
    }

    Vec3 operator-(const Vec3& other) const {
        return Vec3(x - other.x, y - other.y, z - other.z);
    }

    Vec3 operator*(float scalar) const {
        return Vec3(x * scalar, y * scalar, z * scalar);
    }

    Vec3 operator/(float scalar) const {
        return Vec3(x / scalar, y / scalar, z / scalar);
    }
};


void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
void mouse_button_callback(GLFWwindow* window,int button, int action, int mods);


const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

bool firstClick = true;
float x0,y0,z0,x1,y1,z1;

class Line{
    int shaderProgram;
    unsigned int VBO,VAO;
    std::vector<float> vertices;
    Vec3 startPoint;
    Vec3 endPoint;
    Vec3 lineColor;
public:
    Line(Vec3 start,Vec3 end){
        startPoint = start;
        endPoint = end;
        lineColor = Vec3(1.0f,1.0f,1.0f);
        init();
    }
    void init(){
        const char *vertexShaderSource = "#version 330 core\n"
            "layout (location = 0) in vec3 aPos;\n"
            "void main()\n"
            "{\n"
            "   gl_Position = vec4(aPos.x,aPos.y,aPos.z,1.0);\n"
            "}\0";
        const char* fragmentShaderSource = "#version 330 core\n"
            "out vec4 FragColor;\n"
            "uniform vec3 color;\n"
            "void main()\n"
            "{\n"
            "   FragColor = vec4(color, 1.0f);\n"
            "}\n\0";
        
    //vertex Shader
        unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexShader,1,&vertexShaderSource,NULL);
        glCompileShader(vertexShader);
    //check for shader compile errors
        int  success;
        char infoLog[512];
        glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);

        if(!success)
        {
            glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
            std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
        }

    //fragment shader
        unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragmentShader,1,&fragmentShaderSource,NULL);
        glCompileShader(fragmentShader);
    //check for shader compile errors
        glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
        if(!success)
        {
            glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
            std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
        }

    //link shaders
        shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram, vertexShader);
        glAttachShader(shaderProgram,fragmentShader);
        glLinkProgram(shaderProgram);
    //check for linking errors
        glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
        if (!success) {
            glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
            std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
        }

        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);

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

        glBindVertexArray(VAO);

        glBindBuffer(GL_ARRAY_BUFFER,VBO);
        glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices.data(),GL_STATIC_DRAW);

        glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);
        glEnableVertexAttribArray(0);
        
        glBindBuffer(GL_ARRAY_BUFFER,0);
        glBindVertexArray(0);
    }


    void updateVerticesDDA(){
        vertices.clear();
        float x0 = startPoint.x;
        float y0 = startPoint.y;
        float x1 = endPoint.x;
        float y1 = endPoint.y;
        float dx = x1 - x0;
        float dy = y1 - y0;
        float steps = std::max(std::abs(dx), std::abs(dy));
        float xIncrement = dx / steps;
        float yIncrement = dy / steps;

        float x = x0;
        float y = y0;

        for (int i = 0; i <= steps; ++i)
        {
            vertices.push_back(x);
            vertices.push_back(y);
            vertices.push_back(0.0f); // z-coordinate
            x += xIncrement;
            y += yIncrement;
        }

        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(float), vertices.data());
    }

    int draw(){
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
        glDrawArrays(GL_POINTS,0,vertices.size()/3);
        return 1;
    }

    ~Line(){
        glDeleteVertexArrays(1,&VAO);
        glDeleteBuffers(1,&VBO);
        glDeleteProgram(shaderProgram);
    }

void updateVerticesBresenham() {
        vertices.clear();
        int x0 = startPoint.x * SCR_WIDTH / 2 + SCR_WIDTH / 2;
        int y0 = startPoint.y * SCR_HEIGHT / 2 + SCR_HEIGHT / 2;
        int x1 = endPoint.x * SCR_WIDTH / 2 + SCR_WIDTH / 2;
        int y1 = endPoint.y * SCR_HEIGHT / 2 + SCR_HEIGHT / 2;
        int dx = abs(x1 - x0);
        int dy = abs(y1 - y0);
        int sx = (x0 < x1) ? 1 : -1;
        int sy = (y0 < y1) ? 1 : -1;
        int err = dx - dy;

        while (true)
        {
            vertices.push_back((x0 - SCR_WIDTH / 2) / (SCR_WIDTH / 2));
            vertices.push_back((SCR_HEIGHT / 2 - y0) / (SCR_HEIGHT / 2));
            vertices.push_back(0.0f); // z-coordinate
            if (x0 == x1 && y0 == y1)
                break;
            int e2 = 2 * err;
            if (e2 > -dy)
            {
                err -= dy;
                x0 += sx;
            }
            if (e2 < dx)
            {
                err += dx;
                y0 += sy;
            }
        }

        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(float), vertices.data());
    }

};



int main()
{
    glfwInit();
    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, "Line Drawing with DDA / Bresenham", 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);

    Vec3 start(x0,y0,z0);
    Vec3 end(x1,y1,z1);
    Line line(start,end);


    //loop for render
    while(!glfwWindowShouldClose(window))
    {
       
        processInput(window);

        glClearColor(0.2f,0.3f,0.3f,1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        line.updateVerticesDDA();
        line.draw();

        glfwSwapBuffers(window);
        glfwPollEvents();    
    }

    

    glfwTerminate();
    return 0;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

void processInput(GLFWwindow *window){
    if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window,true);
}

void mouse_button_callback(GLFWwindow* window,int button,int action,int mods){
    if(button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
    {
        double xpos,ypos;
        glfwGetCursorPos(window,&xpos,&ypos);

        if (firstClick)
        {
            x0 = (xpos - SCR_WIDTH / 2) / (SCR_WIDTH / 2);
            y0 = (SCR_HEIGHT / 2 - ypos) / (SCR_HEIGHT / 2);
            z0 = 0.0f; // 2D plane
            firstClick = false;
        }
        else
        {
            x1 = (xpos - SCR_WIDTH / 2) / (SCR_WIDTH / 2);
            y1 = (SCR_HEIGHT / 2 - ypos) / (SCR_HEIGHT / 2);
            z1 = 0.0f; // 2D plane
            firstClick = true;

        }
    }
}

I don't know whether it's the mouse callback function or the Line class that went wrong.

Help me to figure out what part went wrong.

BTW can the VBO method enable straight line drawing under the DDA algorithm? It's kinda easy when using glVertex2f method (I tried to updates vertices and draw many points but i got stuck here qaq)

Upvotes: 1

Views: 112

Answers (0)

Related Questions