diff --git a/src/client/client_imgui.cpp b/src/client/client_imgui.cpp index 6d7d481..9851409 100644 --- a/src/client/client_imgui.cpp +++ b/src/client/client_imgui.cpp @@ -15,6 +15,8 @@ #include "common/shaderloader.hpp" +#include "renderable.hpp" + // Globals static Logger logger; static MessageBus messager(&logger); @@ -79,22 +81,15 @@ int main(int argc, char** argv) int height = 0, width = 0; ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); float fov = 45.0; - // Triangle example - // @see http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/ - GLuint VertexArrayID; - glGenVertexArrays(1, &VertexArrayID); - glBindVertexArray(VertexArrayID); - GLuint vertexbuffer; - // An array of 3 vectors which represents 3 vertices - static const GLfloat g_vertex_buffer_data[] = { - -1.0f, -1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - }; - glGenBuffers(1, &vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), - g_vertex_buffer_data, GL_STATIC_DRAW); + + // Required before OpenGL Calls. + GLuint vertex_array; + glGenVertexArrays(1, &vertex_array); + glBindVertexArray(vertex_array); + + Renderable::Object triangle = Renderable::Object(Renderable::triangle_data, sizeof(Renderable::triangle_data)); + Renderable::Object cube = Renderable::Object(Renderable::cube_data, sizeof(Renderable::cube_data), Renderable::cube_color, sizeof(Renderable::cube_color)); + cube.set_position(glm::vec3(0.f, 0.f, -5.f)); static Console console(&messager); bool show_console = false; @@ -107,6 +102,9 @@ int main(int argc, char** argv) static struct ShaderRegistry shader_registry; loadShadersFromFile(shader_list, &shader_registry); static std::vector shader_program_registry; + // @BUG This is a temporary hack. When shader_program_registry is grown, the existing + // entries lose data. + shader_program_registry.reserve(10); loadShaderProgramsFromFile("shaders/shader_programs.txt", &shader_registry, &shader_program_registry); messager.registerCallback(&debug_messagebus_callback); int window_height, window_width; @@ -134,6 +132,7 @@ int main(int argc, char** argv) // Camera movement? double cv_x = 0.f; double cv_y = 0.f; + // This is "kind of" a pan, since it translates the point being looked at by the same value. if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) { cv_x += camera_velocity * dt; } @@ -151,6 +150,7 @@ int main(int argc, char** argv) auto ncla = glm::translate(glm::mat4(1.0f), camera_translation) * glm::vec4(camera_looking_at[0], camera_looking_at[1], camera_looking_at[2], 1.0f); camera_position = glm::vec3(ncp[0], ncp[1], ncp[2]); camera_looking_at = glm::vec3(ncla[0], ncla[1], ncla[2]); + view = glm::lookAt(camera_position, camera_looking_at, glm::vec3(0,1,0)); // Process messages @@ -170,27 +170,15 @@ int main(int argc, char** argv) glfwGetWindowSize(window, &window_width, &window_height); projection = glm::perspective(glm::radians(fov), (float) window_width / (float) window_height, 0.1f, 100.0f); - mvp_matrix = projection * view * model_default; + glm::mat4 vp = projection * view; // @see https://blog.conan.io/2019/06/26/An-introduction-to-the-Dear-ImGui-library.html // 1st attribute buffer : vertices GLuint p = find_shader_program_by_name("default", &shader_program_registry); - glUseProgram(p); - GLuint matrix_id = glGetUniformLocation(p, "MVP"); - glUniformMatrix4fv(matrix_id, 1, GL_FALSE, &mvp_matrix[0][0]); - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); - glVertexAttribPointer( - 0, // attribute 0. No particular reason for 0, but must match the layout in the shader. - 3, // size - GL_FLOAT, // type - GL_FALSE, // normalized? - 0, // stride - (void*)0 // array buffer offset - ); - // Draw the triangle ! - glDrawArrays(GL_TRIANGLES, 0, 3); // Starting from vertex 0; 3 vertices total -> 1 triangle - glDisableVertexAttribArray(0); - glUseProgram(0); + triangle.render(vp, p); + + // Draw a cube? + p = find_shader_program_by_name("color", &shader_program_registry); + cube.render(vp, p); // Start the Dear ImGui frame ImGui_ImplOpenGL3_NewFrame(); diff --git a/src/client/renderable.hpp b/src/client/renderable.hpp new file mode 100644 index 0000000..a70d630 --- /dev/null +++ b/src/client/renderable.hpp @@ -0,0 +1,180 @@ +#ifndef _RENDERABLE_H_ +#define _RENDERABLE_H_ + +#include +#include +#include + +namespace Renderable { + class Object { + public: + Object(const GLfloat * vertex_data, int vd_size, const GLfloat * color_data = 0, int cd_size = 0) { + this->vertex_buffer_data = (GLfloat *) vertex_data; + this->vertex_buffer_data_size = vd_size; + this->colour_buffer_data = (GLfloat *) color_data; + this->colour_buffer_data_size = cd_size; + this->init(); + } + void init() { + if (this->vertex_buffer != 0) { + // @TODO: Delete OpenGL buffer + } + if (this->vertex_buffer_data != 0) { + glGenBuffers(1, &this->vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, this->vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, this->vertex_buffer_data_size, + this->vertex_buffer_data, GL_STATIC_DRAW); + printf("Vertex_buffer: %d (%d, %d)\n", this->vertex_buffer, this->vertex_buffer_data_size, + this->vertex_buffer_data_size / sizeof(GLfloat) / 3); + } + if (this->colour_buffer != 0) { + // @TODO: Delete OpenGL buffer + } + if (this->colour_buffer_data != 0) { + glGenBuffers(1, &this->colour_buffer); + glBindBuffer(GL_ARRAY_BUFFER, this->colour_buffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(this->colour_buffer_data), + this->colour_buffer_data, GL_STATIC_DRAW); + } + } + void render(glm::mat4 vp, GLuint shader_program = 0) { + if (this->vertex_buffer == 0) { + return; + } + glUseProgram(shader_program); + glm::mat4 mvp = vp * this->get_model_matrix(); + GLuint matrix_id = glGetUniformLocation(shader_program, "MVP"); + glUniformMatrix4fv(matrix_id, 1, GL_FALSE, &mvp[0][0]); + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, this->vertex_buffer); + glVertexAttribPointer( + 0, // attribute 0. No particular reason for 0, but must match the layout in the shader. + 3, // size + GL_FLOAT, // type + GL_FALSE, // normalized? + 0, // stride + (void*)0 // array buffer offset + ); + glDrawArrays(GL_TRIANGLES, 0, this->vertex_buffer_data_size / sizeof(GLfloat) / 3); // Starting from vertex 0; 3 vertices total -> 1 triangle + if (this->colour_buffer == 0) { + glDisableVertexAttribArray(0); + glUseProgram(0); + return; + } + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, this->colour_buffer); + glVertexAttribPointer( + 1, // attribute. No particular reason for 1, but must match the layout in the shader. + 3, // size + GL_FLOAT, // type + GL_FALSE, // normalized? + 0, // stride + (void*)0 // array buffer offset + ); + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glUseProgram(0); + } + void set_position(glm::vec3 position) { + this->translation = glm::translate(glm::mat4(1.f), position); + } + private: + glm::mat4 get_model_matrix() { + return translation * rotation * scale; + } + GLuint vertex_buffer = 0; + GLuint colour_buffer = 0; + GLfloat *colour_buffer_data = 0; + int colour_buffer_data_size = 0; + GLfloat *vertex_buffer_data = 0; + int vertex_buffer_data_size = 0; + glm::mat4 translation = glm::mat4(1.f); + glm::mat4 scale = glm::mat4(1.f); + glm::mat4 rotation = glm::mat4(1.f); + }; + + static const GLfloat cube_data[] = { + -1.0f,-1.0f,-1.0f, // triangle 1 : begin + -1.0f,-1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, // triangle 1 : end + 1.0f, 1.0f,-1.0f, // triangle 2 : begin + -1.0f,-1.0f,-1.0f, + -1.0f, 1.0f,-1.0f, // triangle 2 : end + 1.0f,-1.0f, 1.0f, + -1.0f,-1.0f,-1.0f, + 1.0f,-1.0f,-1.0f, + 1.0f, 1.0f,-1.0f, + 1.0f,-1.0f,-1.0f, + -1.0f,-1.0f,-1.0f, + -1.0f,-1.0f,-1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f, 1.0f,-1.0f, + 1.0f,-1.0f, 1.0f, + -1.0f,-1.0f, 1.0f, + -1.0f,-1.0f,-1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f,-1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f,-1.0f,-1.0f, + 1.0f, 1.0f,-1.0f, + 1.0f,-1.0f,-1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f,-1.0f, + -1.0f, 1.0f,-1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f,-1.0f, + -1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + 1.0f,-1.0f, 1.0f + }; + static const GLfloat cube_color[] = { + -1.0f,-1.0f,-1.0f, // triangle 1 : begin + -1.0f,-1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, // triangle 1 : end + 1.0f, 1.0f,-1.0f, // triangle 2 : begin + -1.0f,-1.0f,-1.0f, + -1.0f, 1.0f,-1.0f, // triangle 2 : end + 1.0f,-1.0f, 1.0f, + -1.0f,-1.0f,-1.0f, + 1.0f,-1.0f,-1.0f, + 1.0f, 1.0f,-1.0f, + 1.0f,-1.0f,-1.0f, + -1.0f,-1.0f,-1.0f, + -1.0f,-1.0f,-1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f, 1.0f,-1.0f, + 1.0f,-1.0f, 1.0f, + -1.0f,-1.0f, 1.0f, + -1.0f,-1.0f,-1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f,-1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f,-1.0f,-1.0f, + 1.0f, 1.0f,-1.0f, + 1.0f,-1.0f,-1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f,-1.0f, + -1.0f, 1.0f,-1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f,-1.0f, + -1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + 1.0f,-1.0f, 1.0f + }; + + static const GLfloat triangle_data[] = { + -1.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + }; +} + +#endif // _RENDERABLE_H_ diff --git a/src/common/shaderloader.hpp b/src/common/shaderloader.hpp index 77b5cca..d5a5540 100644 --- a/src/common/shaderloader.hpp +++ b/src/common/shaderloader.hpp @@ -203,7 +203,7 @@ int loadShaderProgramsFromFile(const char* file_path, struct ShaderRegistry *sha // Skipping, line is a comment continue; } - char *line_copy = (char*) calloc(size, sizeof(char*)); + char *line_copy = (char*) calloc(size + 1, sizeof(char*)); strncpy(line_copy, line, size); printf("%s\n", line_copy); @@ -277,6 +277,7 @@ int loadShadersFromFile(const char* file_path, struct ShaderRegistry *registry) char *line; size_t size = 0; const char *delim = ","; + printf("Loading shaders listed in '%s'\n", file_path); fp = fopen(file_path, "r"); if (fp == NULL) { return -1; @@ -296,7 +297,7 @@ int loadShadersFromFile(const char* file_path, struct ShaderRegistry *registry) // Skipping, line is a comment continue; } - char *line_copy = (char*) malloc((size) * sizeof(char*)); + char *line_copy = (char*) malloc((size+1) * sizeof(char*)); strncpy(line_copy, line, size); // Format ,, name = strtok(line_copy, delim); diff --git a/src/shaders/colorVertexShader.glsl b/src/shaders/colorVertexShader.glsl new file mode 100644 index 0000000..b6d8104 --- /dev/null +++ b/src/shaders/colorVertexShader.glsl @@ -0,0 +1,11 @@ +#version 300 es +layout(location = 0) in vec3 vertexPosition_modelspace; +layout(location = 1) in vec3 vertexColor; +uniform mat4 MVP; +out mediump vec3 fragmentColor; +void main(){ + gl_Position.xyz = vertexPosition_modelspace; + gl_Position.w = 1.0; + gl_Position = MVP * gl_Position; + fragmentColor = vertexColor; +} diff --git a/src/shaders/fragmentColour.glsl b/src/shaders/fragmentColour.glsl new file mode 100644 index 0000000..56402c2 --- /dev/null +++ b/src/shaders/fragmentColour.glsl @@ -0,0 +1,7 @@ +#version 300 es +// the precision mediump is required in 3.0es +in mediump vec3 fragmentColor; +out mediump vec3 color; +void main(){ + color = fragmentColor; +} diff --git a/src/shaders/shader_list.txt b/src/shaders/shader_list.txt index 42e348a..9b062ed 100644 --- a/src/shaders/shader_list.txt +++ b/src/shaders/shader_list.txt @@ -7,4 +7,6 @@ # or compute. # defaultVertexShader,vertex,defaultVertexShader.glsl +colorVertexShader,vertex,colorVertexShader.glsl fragmentRed,fragment,fragmentRed.glsl +fragmentColour,fragment,fragmentColour.glsl diff --git a/src/shaders/shader_programs.txt b/src/shaders/shader_programs.txt index c2b097a..d017090 100644 --- a/src/shaders/shader_programs.txt +++ b/src/shaders/shader_programs.txt @@ -3,3 +3,4 @@ # Each line is a program. :,,... # default:defaultVertexShader,fragmentRed +color:colorVertexShader,fragmentColour