#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;
}
}
}
/*------------------------------------------------------------------*/