From 8d9b24b1b84107c90a77d94c86a810cc068fe073 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 19 Feb 2020 22:14:12 +0100 Subject: Fix rendering of texture with multiple frames --- src/RenderBackend/OpenGL/DeviceFrame.cpp | 39 --------- src/RenderBackend/OpenGL/DeviceMemory.cpp | 80 ++++++++---------- src/RenderBackend/OpenGL/ShaderFrame.cpp | 54 +++++++++++++ src/RenderBackend/OpenGL/ShaderProgram.cpp | 57 +------------ src/RenderBackend/OpenGL/Texture2D.cpp | 24 +++++- src/main.cpp | 126 ++++++++++++++++++----------- 6 files changed, 192 insertions(+), 188 deletions(-) delete mode 100644 src/RenderBackend/OpenGL/DeviceFrame.cpp create mode 100644 src/RenderBackend/OpenGL/ShaderFrame.cpp (limited to 'src') diff --git a/src/RenderBackend/OpenGL/DeviceFrame.cpp b/src/RenderBackend/OpenGL/DeviceFrame.cpp deleted file mode 100644 index 2132f83..0000000 --- a/src/RenderBackend/OpenGL/DeviceFrame.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "../../../include/RenderBackend/OpenGL/DeviceFrame.hpp" -#include "../../../include/RenderBackend/OpenGL/DeviceMemory.hpp" -#include "../../../include/RenderBackend/OpenGL/opengl.hpp" -#include "../../../include/RenderBackend/OpenGL/ShaderProgram.hpp" - -namespace amalgine -{ - DeviceFrame::DeviceFrame() - { - glGenVertexArrays(1, &vertexArrayObjectId); - } - - DeviceFrame::~DeviceFrame() - { - for(DeviceMemory *deviceMemory : buffers) - { - delete deviceMemory; - } - glDeleteVertexArrays(1, &vertexArrayObjectId); - } - - DeviceMemory* DeviceFrame::alloc() - { - glBindVertexArray(vertexArrayObjectId); - DeviceMemory *deviceMemory = new DeviceMemory(); - buffers.push_back(deviceMemory); - return deviceMemory; - } - - void DeviceFrame::draw(ShaderProgram *shader) { - shader->use(); - //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - for(DeviceMemory *deviceMemory : buffers) - { - deviceMemory->draw(); - } - //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } -} diff --git a/src/RenderBackend/OpenGL/DeviceMemory.cpp b/src/RenderBackend/OpenGL/DeviceMemory.cpp index a82cdaa..7447657 100644 --- a/src/RenderBackend/OpenGL/DeviceMemory.cpp +++ b/src/RenderBackend/OpenGL/DeviceMemory.cpp @@ -2,12 +2,9 @@ #include "../../../include/RenderBackend/OpenGL/opengl.hpp" #include -namespace amalgine -{ - u32 getOpenglStorageType(DeviceMemory::StorageType storageType) - { - switch(storageType) - { +namespace amalgine { + u32 getOpenglStorageType(DeviceMemory::StorageType storageType) { + switch(storageType) { case DeviceMemory::StorageType::STATIC: return GL_STATIC_DRAW; case DeviceMemory::StorageType::DYNAMIC: return GL_DYNAMIC_DRAW; case DeviceMemory::StorageType::STREAM: return GL_STREAM_DRAW; @@ -15,58 +12,47 @@ namespace amalgine } } - DeviceMemory::DeviceMemory() : primitiveType(0), numVertices(0), type(DeviceMemoryType::NONE) - { - glGenBuffers(1, &vertexBufferObjectId); + DeviceMemory::DeviceMemory(u32 vertex_array_object_id, i32 attrib_location) : + vertex_array_object_id(vertex_array_object_id), vertex_buffer_object_id(-1), attrib_location(attrib_location), + num_vertices(0), memory_type(DeviceMemoryType::NONE) { + glGenBuffers(1, &vertex_buffer_object_id); } - DeviceMemory::~DeviceMemory() - { - glDeleteBuffers(1, &vertexBufferObjectId); + DeviceMemory::~DeviceMemory() { + glDeleteBuffers(1, &vertex_buffer_object_id); } - void DeviceMemory::use() const - { - // TODO: Bind vao here? - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectId); + void DeviceMemory::use() { + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object_id); } - /* - void DeviceMemory::copy(const DataView &data, StorageType storageType, PrimitiveType primitiveType) - { - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectId); - glBufferData(GL_ARRAY_BUFFER, data.getByteSize(), data.data, getOpenglStorageType(storageType)); - this->primitiveType = getOpenglPrimitiveType(primitiveType); - numVertices = getPrimitiveTypePointsPerVertices(primitiveType); - } - */ - void DeviceMemory::copy(const DataView &texture_coords, StorageType storageType) { - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectId); + + void DeviceMemory::set(const DataView &texture_coords, StorageType storageType) { + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object_id); glBufferData(GL_ARRAY_BUFFER, texture_coords.getByteSize(), texture_coords.data, getOpenglStorageType(storageType)); - primitiveType = GL_TRIANGLES; - numVertices = texture_coords.size * 2; - type = DeviceMemoryType::VEC2; + num_vertices = texture_coords.size * 2; + memory_type = DeviceMemoryType::VEC2; + + glBindVertexArray(vertex_array_object_id); // Encapsulate DeviceMemory (vertex buffer object) inside the active vertex array object + glVertexAttribPointer(attrib_location, 2, GL_FLOAT, GL_FALSE, 0, 0); } - void DeviceMemory::copy(const DataView &triangles, StorageType storageType) - { - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectId); + void DeviceMemory::set(const DataView &triangles, StorageType storageType) { + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object_id); glBufferData(GL_ARRAY_BUFFER, triangles.getByteSize(), triangles.data, getOpenglStorageType(storageType)); - primitiveType = GL_TRIANGLES; - numVertices = triangles.size * 2; - type = DeviceMemoryType::VEC2; + num_vertices = triangles.size * 2; + memory_type = DeviceMemoryType::VEC2; + + glBindVertexArray(vertex_array_object_id); // Encapsulate DeviceMemory (vertex buffer object) inside the active vertex array object + glVertexAttribPointer(attrib_location, 2, GL_FLOAT, GL_FALSE, 0, 0); } - void DeviceMemory::copy(const DataView &triangles, StorageType storageType) - { - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectId); + void DeviceMemory::set(const DataView &triangles, StorageType storageType) { + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object_id); glBufferData(GL_ARRAY_BUFFER, triangles.getByteSize(), triangles.data, getOpenglStorageType(storageType)); - primitiveType = GL_TRIANGLES; - numVertices = triangles.size * 3; - type = DeviceMemoryType::VEC3; - } - - void DeviceMemory::draw() - { - glDrawArrays(primitiveType, 0, numVertices); + num_vertices = triangles.size * 3; + memory_type = DeviceMemoryType::VEC3; + + glBindVertexArray(vertex_array_object_id); // Encapsulate DeviceMemory (vertex buffer object) inside the active vertex array object + glVertexAttribPointer(attrib_location, 3, GL_FLOAT, GL_FALSE, 0, 0); } } diff --git a/src/RenderBackend/OpenGL/ShaderFrame.cpp b/src/RenderBackend/OpenGL/ShaderFrame.cpp new file mode 100644 index 0000000..3f7ff01 --- /dev/null +++ b/src/RenderBackend/OpenGL/ShaderFrame.cpp @@ -0,0 +1,54 @@ +#include "../../../include/RenderBackend/OpenGL/ShaderFrame.hpp" +#include "../../../include/RenderBackend/OpenGL/opengl.hpp" + +namespace amalgine { + ShaderFrame::ShaderFrame(u32 shader_program_id) : shader_program_id(shader_program_id), vertex_array_object_id(-1) { + glGenVertexArrays(1, &vertex_array_object_id); + } + + ShaderFrame::~ShaderFrame() { + glDeleteVertexArrays(1, &vertex_array_object_id); + } + + DeviceMemory* ShaderFrame::get_input_by_name(const char *name) { + auto it = shader_inputs.find(name); + if(it != shader_inputs.end()) + return it->second.get(); + + GLint attrib_location = glGetAttribLocation(shader_program_id, name); + if(attrib_location == -1) { + fprintf(stderr, "No such attribute in shader: %s\n", name); + return nullptr; + } + + glBindVertexArray(vertex_array_object_id); // Encapsulate DeviceMemory (vertex buffer object) inside the active vertex array object + DeviceMemory *device_memory_ptr = new DeviceMemory(vertex_array_object_id, attrib_location); + std::unique_ptr device_memory(device_memory_ptr); + device_memory->use(); + glEnableVertexAttribArray(attrib_location); + + shader_inputs[name] = std::move(device_memory); + return device_memory_ptr; + } + + Result ShaderFrame::get_uniform_by_name(const char *name) { + GLint uniform_id = glGetUniformLocation(shader_program_id, name); + if(uniform_id == -1) + return Result::Err(std::string("Uniform with name ") + name + " was not found"); + + Uniform uniform(uniform_id, shader_program_id); + return Result::Ok(std::move(uniform)); + } + + void ShaderFrame::draw() { + glUseProgram(shader_program_id); + glBindVertexArray(vertex_array_object_id); // Set the active shader to use the data encapsulated by the vertex array object + // TODO: Cache this num_vertices count (and reset it when device memory has changed) + int num_vertices = 0; + for(const auto &it : shader_inputs) { + num_vertices = std::max(num_vertices, it.second->get_num_vertices()); + } + // TODO: Allow specifying mode different than GL_TRIANGLES + glDrawArrays(GL_TRIANGLES, 0, num_vertices); + } +} diff --git a/src/RenderBackend/OpenGL/ShaderProgram.cpp b/src/RenderBackend/OpenGL/ShaderProgram.cpp index 7990a82..ba0e6dd 100644 --- a/src/RenderBackend/OpenGL/ShaderProgram.cpp +++ b/src/RenderBackend/OpenGL/ShaderProgram.cpp @@ -28,26 +28,6 @@ namespace amalgine { delete []attachedShaders; } - #if 0 - bool ShaderProgram::setPixelShader(CompiledPixelShader *pixelShader) - { - if(!pixelShader) return false; - - // TODO: Do not allow adding shader if the program has already been built - glAttachShader(shaderProgramId, pixelShader->getShaderId()); - - const auto &pixelAttributes = pixelShader->getPixelAttributes(); - for(const auto &pixelAttribute : pixelAttributes) - { - const string &attributeName = pixelAttribute.first; - i32 attributeLocation = pixelAttribute.second; - glBindFragDataLocation(shaderProgramId, attributeLocation, attributeName.c_str()); - } - - return true; - } - #endif - // static Result> ShaderProgram::build(const std::vector &shaders) { u32 shader_program_id = glCreateProgram(); @@ -64,40 +44,7 @@ namespace amalgine { return Result>::Ok(std::move(shader_program)); } - Result ShaderProgram::get_uniform_by_name(const char *name) { - GLint uniform_id = glGetUniformLocation(program_id, name); - if(uniform_id == -1) - return Result::Err(std::string("Uniform with name ") + name + " was not found"); - - Uniform uniform(uniform_id, program_id); - return Result::Ok(std::move(uniform)); - } - - int ShaderProgram::set_input_data(const char *name, const DeviceMemory &data) { - GLint attrib_location = glGetAttribLocation(program_id, name); - if(attrib_location == -1) { - fprintf(stderr, "No such attribute in shader: %s\n", name); - return -1; - } - - data.use(); - glEnableVertexAttribArray(attrib_location); - switch(data.get_type()) { - case DeviceMemoryType::NONE: - return -1; - case DeviceMemoryType::VEC2: { - glVertexAttribPointer(attrib_location, 2, GL_FLOAT, GL_FALSE, 0, 0); - break; - } - case DeviceMemoryType::VEC3: { - glVertexAttribPointer(attrib_location, 3, GL_FLOAT, GL_FALSE, 0, 0); - break; - } - } - return 0; - } - - void ShaderProgram::use() { - glUseProgram(program_id); + ShaderFrame ShaderProgram::create_frame() { + return { program_id }; } } diff --git a/src/RenderBackend/OpenGL/Texture2D.cpp b/src/RenderBackend/OpenGL/Texture2D.cpp index dcb9cef..f4326a8 100644 --- a/src/RenderBackend/OpenGL/Texture2D.cpp +++ b/src/RenderBackend/OpenGL/Texture2D.cpp @@ -39,6 +39,10 @@ namespace amalgine { static TextureIdAllocator *texture_id_allocator = nullptr; + Texture2D::Texture2D() : texture_id(-1), texture_ref(-1) { + + } + Texture2D::Texture2D(Image *image) { assert(image); @@ -46,6 +50,8 @@ namespace amalgine { texture_id_allocator = new TextureIdAllocator(); texture_id = texture_id_allocator->get_free_texture_id(); + printf("texture id: %d\n", texture_id); + texture_ref = -1; glGenTextures(1, &texture_ref); glActiveTexture(GL_TEXTURE0 + texture_id); glBindTexture(GL_TEXTURE_2D, texture_ref); @@ -60,7 +66,21 @@ namespace amalgine { Texture2D::~Texture2D() { - texture_id_allocator->free_texture_id(texture_id); - glDeleteTextures(1, &texture_ref); + if(texture_ref != -1) { + texture_id_allocator->free_texture_id(texture_id); + glDeleteTextures(1, &texture_ref); + } + } + + Texture2D::Texture2D(Texture2D &&other) { + this->operator=(std::move(other)); + } + + Texture2D& Texture2D::operator=(Texture2D &&other) { + texture_id = other.texture_id; + texture_ref = other.texture_ref; + other.texture_id = -1; + other.texture_ref = -1; + return *this; } } diff --git a/src/main.cpp b/src/main.cpp index 22bfe1c..a2ea0b8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,6 @@ #include "../include/RenderBackend/OpenGL/Shader.hpp" #include "../include/RenderBackend/OpenGL/ShaderProgram.hpp" #include "../include/RenderBackend/OpenGL/DeviceMemory.hpp" -#include "../include/RenderBackend/OpenGL/DeviceFrame.hpp" #include "../include/RenderBackend/OpenGL/Texture2D.hpp" #include "../include/Image.hpp" #include "../include/Triangle.hpp" @@ -34,24 +33,27 @@ static std::vector generate_sand() { const int columns = 50; std::vector vertices(rows * columns * 2); int i = 0; - float div = 0.3f; + float div = 1.0f / (float)rows; for(int y = 0; y < rows; ++y) { for(int x = 0; x < columns; ++x) { vertices[i++] = { - Vertex3D{x * div + 0.0f, y * div + 0.0f, 0.0f}, - Vertex3D{x * div + 1.0f * div, y * div + 0.0f, 0.0f}, - Vertex3D{x * div + 0.0f, y * div + 1.0f * div, 0.0f} + Vertex3D{x * div + 0.0f * div, y * div + 0.0f * div, 0.0f}, + Vertex3D{x * div + 1.0f * div, y * div + 0.0f * div, 0.0f}, + Vertex3D{x * div + 1.0f * div, y * div + 1.0f * div, 0.0f} }; vertices[i++] = { - Vertex3D{x * div + 1.0f * div, y * div + 0.0f, 0.0f}, Vertex3D{x * div + 1.0f * div, y * div + 1.0f * div, 0.0f}, - Vertex3D{x * div + 0.0f, y * div + 1.0f * div, 0.0f} + Vertex3D{x * div + 0.0f * div, y * div + 1.0f * div, 0.0f}, + Vertex3D{x * div + 0.0f * div, y * div + 0.0f * div, 0.0f} }; } } return vertices; } +static void create_sand(DeviceMemory *triangles, DeviceMemory *texcoords, Texture2D *texture); +static DeviceMemory* load_model(const char *filepath); + int main() { initGlfw(); @@ -60,52 +62,52 @@ int main() int window_width = 1; int window_height = 1; glfwGetWindowSize(window, &window_width, &window_height); - - DeviceFrame frame; - - std::vector cpu_sand = generate_sand(); - DeviceMemory *gpuSand = frame.alloc(); - gpuSand->copy({cpu_sand.data(), cpu_sand.size()}, DeviceMemory::StorageType::STATIC); + + glm::mat4 proj = glm::perspective(glm::radians(75.0f), (float)window_width / (float)window_height, 0.2f, 1000.0f); std::unique_ptr sand_vertex_shader = load_shader_from_file("shaders/sand_vertex.vert", Shader::Type::VERTEX); std::unique_ptr sand_pixel_shader = load_shader_from_file("shaders/sand_fragment.frag", Shader::Type::PIXEL); std::unique_ptr sand_shader_program = build_shader_program_from_shaders({ sand_vertex_shader.get(), sand_pixel_shader.get() }); + ShaderFrame sand_frame = sand_shader_program->create_frame(); + + DeviceMemory *sand_triangles = sand_frame.get_input_by_name("position"); + DeviceMemory *sand_texcoords = sand_frame.get_input_by_name("texcoord_vert"); + Texture2D sand_texture; + create_sand(sand_triangles, sand_texcoords, &sand_texture); + + Result sand_proj_uniform = sand_frame.get_uniform_by_name("proj"); + Result sand_view_uniform = sand_frame.get_uniform_by_name("view"); + Result sand_model_uniform = sand_frame.get_uniform_by_name("model"); + //Result sand_time = sand_frame.get_uniform_by_name("time"); + Result sand_heightmap_uniform = sand_frame.get_uniform_by_name("tex"); + + sand_proj_uniform->set(proj); + sand_heightmap_uniform->set(sand_texture); - std::vector triangles; - std::vector texture_coords; - Image *image; - ObjModelLoader::load_from_file("/home/dec05eba/Downloads/ELI4OS.obj", triangles, texture_coords, &image); - DeviceMemory *gpuModel = frame.alloc(); - gpuModel->copy({triangles.data(), triangles.size()}, DeviceMemory::StorageType::STATIC); - Texture2D model_texture(image); - DeviceMemory *model_gpu_texture = frame.alloc(); - model_gpu_texture->copy({texture_coords.data(), texture_coords.size()}, DeviceMemory::StorageType::STATIC); std::unique_ptr vertex_shader = load_shader_from_file("shaders/vertex.vert", Shader::Type::VERTEX); std::unique_ptr pixel_shader = load_shader_from_file("shaders/fragment.frag", Shader::Type::PIXEL); std::unique_ptr shader_program = build_shader_program_from_shaders({ vertex_shader.get(), pixel_shader.get() }); + ShaderFrame model_frame = shader_program->create_frame(); - glm::mat4 proj = glm::perspective(glm::radians(75.0f), (float)window_width / (float)window_height, 0.2f, 1000.0f); - vec3f triangle_color = { 1.0f, 0.0f, 0.0f }; - - Result sand_proj_uniform = sand_shader_program->get_uniform_by_name("proj"); - Result sand_view_uniform = sand_shader_program->get_uniform_by_name("view"); - Result sand_model_uniform = sand_shader_program->get_uniform_by_name("model"); - Result sand_time = sand_shader_program->get_uniform_by_name("time"); - Result sand_triangle_color_uniform = sand_shader_program->get_uniform_by_name("triangle_color"); + std::vector triangles; + std::vector texture_coords; + Image *image; + ObjModelLoader::load_from_file("/home/dec05eba/Downloads/ELI4OS.obj", triangles, texture_coords, &image); + DeviceMemory *gpuModel = model_frame.get_input_by_name("position"); + gpuModel->set({triangles.data(), triangles.size()}, DeviceMemory::StorageType::STATIC); - Result proj_uniform = shader_program->get_uniform_by_name("proj"); - Result view_uniform = shader_program->get_uniform_by_name("view"); - Result model_uniform = shader_program->get_uniform_by_name("model"); - Result tex_uniform = shader_program->get_uniform_by_name("tex"); + Texture2D model_texture(image); + DeviceMemory *model_gpu_texcoords = model_frame.get_input_by_name("texcoord_vert"); + model_gpu_texcoords->set({texture_coords.data(), texture_coords.size()}, DeviceMemory::StorageType::STATIC); - sand_proj_uniform->set(proj); - sand_triangle_color_uniform->set(triangle_color); + Result proj_uniform = model_frame.get_uniform_by_name("proj"); + Result view_uniform = model_frame.get_uniform_by_name("view"); + Result model_uniform = model_frame.get_uniform_by_name("model"); + Result tex_uniform = model_frame.get_uniform_by_name("tex"); proj_uniform->set(proj); - - shader_program->set_input_data("texcoord_vert", *model_gpu_texture); tex_uniform->set(model_texture); Userdata userdata; @@ -121,6 +123,9 @@ int main() }); glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + float time = 0.0f; while(!glfwWindowShouldClose(window)) { glfwPollEvents(); @@ -158,11 +163,19 @@ int main() 0.0f, glm::vec3(0.0f, 0.0f, 1.0f) ); - sand_model_uniform->set(model); model_uniform->set(model); + glm::mat4 sand_model = glm::mat4(1.0f); + sand_model = glm::rotate( + sand_model, + 0.0f, + glm::vec3(0.0f, 0.0f, 1.0f) + ); + sand_model = glm::scale(sand_model, glm::vec3(50.0f, 50.0f, 50.0f)); + sand_model_uniform->set(sand_model); + //printf("now: %f\n", time); - sand_time->set(time); + //sand_time->set(time); // Set color for clearing glClearColor(0.0f, 0.0f, 0.0f, 1.0f); @@ -170,11 +183,8 @@ int main() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - shader_program->set_input_data("position", *gpuModel); - frame.draw(shader_program.get()); - - sand_shader_program->set_input_data("position", *gpuSand); - frame.draw(sand_shader_program.get()); + model_frame.draw(); + sand_frame.draw(); //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glfwSwapBuffers(window); @@ -185,6 +195,32 @@ int main() return 0; } +void create_sand(DeviceMemory *triangles, DeviceMemory *texcoords, Texture2D *texture) { + std::vector cpu_sand = generate_sand(); + triangles->set({cpu_sand.data(), cpu_sand.size()}, DeviceMemory::StorageType::STATIC); + + Result height_map_image = Image::loadFromFile("heightmap.jpg"); + if(!height_map_image) { + fprintf(stderr, "Error: failed to load image: heightmap.jpg\n"); + exit(1); + } + + std::vector height_map_texcoord; + for(const Triangle3D &triangle : cpu_sand) { + height_map_texcoord.push_back(vec2f{ triangle.p1.x, triangle.p1.y }); + height_map_texcoord.push_back(vec2f{ triangle.p2.x, triangle.p2.y }); + height_map_texcoord.push_back(vec2f{ triangle.p3.x, triangle.p3.y }); + } + + Texture2D height_map_texture(height_map_image.unwrap()); + *texture = std::move(height_map_texture); + texcoords->set({height_map_texcoord.data(), height_map_texcoord.size()}, DeviceMemory::StorageType::STATIC); +} + +DeviceMemory* load_model(const char *filepath) { + return nullptr; +} + void glfwErrorHandler(int errorCode, const char *errorDescription) { printf("GLFW error code: %d, description: %s\n", errorCode, errorDescription); -- cgit v1.2.3