From 89a19a6ab69adaf65d2ecf0809a45e0f4eb81218 Mon Sep 17 00:00:00 2001 From: ao Date: Mon, 8 Oct 2018 10:12:21 +0200 Subject: [PATCH] Spline scene --- src/hello_spline/hellospline.cpp | 175 +++++++++++++++++++++++++++++++ src/hello_spline/hellospline.h | 71 +++++++++++++ src/mainwindow.cpp | 4 + src/mainwindow.h | 1 + src/mainwindow.ui | 8 +- src/myopenglwidget.cpp | 4 +- src/scene.cpp | 1 + 7 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 src/hello_spline/hellospline.cpp create mode 100644 src/hello_spline/hellospline.h diff --git a/src/hello_spline/hellospline.cpp b/src/hello_spline/hellospline.cpp new file mode 100644 index 0000000..5ec464c --- /dev/null +++ b/src/hello_spline/hellospline.cpp @@ -0,0 +1,175 @@ +#include "hellospline.h" +#include "bspline.h" +#include +//#define deg2rad(x) float(M_PI)*(x)/180.f + +// CTOR +SimpleSpline::SimpleSpline(int width, int height, MainWindow* w) : Scene(width, height, w), _activecamera(0), _camera(nullptr) +{ + // Initialize last shaders + _lastVertex = _w->vertexShader; + _lastFragment = _w->fragmentShader; + + // LOAD B-SPLINE + + std::cout << "Vertices count: " << _vertices.size() / 3 << std::endl; + std::cout << "Edges count: " << _indices.size() << std::endl; + std::cout << "Triangles count: " << _indices.size() / 3 << std::endl; + + // 1. Generate geometry buffers + glGenBuffers(1, &_vbo) ; + glGenBuffers(1, &_nbo) ; + glGenBuffers(1, &_ebo) ; + glGenVertexArrays(1, &_vao) ; + // 2. Bind Vertex Array Object + glBindVertexArray(_vao); + // 3. Copy our vertices array in a buffer for OpenGL to use + glBindBuffer(GL_ARRAY_BUFFER, _vbo); + glBufferData(GL_ARRAY_BUFFER, _vertices.size()*sizeof (GLfloat), _vertices.data(), GL_STATIC_DRAW); + // 4. Then set our vertex attributes pointers + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); + glEnableVertexAttribArray(0); + // 5. Copy our normals array in a buffer for OpenGL to use + glBindBuffer(GL_ARRAY_BUFFER, _nbo); + glBufferData(GL_ARRAY_BUFFER, _normals.size()*sizeof (GLfloat), _normals.data(), GL_STATIC_DRAW); + // 6. Copy our vertices array in a buffer for OpenGL to use + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); + glEnableVertexAttribArray(1); + // 7. Copy our index array in a element buffer for OpenGL to use + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices.size()*sizeof (GLfloat), _indices.data(), GL_STATIC_DRAW); + //6. Unbind the VAO + glBindVertexArray(0); + + // Camera Initialization + _cameraselector.push_back( []()->Camera*{return new EulerCamera(glm::vec3(0.f, 0.f, 1.f));} ); + _cameraselector.push_back( []()->Camera*{return new TrackballCamera(glm::vec3(0.f, 0.f, 1.f),glm::vec3(0.f, 1.f, 0.f),glm::vec3(0.f, 0.f, 0.f));} ); + + _camera.reset(_cameraselector[_activecamera]()); + + _camera->setviewport(glm::vec4(0.f, 0.f, _width, _height)); + _view = _camera->viewmatrix(); + + _projection = glm::perspective(_camera->zoom(), float(_width) / _height, 0.1f, 100.0f); + + generateProgram(); + glUseProgram(_program); +} + +SimpleSpline::~SimpleSpline() {} + +void SimpleSpline::resize(int width, int height){ + Scene::resize(width, height); + _camera->setviewport(glm::vec4(0.f, 0.f, _width, _height)); +} + +void SimpleSpline::draw() { + // Set OpenGL Render Mode + Scene::draw(); + + // Recompute program, but using pipeline should be better + if(_lastVertex != _w->vertexShader || _lastFragment != _w->fragmentShader) { + generateProgram(); + glUseProgram(_program); + } + + /* Uniforms + glUniform3f(glGetUniformLocation(_program, "center"), 0.0f, 0.0f, 0.0f); + glUniform1f(glGetUniformLocation(_program, "radius"), _radius); + glUniform1f(glGetUniformLocation(_program, "errorMax"), _errorMax); + */ + glUniform3f(glGetUniformLocation(_program, "cameraView"), _camera->_front.x, _camera->_front.y, _camera->_front.z); + + // Camera + _view = _camera->viewmatrix(); + + glUniformMatrix4fv( glGetUniformLocation(_program, "model"), 1, GL_FALSE, glm::value_ptr(_model)); + glUniformMatrix4fv( glGetUniformLocation(_program, "view"), 1, GL_FALSE, glm::value_ptr(_view)); + glUniformMatrix4fv( glGetUniformLocation(_program, "projection"), 1, GL_FALSE, glm::value_ptr(_projection)); + + // Draw the shape + glBindVertexArray(_vao); + glDrawElements(GL_TRIANGLES, _indices.size(), GL_UNSIGNED_INT, 0); + glBindVertexArray(0); +} + +void SimpleSpline::mouseclick(int button, float xpos, float ypos) { + _button = button; + _mousex = xpos; + _mousey = ypos; + _camera->processmouseclick(_button, xpos, ypos); +} + +void SimpleSpline::mousemove(float xpos, float ypos) { + _camera->processmousemovement(_button, xpos, ypos, true); +} + +void SimpleSpline::keyboardmove(int key, double time) { + _camera->processkeyboard(Camera_Movement(key), time); +} + +bool SimpleSpline::keyboard(unsigned char k) { + switch(k) { + case 'p': + _activecamera = (_activecamera+1)%2; + _camera.reset(_cameraselector[_activecamera]()); + _camera->setviewport(glm::vec4(0.f, 0.f, _width, _height)); + return true; + default: + return false; + } +} + +void SimpleSpline::generateProgram() { + // Change last shader variables + _lastVertex = _w->vertexShader; + _lastFragment = _w->fragmentShader; + + // Initialize shaders + GLint success; + GLchar infoLog[512]; // warning fixed size ... request for LOG_LENGTH!!! + GLuint vertexshader, fragmentshader; + + /* VERTEX SHADER */ + // 1. Generate the shader + vertexshader = glCreateShader(GL_VERTEX_SHADER); + // 2. set the source + auto pointerVertex = _w->vertexShaders[_w->vertexShader].c_str(); + glShaderSource(vertexshader, 1, &pointerVertex, NULL); + // 3. Compile + glCompileShader(vertexshader); + // 4. test for compile error + glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &success); + if(!success) { + glGetShaderInfoLog(vertexshader, 512, NULL, infoLog); + std::cerr << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; + } + + /* FRAGMENT SHADER */ + fragmentshader = glCreateShader(GL_FRAGMENT_SHADER); + auto pointerFragment = _w->fragmentShaders[_w->fragmentShader].c_str(); + glShaderSource(fragmentshader, 1, &pointerFragment, NULL); + glCompileShader(fragmentshader); + glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &success); + if(!success) { + glGetShaderInfoLog(fragmentshader, 512, NULL, infoLog); + std::cerr << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; + } + + /* Program Object */ + // 1. Generate the program + _program = glCreateProgram(); + // 2. Attach the shaders to the program + glAttachShader(_program, vertexshader); + glAttachShader(_program, fragmentshader); + // 3. Link the program + glLinkProgram(_program); + // 4. Test for link errors + glGetProgramiv(_program, GL_LINK_STATUS, &success); + if(!success) { + glGetProgramInfoLog(_program, 512, NULL, infoLog); + std::cerr << "ERROR::SHADER::LINK_FAILED\n" << infoLog << std::endl; + } + glDeleteShader(vertexshader); + glDeleteShader(fragmentshader); +} diff --git a/src/hello_spline/hellospline.h b/src/hello_spline/hellospline.h new file mode 100644 index 0000000..e0916c4 --- /dev/null +++ b/src/hello_spline/hellospline.h @@ -0,0 +1,71 @@ +#ifndef HELLOSPLINE_H +#define HELLOSPLINE_H + +#include "scene.h" +#include "hello_camera/camera.h" +#include "mainwindow.h" + +#include +#include + +/** Simple drawing demonstration + */ +class SimpleSpline : public Scene { +public: + explicit SimpleSpline(int width, int height, MainWindow* w); + ~SimpleSpline(); + + void resize(int width, int height) override; + void draw() override; + + void mouseclick(int button, float xpos, float ypos) override; + void mousemove(float xpos, float ypos) override; + void keyboardmove(int key, double time) override; + bool keyboard(unsigned char k) override; + +public slots: + void generateProgram(); + +private: + // A simple geometry + std::vector _vertices; + std::vector _normals; + std::vector _indices; + + // OpenGL object for geometry + GLuint _vao; + GLuint _vbo; + GLuint _nbo; + GLuint _ebo; + + // Shader program for rendering + QString _lastVertex; + QString _lastFragment; + GLuint _program; + + // for mouse management + int _button; // 0 --> left. 1 --> right. 2 --> middle. 3 --> other + float _mousex{0}; + float _mousey{0}; + + // Camera + using CameraSelector=std::function; + std::vector _cameraselector; + int _activecamera; + std::unique_ptr _camera; + + // Matrices + glm::mat4 _model; + glm::mat4 _view; + glm::mat4 _projection; + + /* Shape Methods + void drawCube(float size = 0.1f); + void drawUVSphere(int resolution = 5, float radius = 0.5f); + void drawIcoSphere(int resolution = 5, float radius = 0.f); + float _radius = 0.5f; + float _errorMax = 0.0f; + */ +}; + +#endif // SIMPLESPLINE_H diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index d2dbb7d..07d5312 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -52,6 +52,10 @@ void MainWindow::on_actionHello_spheres_triggered() { ui->openglWidget->activatedemo(3); } +void MainWindow::on_actionHello_spline_triggered() { + ui->openglWidget->activatedemo(4); +} + void MainWindow::on_actionToggle_Back_Face_Culling_triggered(bool checked) { culling = checked; diff --git a/src/mainwindow.h b/src/mainwindow.h index ae543f1..ae482ab 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -29,6 +29,7 @@ private slots: void on_actionHello_triangle_triggered(); void on_actionHello_camera_triggered(); void on_actionHello_spheres_triggered(); + void on_actionHello_spline_triggered(); void on_actionHello_clear_triggered(); void on_actionToggle_Back_Face_Culling_triggered(bool checked); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 4a7365a..02ea235 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -27,7 +27,7 @@ 0 0 800 - 25 + 24 @@ -44,6 +44,7 @@ + @@ -101,6 +102,11 @@ Toggle backface culling + + + Hello splines ... + + diff --git a/src/myopenglwidget.cpp b/src/myopenglwidget.cpp index 3720296..9da1ec4 100644 --- a/src/myopenglwidget.cpp +++ b/src/myopenglwidget.cpp @@ -10,6 +10,7 @@ #include "hello_triangles/hellotriangles.h" #include "hello_camera/hellocamera.h" #include "hello_spheres/hellosphere.h" +#include "hello_spline/hellospline.h" MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) :QOpenGLWidget(parent), QOpenGLFunctions_4_1_Core(), _scene(nullptr), _lastime(0) { @@ -18,6 +19,7 @@ MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) :QOpenGLWidget(parent), QOpenGLF _democonstructors.push_back( [](int width, int height, MainWindow* w)->Scene*{std::cout << "Hello triangles ..." << std::endl; return new SimpleTriangle(width, height, w);} ); _democonstructors.push_back( [](int width, int height, MainWindow* w)->Scene*{std::cout << "Hello camera ..." << std::endl; return new SimpleCamera(width, height, w);} ); _democonstructors.push_back( [](int width, int height, MainWindow* w)->Scene*{std::cout << "Hello sphere ..." << std::endl; return new SimpleSphere(width, height, w);} ); + _democonstructors.push_back( [](int width, int height, MainWindow* w)->Scene*{std::cout << "Hello spline ..." << std::endl; return new SimpleSpline(width, height, w);} ); } MyOpenGLWidget::~MyOpenGLWidget() { @@ -30,7 +32,7 @@ void MyOpenGLWidget::initializeGL() { exit(1); } // Initialize OpenGL and all OpenGL dependent stuff below - _scene.reset(_democonstructors[3](width(), height(), (MainWindow*) this->parent())); + _scene.reset(_democonstructors[4](width(), height(), (MainWindow*) this->parent())); } void MyOpenGLWidget::paintGL() { diff --git a/src/scene.cpp b/src/scene.cpp index b022792..540faca 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -5,6 +5,7 @@ Scene::Scene(int width, int height, MainWindow* w) : _width(width), _height(height), _w(w), _drawfill(true) { glEnable(GL_DEPTH_TEST); glViewport(0, 0, width, height); + glPointSize(5.0f); } Scene::~Scene() {