Reputation: 39
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:
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