Curvas y captura de eventos en OpenGL3+

Videos

Código

main.cpp

#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include <glm\glm.hpp>
#include <glm\gtc\type_ptr.hpp>
#include <glm\gtc\matrix_transform.hpp>

#include <string>
#include <iostream>
#include <fstream>
#include <vector>

#include "Utils.hpp"

using namespace std;

#define LOG(x) cout<<"[LOG]\t"<<(x)<<endl
#define numVAOs 1
#define numVBOs 3 
#define ANCHO 800
#define LARGO 800
#define PI 3.14159265

/*--------------- VARIABLES GLOBALES --------------- */
GLuint renderingProgram;
GLuint vao[numVAOs];
GLuint vbo[numVBOs];
vector<glm::vec2> p_control {
/*0*/ glm::vec2{0.235,0.5325},
/*1*/ glm::vec2{-0.0675,0.7675},
/*2*/ glm::vec2{-0.4075,0.475},
/*3*/ glm::vec2{-0.4,0.4675},
/*4*/ glm::vec2{-0.315,0.105},
/*5*/ glm::vec2{-0.44,-0.265},
/*6*/ glm::vec2{-0.0575,0.3},
/*7*/ glm::vec2{-0.115,0.15},
/*8*/ glm::vec2{-0.2275,0.28},
/*9*/ glm::vec2{-0.1525,0.4025},
/*10*/ glm::vec2{-0.0525,0.32}
};
vector<double> vertices;
vector<double> vertices_2;

/* ------------------------------------------------- */

/*--------------- FUNCIONES ---------------*/
void init(GLFWwindow *window);
void setupVertices();
void buildCurvas();
void display();
void addPointsCurveG2(std::vector<double> &vertices, glm::vec2 p0, glm::vec2 p1, glm::vec2 p2, int n_points);
/*--------------- CONTROLES ---------------*/
bool edit_mode = false;
int vertClickeado = -1;
bool clickPuntoControl(glm::vec2 center, float x, float y);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos);
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
/* ---------------------------------------- */
int main() {
    if (!glfwInit()) exit(EXIT_FAILURE);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    GLFWwindow * window = glfwCreateWindow(800, 800, "Curvas-01-wcontrols", NULL, NULL);
    glfwMakeContextCurrent(window);
    glfwSetKeyCallback(window, key_callback);
    glfwSetCursorPosCallback(window, cursor_position_callback);
    glfwSetMouseButtonCallback(window, mouse_button_callback);
    if (glewInit() != GLEW_OK) exit(EXIT_FAILURE);
    cout<<"GL_VERSION: "<<glGetString(GL_VERSION)<<endl;
    glfwSwapInterval(0);

    init(window);

    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
        display();
        glfwSwapBuffers(window);
    }

    glDeleteBuffers(numVBOs, vbo);
    glDeleteShader(renderingProgram);
    glDeleteVertexArrays(numVAOs, vao);

    glfwDestroyWindow(window);
    glfwTerminate();
    exit(EXIT_SUCCESS);
}

void init(GLFWwindow *window) {
    renderingProgram = Utils::createShaderProgram("vertShader.glsl", "fragShader.glsl");
    glUseProgram(renderingProgram);
    setupVertices();
}

void setupVertices(void) {
    vertices.clear();
    vertices_2.clear();
    buildCurvas();

    glGenVertexArrays(1, vao);
    glBindVertexArray(vao[0]);

    glGenBuffers(numVBOs, vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(double), &vertices[0], GL_STATIC_DRAW);

    vector<double> p_control_points(p_control.size()*2);
    for (int i=0; i<p_control.size(); i++){
        p_control_points[i*2] = p_control[i].x;
        p_control_points[i*2+1] = p_control[i].y;
    }
    glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
    glBufferData(GL_ARRAY_BUFFER, p_control_points.size()*sizeof(double), &p_control_points[0], GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
    glBufferData(GL_ARRAY_BUFFER, vertices_2.size()*sizeof(double), &vertices_2[0], GL_STATIC_DRAW);
}

void buildCurvas(){
    addPointsCurveG2(vertices, p_control[0], p_control[1], p_control[2], 20);
    addPointsCurveG2(vertices, p_control[3], p_control[4], p_control[5], 30);
    addPointsCurveG2(vertices_2, p_control[6], p_control[7], p_control[8], 15);
    addPointsCurveG2(vertices_2, p_control[8], p_control[9], p_control[10], 15);

}

void addPointsCurveG2(std::vector<double> &vertices, glm::vec2 p0, glm::vec2 p1, glm::vec2 p2, int n_points){
/* Curva cuadratica de Bezier
 * P = (P0)(1-t)^2 + (P1)2t(1-t) + (P2)t^2 , t: [0,1] */

    float inc = 1.0/(n_points-1);
    for(float t = 0.0f; t <= 1; t += inc){
        
        glm::vec2 p =   p0*(1.f-t)*(1.f-t) + p1*2.f*t*(1.f-t) + p2*t*t;

        vertices.push_back(p.x);
        vertices.push_back(p.y);
    }
}

void display() {
    glClearColor(1,0,0, 1);
    glClear(GL_COLOR_BUFFER_BIT);

    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glVertexAttribPointer(0, 2, GL_DOUBLE, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);
    glDrawArrays(GL_LINE_STRIP, 0, vertices.size()/2);
    
    glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
    glVertexAttribPointer(0, 2, GL_DOUBLE, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);
    glDrawArrays(GL_LINE_STRIP, 0, vertices_2.size()/2);

    if(edit_mode){
        glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
        glVertexAttribPointer(0, 2, GL_DOUBLE, GL_FALSE, 0, 0);
        glEnableVertexAttribArray(0);
        glPointSize(10.0);
        glDrawArrays(GL_POINTS, 0, p_control.size());
    }
}

/*------------------------------ [CONTROLES] ---------------------------*/

bool clickPuntoControl(glm::vec2 center, float x, float y){
    float radio = 0.05; // radio del rango para clickear el punto de control
    x =  x/(ANCHO/2.0) - 1.0;
    y = (y/(LARGO/2.0) - 1.0) * -1;
    float d = (center.x - x) * (center.x - x) + (center.y - y) * (center.y - y);
    d = sqrt(d);
    return d <= radio;
}

void mouse_button_callback(GLFWwindow* window, int button, int action, int mods){
    if(button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS){
        double posx, posy;
        glfwGetCursorPos(window, &posx, &posy);
        for (unsigned int i=0; i<p_control.size(); i++){
            if (clickPuntoControl(p_control[i], posx, posy)) vertClickeado = i;
        }
    }
    else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE){
        vertClickeado = -1;
    }
}

void cursor_position_callback(GLFWwindow* window, double xpos, double ypos){
    if (!edit_mode) return;
    if (vertClickeado != -1){

        xpos =  (xpos)/(ANCHO/2.0) - 1.0;
        ypos = ((ypos)/(LARGO/2.0) - 1.0) * -1;

        p_control[vertClickeado].x = xpos;
        p_control[vertClickeado].y = ypos;
        setupVertices();
    }
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods){
    if (key == GLFW_KEY_P && action == GLFW_PRESS){
        // imprime los puntos de control actuales
        cout<<"\tPuntos de control:"<<endl;
        for(int i=0; i<p_control.size(); i++){
            cout<<"/*"<<i<<"*/ ";
            cout<<"glm::vec2";
            cout<<"{"<<p_control[i].x<<","<<p_control[i].y<<"}";
            if (i != p_control.size()-1)
                cout<<","<<endl;
        }
        cout<<endl;
    }
    if (key == GLFW_KEY_E && action == GLFW_PRESS){
        // imprime los puntos de control actuales
        if(!edit_mode){
            LOG("EDIT MODE ON");
            edit_mode = true;
        } else {
            LOG("EDIT MODE OFF");
            edit_mode = false;
        }
    }
}
/*------------------------------------------------------------------*/

Utils.hpp

#ifndef UTILS_H
#define UTILS_H

// #define GLEW_STATIC
#include <GL/glew.h>

#include <string>
#include <fstream>

namespace Utils{
    std::string readShader(const char *filePath) {
        std::string content;
        std::ifstream fileStream(filePath, std::ios::in);
        std::string line = "";

        while(getline(fileStream, line)) {
            content.append(line + "\n");
        }

        fileStream.close();
        return content;
    }
    unsigned int createShaderProgram(const char *file_vs, const char *file_fs ) {
        std::string str_src_vs = readShader(file_vs);
        std::string str_src_fs = readShader(file_fs);

        const char *src_vs = str_src_vs.c_str();
        const char *src_fs = str_src_fs.c_str();

        unsigned int vs, fs; 
        vs = glCreateShader(GL_VERTEX_SHADER);
        fs = glCreateShader(GL_FRAGMENT_SHADER);

        glShaderSource(vs, 1, &(src_vs), NULL);
        glShaderSource(fs, 1, &(src_fs), NULL);

        glCompileShader(vs);
        glCompileShader(fs);

        unsigned int program = glCreateProgram();
        glAttachShader(program, vs);
        glAttachShader(program, fs);
        glLinkProgram(program);

        return program;
    }
}
#endif

fragShader.glsl

#version 430

out vec4 color;

void main(void) {
    color = vec4(0,0,0,1);
}

vertShader.glsl

#version 430

layout (location=0) in vec3 position; 

void main(void) {
    gl_Position = vec4(position, 1.0);
}

Deja un comentario