diff --git a/CMakeLists.txt b/CMakeLists.txt index 500cdae..82bb540 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,8 @@ else() target_link_libraries(simpleengine PUBLIC assimp) endif() +# Link resources +target_link_libraries(simpleengine PUBLIC cmrc::base) target_link_libraries(simpleengine PRIVATE simpleengine_resources) # Include some dependencies' include directories diff --git a/cmrc b/cmrc index a64bea5..e386a62 160000 --- a/cmrc +++ b/cmrc @@ -1 +1 @@ -Subproject commit a64bea50c05594c8e7cf1f08e441bb9507742e2e +Subproject commit e386a629eb537d384811e598a3c96b9ca928f65e diff --git a/examples/dev_testing/CMakeLists.txt b/examples/dev_testing/CMakeLists.txt index 01a45e9..6253a89 100644 --- a/examples/dev_testing/CMakeLists.txt +++ b/examples/dev_testing/CMakeLists.txt @@ -9,17 +9,17 @@ target_sources(dev_testing PRIVATE ${source_list}) target_include_directories(dev_testing PUBLIC include) # Embed shaders -file(GLOB_RECURSE shaders_list resources/shaders/*.glsl) -cmrc_add_resource_library( - resource_shaders - WHENCE resources/shaders - PREFIX shaders - ${shaders_list} -) +#file(GLOB_RECURSE shaders_list resources/shaders/*.glsl) +#cmrc_add_resource_library( +# resource_shaders +# WHENCE resources/shaders +# PREFIX shaders +# ${shaders_list} +#) # Link simpleengine target_link_libraries(dev_testing PUBLIC simpleengine) -target_link_libraries(dev_testing PRIVATE resource_shaders) +#target_link_libraries(dev_testing PRIVATE resource_shaders) # Set standard to C++20 set_target_properties(dev_testing PROPERTIES CXX_STANDARD 20 CXX_EXTENSIONS OFF) \ No newline at end of file diff --git a/examples/dev_testing/resources/shaders/fragment_core.glsl b/examples/dev_testing/resources/shaders/fragment_core.glsl deleted file mode 100644 index d5fe2e6..0000000 --- a/examples/dev_testing/resources/shaders/fragment_core.glsl +++ /dev/null @@ -1,46 +0,0 @@ -#version 440 - -in vec3 vs_position; -in mat4 vs_transform; -in vec2 vs_texcoord; -in vec3 vs_normal; -in vec3 vs_to_light; -in vec3 vs_to_camera; - -uniform bool texture_is_set; -uniform sampler2D vs_texture; -uniform vec3 light_color; -uniform float shine_damper; -uniform float reflectivity; - -out vec4 fs_color; - -void main() { - // Lighting - vec3 unit_normal = normalize(vs_normal); - vec3 unit_light_vector = normalize(vs_to_light); - - float dot_prod = dot(unit_normal, unit_light_vector); - float brightness = max(dot_prod, 0.f); - vec3 diffuse = brightness * light_color; - - // Specular lighting - // only do all this math is reflectivity is > 0 - vec3 final_specular = vec3(0.f); - if (reflectivity > 0) { - vec3 unit_vector_to_camera = normalize(vs_to_camera); - vec3 light_direction = -unit_vector_to_camera; - vec3 reflected_light_dir = reflect(light_direction, unit_normal); - float specular_factor = dot(reflected_light_dir, unit_vector_to_camera); - specular_factor = max(specular_factor, 0.f); - float damped_specular = pow(specular_factor, shine_damper); - final_specular = damped_specular * reflectivity * light_color; - } - - if (texture_is_set) { - //fs_color = vec4(0.5 * unit_normal + vec3(0.5), 1.f); // Visualize normals - fs_color = vec4(diffuse, 1.f) * texture(vs_texture, vs_texcoord) + vec4(final_specular, 1.f); - } else { - fs_color = vec4(diffuse, 1.f) + vec4(final_specular, 1.f); - } -} \ No newline at end of file diff --git a/examples/dev_testing/resources/shaders/vertex_core.glsl b/examples/dev_testing/resources/shaders/vertex_core.glsl deleted file mode 100644 index 42b9be3..0000000 --- a/examples/dev_testing/resources/shaders/vertex_core.glsl +++ /dev/null @@ -1,31 +0,0 @@ -#version 440 - -layout (location = 0) in vec3 vertex_position; -layout (location = 1) in vec2 vertex_texcoord; -layout (location = 2) in vec3 vertex_normal; - -out vec3 vs_position; -out vec2 vs_texcoord; -out mat4 vs_transform; -out vec3 vs_normal; -out vec3 vs_to_light; -out vec3 vs_to_camera; - -uniform mat4 transform_matrix; -uniform mat4 view_matrix; -uniform mat4 projection_matrix; -uniform vec3 light_position; - -void main() { - vec4 world_pos = (transform_matrix * vec4(vertex_position, 1.f)); - - vs_position = world_pos.xyz; - vs_transform = transform_matrix; - vs_texcoord = vertex_texcoord; - - gl_Position = projection_matrix * view_matrix * world_pos; - - vs_normal = (transform_matrix * vec4(vertex_normal, 0.f)).xyz; - vs_to_light = light_position - world_pos.xyz; - vs_to_camera = (inverse(view_matrix) * vec4(0.f, 0.f, 0.f, 1.f)).xyz - world_pos.xyz; -} \ No newline at end of file diff --git a/examples/dev_testing/src/main.cpp b/examples/dev_testing/src/main.cpp index 901cb11..ed161eb 100644 --- a/examples/dev_testing/src/main.cpp +++ b/examples/dev_testing/src/main.cpp @@ -31,9 +31,6 @@ #include #include -#include -CMRC_DECLARE(resource_shaders); - namespace se = simpleengine; class FPSCounterEvent : public se::Event { @@ -61,141 +58,43 @@ public: } }; -std::string read_resource_shader(const std::string &path) { - auto fs = cmrc::resource_shaders::get_filesystem(); - cmrc::file vertex_file = fs.open(path); - - return std::string(vertex_file.begin()); -} - int main(int argc, char *argv[]) { se::Game game(640, 480, "SimpleEngine 3D OpenGL - Developer Testing", GLFW_OPENGL_CORE_PROFILE, 4, 4, false); - /* se::gfx::Texture wall_texture("resources/wall.jpg"); - se::gfx::Texture crate_texture("resources/container.jpg", true, true); */ - // Load core shaders from SimpleEngine resources se::gfx::shaders::Core3dShader core_shader; - auto white_texture = se::gfx::Texture::white_texture(); - // white_texture.shine_damper = 10; - // white_texture.reflectivity = 1; - /* auto dragon = std::make_shared(game.get_window(), core_shader, white_texture, - "examples/dev_testing/resources/dragon.obj"); dragon->translate(0.f, -5.f, -15.f); game.add_event(dragon); */ - - /* auto cube = std::make_shared(game.get_window(), core_shader, white_texture, - "examples/dev_testing/resources/cube.obj"); cube->translate(0.f, -5.f, -15.f); game.add_event(cube); - - se::gfx::Texture grass("examples/dev_testing/resources/grass.png"); - auto terrain = std::make_shared(game.get_window(), core_shader, grass, 0, 0); - terrain->translate(0.f, -5.f, -15.f); - game.add_event(terrain); */ - - /* se::gfx::Texture stall_texture("examples/dev_testing/resources/stallTextureb.png"); - auto stall = std::make_shared(game.get_window(), core_shader, stall_texture, - "examples/dev_testing/resources/stall.obj"); stall->translate(10.f, -5.f, 0.f); stall->rotate_y(90.f); - game.add_event(stall); */ - - /* std::vector square_vertices = { - { se::Vectorf(0.5f, 0.5f, -1.f), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 0.f) }, // top right - { se::Vectorf(0.5f, -0.5f, -1.f), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, 0.f) }, // bottom right - { se::Vectorf(-0.5f, -0.5f, -1.f), glm::vec3(0.f, 0.f, 1.f), glm::vec2(0.5f, 1.0f) }, // bottom left - { se::Vectorf(-0.5f, 0.5f, -1.f), glm::vec3(.5f, 0.5f, 0.f), glm::vec2(0.5f, 1.0f) }, // top left - }; - - std::vector indicies = { - 0, 1, 3, - 1, 2, 3 - }; - - auto square = std::make_shared(game.get_window(), core_shader, square_vertices, indicies); - square->translate(1.25f, 0.f, -1.f); - //square->rotate_y(90.f); - //square->scale(.75f); - game.add_event(square); */ - - /* se::gfx::Texture white_texture("examples/dev_testing/resources/white_texture.png"); - auto cube = std::make_shared(game.get_window(), core_shader, white_texture, - "examples/dev_testing/resources/cube.obj"); cube->translate(-1.25f, 0.f, -1.f); game.add_event(cube); */ - - /* std::vector tri_vertices = { - { se::Vectorf(-0.5f, -0.5f, -1.f), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 0.f) }, // top right - { se::Vectorf(0.5f, -0.5f, -1.f), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, 0.f) }, // bottom right - { se::Vectorf(0.f, 0.5f, -1.f), glm::vec3(0.f, 0.f, 1.f), glm::vec2(0.5f, 1.0f) }, // bottom left - }; - - auto tri = std::make_shared(game.get_window(), core_shader, tri_vertices); - tri->translate(-1.25f, 0.f, -1.f); - tri->scale(.75f); - game.add_event(tri); */ - - std::vector cube_vertices = { - {se::Vectorf(-1.f, -1.f, -1.f), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 0.f)}, - {se::Vectorf(1.f, -1.f, -1.f), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, 0.f)}, - {se::Vectorf(1.f, 1.f, -1.f), glm::vec3(0.f, 0.f, 1.f), glm::vec2(2.f, 0.f)}, - {se::Vectorf(-1.f, 1.f, -1.f), glm::vec3(1.f, 1.f, 0.f), glm::vec2(3.f, 0.f)}, - {se::Vectorf(-1, -1, -1), glm::vec3(1.f, 1.f, 0.f), glm::vec2(4.f, 0.f)}, - - {se::Vectorf(-1, -1, 1), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 1.f)}, - {se::Vectorf(1, -1, 1), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, 1.f)}, - {se::Vectorf(1, 1, 1), glm::vec3(0.f, 0.f, 1.f), glm::vec2(2.f, 1.f)}, - {se::Vectorf(-1, 1, 1), glm::vec3(1.f, 1.f, 0.f), glm::vec2(3.f, 1.f)}, - {se::Vectorf(-1, -1, 1), glm::vec3(1.f, 1.f, 0.f), glm::vec2(4.f, 1.f)}, - - {se::Vectorf(-1, 1, -1), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, -1.f)}, - {se::Vectorf(1, 1, -1), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, -1.f)}, - - {se::Vectorf(-1, 1, 1), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 2.f)}, - {se::Vectorf(1, 1, 1), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, 2.f)}, - }; - - std::vector cube_indicies = {0, 1, 5, 5, 1, 6, 1, 2, 6, 6, 2, 7, 2, 3, 7, 7, 3, 8, - 3, 4, 8, 8, 4, 9, 10, 11, 0, 0, 11, 1, 5, 6, 12, 12, 6, 13}; + auto camera = std::make_shared(game.get_window(), core_shader, 70, glm::vec3(0, 0, 0)); + game.add_event(camera); // Create a renderer - auto renderer = std::make_shared(game.get_window(), core_shader); + auto renderer = std::make_shared(game.get_window(), core_shader, camera); + renderer->initialize(); game.add_renderable(renderer); // Create a Scene and give it the renderer auto scene = std::make_shared(renderer); game.add_event(scene); + se::ecs::Entity other_e = scene->create_entity(); + other_e.add_component("examples/dev_testing/resources/transparent_window.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE | simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_TRANSPARENT); + auto &other_transform = other_e.add_component(); + other_transform.translate(5.f, 0.5f, 1.f); + // Create an Entity in the Scene and add components to it. se::ecs::Entity entity = scene->create_entity(); - // entity.add_component("examples/dev_testing/resources/dragon.obj"); - // entity.add_component("examples/dev_testing/resources/stall.obj"); - // Backpack model required vertically flipped texture coords. - /* auto& model_comp = - entity.add_component("examples/dev_testing/resources/backpack/backpack.obj"); - model_comp.model.vertically_flip_tex_coords(); */ - - // entity.add_component("examples/dev_testing/resources/viper/viper.obj"); - // entity.add_component("examples/dev_testing/resources/halot/chief.fbx"); // entity.add_component("examples/dev_testing/resources/planks/planks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE); - entity.add_component("examples/dev_testing/resources/bricks/bricks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE); + //entity.add_component("examples/dev_testing/resources/bricks/bricks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE); + entity.add_component("examples/dev_testing/resources/transparent_window.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE | simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_TRANSPARENT); - // entity.add_component("examples/dev_testing/resources/scientist/scientist.fbx"); - // entity.add_component("examples/dev_testing/resources/paradigm/paradigm.fbx"); - // entity.add_component(); auto &transform_comp = entity.add_component(); transform_comp.translate(4.f, 0.f, 0.f); - // transform_comp.scale(0.05f); - // transform_comp.rotate_z(-90.f); - // transform_comp.rotate_y(-90.f); - // transform_comp.rotate_x(-90.f); - // Create the entity and add the model component to it. - /* auto entity = std::make_shared(); - entity->add_component(cube_vertices, cube_indicies, white_material, true); - entity->translate(3.5f, 0.f, 0.f); */ - - /* auto entity = std::make_shared(); - entity->add_component("examples/dev_testing/resources/dragon.obj"); - entity->translate(12.f, -4.f, 0.f); */ - - auto camera = std::make_shared(game.get_window(), core_shader, 70, glm::vec3(0, 0, 0)); - game.add_event(camera); + se::ecs::Entity brick_e = scene->create_entity(); + brick_e.add_component("examples/dev_testing/resources/bricks/bricks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE); + auto &brick_transf = brick_e.add_component(); + brick_transf.translate(6.f, -0.5f, 1.f); auto light = std::make_shared(core_shader, glm::vec3(0.f, 0.f, 0.f), glm::vec3(1.f, 1.f, 1.f)); game.add_event(light); diff --git a/include/simpleengine/gfx/material.h b/include/simpleengine/gfx/material.h index 50077d7..1acd12b 100644 --- a/include/simpleengine/gfx/material.h +++ b/include/simpleengine/gfx/material.h @@ -1,5 +1,6 @@ #pragma once +#include "rendering_type.h" #include "texture.h" #include @@ -10,6 +11,9 @@ namespace simpleengine::gfx { class Material { public: + RenderingType rendering_type; + + // TODO: Only one of each texture type. std::unordered_map>> textures; float ambient_strength; @@ -32,9 +36,9 @@ namespace simpleengine::gfx { */ float shine_factor; - Material(std::unordered_map>> textures, float shine = 1.f, float specular_scalar = 1.f, float ambient_scalar = 1.f, float diffuse_scalar = 1.f) : - textures(textures), ambient_strength(ambient_scalar), diffuse_strength(diffuse_scalar), specular_strength(specular_scalar), - shine_factor(shine) { + Material(std::unordered_map>> textures, RenderingType rendering_type, float shine = 1.f, + float specular_scalar = 1.f, float ambient_scalar = 1.f, float diffuse_scalar = 1.f) : textures(textures), rendering_type(rendering_type), + ambient_strength(ambient_scalar), diffuse_strength(diffuse_scalar), specular_strength(specular_scalar), shine_factor(shine) { } }; diff --git a/include/simpleengine/gfx/model.h b/include/simpleengine/gfx/model.h index 4aa8a31..4b3c899 100644 --- a/include/simpleengine/gfx/model.h +++ b/include/simpleengine/gfx/model.h @@ -16,6 +16,7 @@ namespace simpleengine::gfx { MdlProcFlag_FLIP_TEX_COORDS_VERTICALLY = 0b00000001, MdlProcFlag_FLIP_TEX_COORDS_HORIZONTALLY = 0b00000010, MdlProcFlag_CALCULATE_TANGENT_SPACE = 0b00000100, + MdlProcFlag_TRANSPARENT = 0b00001000, }; /** @@ -40,7 +41,7 @@ namespace simpleengine::gfx { gfx::Mesh process_mesh(std::unordered_map>>& processed_textures, aiMesh* mesh, const aiScene* scene); std::unordered_map> load_all_textures(aiMaterial* material); - std::vector> load_material_texture(std::unordered_map>>& processed_textures, aiMaterial* material, aiTextureType type, TextureFlags texture_color); + std::vector> load_material_texture(std::unordered_map>>& processed_textures, aiMaterial* material, aiTextureType type); protected: void post_process(); public: diff --git a/include/simpleengine/gfx/renderer.h b/include/simpleengine/gfx/renderer.h index 3cb5cce..684e7b7 100644 --- a/include/simpleengine/gfx/renderer.h +++ b/include/simpleengine/gfx/renderer.h @@ -1,36 +1,45 @@ #pragma once +#include "../camera.h" #include "shader.h" -#include "simpleengine/gfx/mesh.h" +#include "../renderable.h" +#include "rendering_type.h" #include #include #include +#include namespace simpleengine::gfx { + class Mesh; + class RenderingJob { public: - gfx::Mesh& rendering_mesh; + RenderingType rendering_type; + gfx::Mesh* rendering_mesh; glm::mat4 transform_mat; - RenderingJob(gfx::Mesh& mesh, glm::mat4 position) : rendering_mesh(mesh), transform_mat(position) { - - } + RenderingJob(RenderingType rendering_type, gfx::Mesh& mesh, glm::mat4 position); }; class Renderer : public simpleengine::Renderable { private: GLFWwindow* window; + protected: public: + std::queue transparent_render_queue; + std::queue other_render_queue; - std::queue rendering_queue; gfx::Shader shader; + std::shared_ptr camera; - Renderer(GLFWwindow* window, gfx::Shader shader); - Renderer(GLFWwindow* window, GLuint shader_program); + Renderer(GLFWwindow* window, gfx::Shader shader, std::shared_ptr camera); + Renderer(GLFWwindow* window, GLuint shader_program, std::shared_ptr camera); void enable_debug(); + virtual void sort_jobs(); + virtual void queue_job(RenderingType rendering_type, gfx::Mesh& mesh, glm::mat4 position); virtual void queue_job(RenderingJob job); virtual void create_job_buffers(RenderingJob& job); @@ -40,5 +49,16 @@ namespace simpleengine::gfx { virtual void update(const float& delta_time) override; virtual void render() override; + + /** + * @brief Renders a single job. + * + * @param job The job that will be rendered. + * @return true if the job was rendered successfully. + * @return false if there was an error when trying to render the job. + */ + virtual bool render_job(const RenderingJob& job); + virtual void render_job_queue(std::queue& queue); + virtual void render_job_queue(std::map>& queue); }; } \ No newline at end of file diff --git a/include/simpleengine/gfx/rendering_type.h b/include/simpleengine/gfx/rendering_type.h new file mode 100644 index 0000000..d6c66dc --- /dev/null +++ b/include/simpleengine/gfx/rendering_type.h @@ -0,0 +1,8 @@ +#pragma once + +namespace simpleengine::gfx { + enum RenderingType { + RendType_OPAQUE = 0, + RendType_TRANSPARENT = 1, + }; +} \ No newline at end of file diff --git a/include/simpleengine/gfx/texture.h b/include/simpleengine/gfx/texture.h index 32bffab..69c492e 100644 --- a/include/simpleengine/gfx/texture.h +++ b/include/simpleengine/gfx/texture.h @@ -23,39 +23,29 @@ namespace simpleengine::gfx { TexFlags_FLIP_VERTICALLY = 0b00000010, TexFlags_FLIP_HORIZONTALLY = 0b00000100, TexFlags_MIPMAP = 0b00001000, - TexFlags_NO_COLOR = 0b00010000, + /* TexFlags_NO_COLOR = 0b00010000, TexFlags_RGB = 0b00100000, - TexFlags_RGBA = 0b01000000, + TexFlags_RGBA = 0b01000000, */ }; class Texture { private: - unsigned char* img_data; // TODO Free this if its not used anymore + //unsigned char* img_data; // TODO Free this if its not used anymore unsigned int texture_id; unsigned int image_type_gl; Texture() = default; public: - /** - * @brief The default Texture flags not including the color. - * - * The default flags are `TexFlags_IMG_2D | TexFlags_MIPMAP` - * - * @see simpleengine::gfx::Texture::default_flags - * - */ - static constexpr int default_flags_no_color = TexFlags_IMG_2D | TexFlags_MIPMAP; - /** * @brief The default Texture flags including the color. * - * The default flags are `TexFlags_IMG_2D | TexFlags_MIPMAP | TexFlags_RGBA` + * The default flags are `TexFlags_IMG_2D | TexFlags_MIPMAP` * * @see simpleengine::gfx::Texture::default_flags_no_color * */ - static constexpr int default_flags = default_flags_no_color | TexFlags_RGBA; + static constexpr int default_flags = TexFlags_IMG_2D | TexFlags_MIPMAP; int height; int width; diff --git a/resources/shaders/core/3d/fragment_core.glsl b/resources/shaders/core/3d/fragment_core.glsl index 9801a5f..0751d1c 100644 --- a/resources/shaders/core/3d/fragment_core.glsl +++ b/resources/shaders/core/3d/fragment_core.glsl @@ -47,8 +47,13 @@ out vec4 fs_color; vec3 calculate_lighting(); void main() { - vec3 lighting = calculate_lighting(); + // Skip completely transparent fragments. + /* vec4 diffuse = texture(u_material.diffuse, vs_texcoord); + if (diffuse.a < 0.1) { + discard; + } */ + vec3 lighting = calculate_lighting(); fs_color = vec4(lighting, 1.f) * texture(u_material.diffuse, vs_texcoord); } diff --git a/src/game.cpp b/src/game.cpp index 9d603e9..dc7d5ac 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -48,9 +48,7 @@ simpleengine::Game::Game(int w, int h, const std::string& window_name, const int } void simpleengine::Game::enable_default_gl_options() const { - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); + //glFrontFace(GL_CW); update_enabled_vsync(); diff --git a/src/gfx/model.cpp b/src/gfx/model.cpp index 8fd542c..956ea1d 100644 --- a/src/gfx/model.cpp +++ b/src/gfx/model.cpp @@ -1,5 +1,6 @@ #include "gfx/model.h" #include "gfx/material.h" +#include "gfx/rendering_type.h" #include "gfx/texture.h" #include "vector.h" @@ -107,11 +108,17 @@ namespace simpleengine::gfx { } } + // Get the rendering type + RenderingType rendering_type = RenderingType::RendType_OPAQUE; + if (model_processing_flags & ModelProcessingFlags::MdlProcFlag_TRANSPARENT) { + rendering_type = RenderingType::RendType_TRANSPARENT; + } + // Create a default material and white texture. auto white_texture = gfx::Texture::white_texture(); std::unordered_map>> default_textures; default_textures.emplace(white_texture.type, std::vector>{ std::make_shared(white_texture) }); - gfx::Material mat(default_textures); + gfx::Material mat(default_textures, rendering_type); if (mesh->mMaterialIndex >= 0) { std::cout << "TODO: Process model materials!" << std::endl; @@ -121,17 +128,17 @@ namespace simpleengine::gfx { // Load Diffuse texture maps aiTextureType loading_type = aiTextureType_DIFFUSE; - std::vector> diffuse_maps = load_material_texture(processed_textures, material, loading_type, TextureFlags::TexFlags_RGBA); + std::vector> diffuse_maps = load_material_texture(processed_textures, material, loading_type); if (!diffuse_maps.empty()) textures.emplace(loading_type, diffuse_maps); // Load specular texture maps loading_type = aiTextureType_SPECULAR; - std::vector> spec_maps = load_material_texture(processed_textures, material, loading_type, TextureFlags::TexFlags_NO_COLOR); + std::vector> spec_maps = load_material_texture(processed_textures, material, loading_type); if (!spec_maps.empty()) textures.emplace(loading_type, spec_maps); // Load normals texture maps loading_type = aiTextureType_NORMALS; - std::vector> normal_maps = load_material_texture(processed_textures, material, loading_type, TextureFlags::TexFlags_RGB); + std::vector> normal_maps = load_material_texture(processed_textures, material, loading_type); if (!normal_maps.empty()) { textures.emplace(loading_type, normal_maps); @@ -143,7 +150,7 @@ namespace simpleengine::gfx { if (!textures.empty()) { // TODO: Find a way to let the user set the scalars. - mat = Material(textures); + mat = Material(textures, rendering_type); // Add `textures` into the `processed_textures` list. for (const auto& pair : textures) { @@ -189,7 +196,7 @@ namespace simpleengine::gfx { return {}; } - std::vector> Model::load_material_texture(std::unordered_map>>& processed_textures, aiMaterial* material, aiTextureType type, TextureFlags texture_color) { + std::vector> Model::load_material_texture(std::unordered_map>>& processed_textures, aiMaterial* material, aiTextureType type) { std::vector> textures; for (int i = 0; i < material->GetTextureCount(type); i++) { @@ -216,7 +223,7 @@ namespace simpleengine::gfx { ss << model_directory << "/" << texture_path; std::string full_path = ss.str(); - Texture texture(full_path.c_str(), type, Texture::default_flags_no_color | texture_color); + Texture texture(full_path.c_str(), type); texture.path = texture_path; textures.emplace_back(std::make_shared(texture)); diff --git a/src/gfx/renderer.cpp b/src/gfx/renderer.cpp index 336568a..19879e9 100644 --- a/src/gfx/renderer.cpp +++ b/src/gfx/renderer.cpp @@ -9,25 +9,27 @@ #include #include +#include +#include +// TODO: Check if initialized before trying to do stuff namespace simpleengine::gfx { - void create_mesh_buffers(simpleengine::gfx::Mesh& mesh); + void create_mesh_buffers(simpleengine::gfx::Mesh &mesh); - Renderer::Renderer(GLFWwindow* window, gfx::Shader shader): window(window), shader(shader) { - - } + RenderingJob::RenderingJob(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 position) + : rendering_type(rendering_type), rendering_mesh(&mesh), transform_mat(position) {} - Renderer::Renderer(GLFWwindow* window, GLuint shader_program): Renderer(window, - gfx::Shader(shader_program)) { + Renderer::Renderer(GLFWwindow *window, gfx::Shader shader, std::shared_ptr camera) + : window(window), shader(shader), camera(camera)/* , transparent_render_queue(CameraDistanceComparator(camera)) */ {} - } + Renderer::Renderer(GLFWwindow *window, GLuint shader_program, std::shared_ptr camera) + : Renderer(window, gfx::Shader(shader_program), camera) {} + + void debug_message_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, + const GLchar *message, const void *userParam) { - void debug_message_callback(GLenum source, GLenum type, GLuint id, GLenum severity, - GLsizei length, const GLchar* message, const void* userParam) { - fprintf(stderr, "%s type = 0x%x, severity = 0x%x, message = %s\n", - (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), - type, severity, message); + (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), type, severity, message); } void Renderer::enable_debug() { @@ -35,24 +37,49 @@ namespace simpleengine::gfx { glDebugMessageCallback(debug_message_callback, 0); } - void Renderer::queue_job(RenderingJob job) { - RenderingJob& emplace = rendering_queue.emplace(job); - create_job_buffers(emplace); + void Renderer::sort_jobs() { + // Sort transparents + + // std::sort() } - void Renderer::create_job_buffers(RenderingJob& job) { - Mesh& rendering_mesh = job.rendering_mesh; + void Renderer::queue_job(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 position) { + RenderingJob job(rendering_type, mesh, position); - if (!rendering_mesh.are_buffers_created) { - gfx::VBO& vbo = rendering_mesh.vbo; - gfx::VBO& ebo = rendering_mesh.ebo; - gfx::VAO& vao = rendering_mesh.vao; + this->queue_job(job); + } + + void Renderer::queue_job(RenderingJob job) { + create_job_buffers(job); + + switch (job.rendering_type) { + case RenderingType::RendType_TRANSPARENT: { + /* glm::vec3 pos = job.transform_mat[3]; + float distance = glm::distance(pos, camera->position); */ + this->transparent_render_queue.emplace(job); + break; + } + default: + this->other_render_queue.emplace(job); + break; + } + + sort_jobs(); + } + + void Renderer::create_job_buffers(RenderingJob &job) { + Mesh *rendering_mesh = job.rendering_mesh; + + if (!rendering_mesh->are_buffers_created) { + gfx::VBO &vbo = rendering_mesh->vbo; + gfx::VBO &ebo = rendering_mesh->ebo; + gfx::VAO &vao = rendering_mesh->vao; vao.bind(); - vbo.buffer(rendering_mesh.vertices.data(), 0, sizeof(LitVertex) * rendering_mesh.vertices.size()); + vbo.buffer(rendering_mesh->vertices.data(), 0, sizeof(LitVertex) * rendering_mesh->vertices.size()); - if (!rendering_mesh.indicies.empty()) { - ebo.buffer(rendering_mesh.indicies.data(), 0, rendering_mesh.indicies.size() * sizeof(GLuint)); + if (!rendering_mesh->indicies.empty()) { + ebo.buffer(rendering_mesh->indicies.data(), 0, rendering_mesh->indicies.size() * sizeof(GLuint)); } // Enable VAO attributes @@ -61,23 +88,29 @@ namespace simpleengine::gfx { vao.enable_attrib(vbo, 2, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, normal), false); vao.enable_attrib(vbo, 3, 2, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, tex_coord), false); - rendering_mesh.tangent_vbo.buffer(rendering_mesh.tangents.data(), 0, rendering_mesh.tangents.size() * sizeof(Vectorf)); - vao.enable_attrib(rendering_mesh.tangent_vbo, 4, 3, GL_FLOAT, sizeof(Vectorf), 0, false); + rendering_mesh->tangent_vbo.buffer(rendering_mesh->tangents.data(), 0, + rendering_mesh->tangents.size() * sizeof(Vectorf)); + vao.enable_attrib(rendering_mesh->tangent_vbo, 4, 3, GL_FLOAT, sizeof(Vectorf), 0, false); vbo.unbind(); vao.unbind(); - rendering_mesh.are_buffers_created = true; + rendering_mesh->are_buffers_created = true; std::cout << "Created render job buffers" << std::endl; } } - void Renderer::update(const float& delta_time) { - - } + void Renderer::update(const float &delta_time) {} void Renderer::initialize() { + glEnable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + std::cout << "Base Renderer initialized" << std::endl; } @@ -89,73 +122,112 @@ namespace simpleengine::gfx { } */ } - void Renderer::render() { + bool Renderer::render_job(const RenderingJob &job) { + Mesh *mesh = job.rendering_mesh; + + shader.set_uniform_matrix_4f("u_transform_matrix", job.transform_mat, false); + + std::optional &material = mesh->material; + + if (material.has_value()) { + shader.set_uniform_float("u_material.ambient_strength", material->ambient_strength, false); + shader.set_uniform_float("u_material.diffuse_strength", material->diffuse_strength, false); + shader.set_uniform_float("u_material.specular_strength", material->specular_strength, false); + shader.set_uniform_float("u_material.shine_factor", material->shine_factor, false); + // shader.set_uniform_float("u_material.reflect_factor", .1f, false); + + auto diffuse_maps = material->textures.find(aiTextureType_DIFFUSE); + auto diffuse_map = diffuse_maps->second.front(); + + shader.set_uniform_int("u_material.diffuse", 0, false); + + glActiveTexture(GL_TEXTURE0); + diffuse_map->bind(); + + // Apply the specular map if it exists + auto specular_maps = material->textures.find(aiTextureType_SPECULAR); + if (specular_maps != material->textures.end()) { + auto spec = specular_maps->second.front(); + + shader.set_uniform_int("u_material.has_specular_map", 1, false); + shader.set_uniform_int("u_material.specular_map", 1, false); + + glActiveTexture(GL_TEXTURE1); + spec->bind(); + } else { + shader.set_uniform_int("u_material.has_specular_map", 0, false); + } + + // Apply the normal map if it exists + auto normal_maps = material->textures.find(aiTextureType_NORMALS); + if (normal_maps != material->textures.end()) { + auto normal = normal_maps->second.front(); + + shader.set_uniform_int("u_material.has_normal_map", 1, false); + shader.set_uniform_int("u_material.normal_map", 2, false); + + glActiveTexture(GL_TEXTURE2); + normal->bind(); + } else { + shader.set_uniform_int("u_material.has_normal_map", 0, false); + } + } + + mesh->vao.bind(); + if (mesh->indicies.empty()) { + glDrawArrays(GL_TRIANGLES, 0, mesh->vertices.size()); + } else { + glDrawElements(GL_TRIANGLES, mesh->indicies.size(), GL_UNSIGNED_INT, 0); + } + + return true; + } + + void Renderer::render_job_queue(std::queue &rendering_queue) { shader.use(); - + while (!rendering_queue.empty()) { // Get the job from the queue, we'll remove it after we render. - RenderingJob& job = rendering_queue.front(); - Mesh& mesh = job.rendering_mesh; + RenderingJob &job = rendering_queue.front(); - shader.set_uniform_matrix_4f("u_transform_matrix", job.transform_mat, false); + bool res = this->render_job(job); - std::optional& material = mesh.material; - - if (material.has_value()) { - shader.set_uniform_float("u_material.ambient_strength", material->ambient_strength, false); - shader.set_uniform_float("u_material.diffuse_strength", material->diffuse_strength, false); - shader.set_uniform_float("u_material.specular_strength", material->specular_strength, false); - shader.set_uniform_float("u_material.shine_factor", material->shine_factor, false); - //shader.set_uniform_float("u_material.reflect_factor", .1f, false); - - auto diffuse_maps = material->textures.find(aiTextureType_DIFFUSE); - auto diffuse_map = diffuse_maps->second.front(); - - shader.set_uniform_int("u_material.diffuse", 0, false); - - glActiveTexture(GL_TEXTURE0); - diffuse_map->bind(); - - // Apply the specular map if it exists - auto specular_maps = material->textures.find(aiTextureType_SPECULAR); - if (specular_maps != material->textures.end()) { - auto spec = specular_maps->second.front(); - - shader.set_uniform_int("u_material.has_specular_map", 1, false); - shader.set_uniform_int("u_material.specular_map", 1, false); - - glActiveTexture(GL_TEXTURE1); - spec->bind(); - } else { - shader.set_uniform_int("u_material.has_specular_map", 0, false); - } - - // Apply the normal map if it exists - auto normal_maps = material->textures.find(aiTextureType_NORMALS); - if (normal_maps != material->textures.end()) { - auto normal = normal_maps->second.front(); - - shader.set_uniform_int("u_material.has_normal_map", 1, false); - shader.set_uniform_int("u_material.normal_map", 2, false); - - glActiveTexture(GL_TEXTURE2); - normal->bind(); - } else { - shader.set_uniform_int("u_material.has_normal_map", 0, false); - } + if (res) { + // Now we'll remove the job from the queue. + rendering_queue.pop(); } - - mesh.vao.bind(); - if (mesh.indicies.empty()) { - glDrawArrays(GL_TRIANGLES, 0, mesh.vertices.size()); - } else { - glDrawElements(GL_TRIANGLES, mesh.indicies.size(), GL_UNSIGNED_INT, 0); - } - - // Now we'll remove the job from the queue. - rendering_queue.pop(); } shader.unuse(); } -} \ No newline at end of file + + void Renderer::render_job_queue(std::map>& rendering_queue) { + shader.use(); + + // Render each job then clear the queue + for (const auto& it : rendering_queue) { + this->render_job(it.second); + } + rendering_queue.clear(); + + shader.unuse(); + } + + void Renderer::render() { + // Render other (opaque) objects first + this->render_job_queue(other_render_queue); + + // Render transparent objects + std::map> transparent_jobs; + while (!transparent_render_queue.empty()) { + RenderingJob& job = transparent_render_queue.front(); + + glm::vec3 pos = job.transform_mat[3]; + float distance = glm::distance(pos, camera->position); + transparent_jobs.emplace(distance, job); + + transparent_render_queue.pop(); + } + this->render_job_queue(transparent_jobs); + } +} // namespace simpleengine::gfx \ No newline at end of file diff --git a/src/gfx/texture.cpp b/src/gfx/texture.cpp index 4e2fc3d..257c5d0 100644 --- a/src/gfx/texture.cpp +++ b/src/gfx/texture.cpp @@ -10,24 +10,6 @@ namespace simpleengine::gfx { bool flip_vertically = flags & TextureFlags::TexFlags_FLIP_VERTICALLY; bool mipmap = flags & TextureFlags::TexFlags_MIPMAP; - // Get the color channel type for opengl, and get - // the channel count for loading the texture with stb_image - int gl_color_channels; - int channel_count; - if (flags & TexFlags_RGBA) { - channel_count = 4; - gl_color_channels = GL_RGBA; - } else if (flags & TexFlags_RGB) { - channel_count = 3; - gl_color_channels = GL_RGB; - } else if (flags & TexFlags_NO_COLOR) { - channel_count = 1; - gl_color_channels = GL_RED; - } else { - std::cerr << "Texture color flag is missing!! Specify TexFlags_RGBA" << std::endl; - throw std::runtime_error("Texture color flag is missing!! Specify TexFlags_RGBA"); - } - image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D; glGenTextures(1, &texture_id); @@ -42,7 +24,7 @@ namespace simpleengine::gfx { stbi_set_flip_vertically_on_load(flip_vertically); - img_data = stbi_load(path, &width, &height, &channels, channel_count); + unsigned char*img_data = stbi_load(path, &width, &height, &channels, 0); if(!img_data) { const char* failure = stbi_failure_reason(); std::cerr << "Failed to load texture! (" << failure << ")" << std::endl; @@ -50,13 +32,27 @@ namespace simpleengine::gfx { } std::cout << "Loaded image with a width of " << width << "px, a height of " << height << "px and " << channels << " channels" << std::endl; - glTexImage2D(image_type_gl, 0, gl_color_channels, width, height, 0, gl_color_channels, GL_UNSIGNED_BYTE, img_data); + // Get the color type + int color_format = 0; + if (channels == 1) { + color_format = GL_RED; + } else if (channels == 3) { + color_format = GL_RGB; + } else if (channels == 4) { + color_format = GL_RGBA; + } else { + std::cerr << "Unknown texture color format with " << channels << " channels!" << std::endl; + throw std::runtime_error("Unknown texture color format!"); + } + + glTexImage2D(image_type_gl, 0, color_format, width, height, 0, color_format, GL_UNSIGNED_BYTE, img_data); if (mipmap) { glGenerateMipmap(image_type_gl); } stbi_set_flip_vertically_on_load(false); + stbi_image_free(img_data); unbind(); } @@ -66,24 +62,6 @@ namespace simpleengine::gfx { bool flip_vertically = flags & TextureFlags::TexFlags_FLIP_VERTICALLY; bool mipmap = flags & TextureFlags::TexFlags_MIPMAP; - // Get the color channel type for opengl, and get - // the channel count for loading the texture with stb_image - int gl_color_channels; - int channel_count; - if (flags & TexFlags_RGBA) { - channel_count = 4; - gl_color_channels = GL_RGBA; - } else if (flags & TexFlags_RGB) { - channel_count = 3; - gl_color_channels = GL_RGB; - } else if (flags & TexFlags_NO_COLOR) { - channel_count = 1; - gl_color_channels = GL_RED; - } else { - std::cerr << "Texture color flag is missing!! Specify TexFlags_RGBA" << std::endl; - throw std::runtime_error("Texture color flag is missing!! Specify TexFlags_RGBA"); - } - image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D; glGenTextures(1, &texture_id); @@ -98,7 +76,7 @@ namespace simpleengine::gfx { stbi_set_flip_vertically_on_load(flip_vertically); - img_data = stbi_load_from_memory(buffer, buffer_length, &width, &height, &channels, channel_count); + unsigned char* img_data = stbi_load_from_memory(buffer, buffer_length, &width, &height, &channels, 0); if(!img_data) { const char* failure = stbi_failure_reason(); std::cerr << "Failed to load texture! (" << failure << ")" << std::endl; @@ -106,13 +84,27 @@ namespace simpleengine::gfx { } std::cout << "Loaded image with a width of " << width << "px, a height of " << height << "px and " << channels << " channels" << std::endl; - glTexImage2D(image_type_gl, 0, gl_color_channels, width, height, 0, gl_color_channels, GL_UNSIGNED_BYTE, img_data); + // Get the color type + int color_format = 0; + if (channels == 1) { + color_format = GL_RED; + } else if (channels == 3) { + color_format = GL_RGB; + } else if (channels == 4) { + color_format = GL_RGBA; + } else { + std::cerr << "Unknown texture color format with " << channels << " channels!" << std::endl; + throw std::runtime_error("Unknown texture color format!"); + } + + glTexImage2D(image_type_gl, 0, color_format, width, height, 0, color_format, GL_UNSIGNED_BYTE, img_data); if (mipmap) { glGenerateMipmap(image_type_gl); } stbi_set_flip_vertically_on_load(false); + stbi_image_free(img_data); unbind(); } @@ -138,7 +130,6 @@ namespace simpleengine::gfx { texture.height = height; texture.channels = 4; texture.type = aiTextureType::aiTextureType_DIFFUSE; - texture.img_data = data; glGenTextures(1, &texture.texture_id); texture.bind(); @@ -148,10 +139,12 @@ namespace simpleengine::gfx { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.img_data); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); texture.unbind(); + free(data); + return texture; } diff --git a/src/scene.cpp b/src/scene.cpp index c2caeff..8a5e735 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -19,12 +19,22 @@ namespace simpleengine { // Is there a way these can be grouped? registry.view().each([this](const TransformComponent& transform, ModelComponent& model_component) { for (auto& mesh : model_component.model.meshes) { - renderer->queue_job(gfx::RenderingJob(mesh, transform.transform_matrix)); + auto rendering_type = gfx::RenderingType::RendType_OPAQUE; + if (mesh.material) { + rendering_type = mesh.material->rendering_type; + } + + renderer->queue_job(gfx::RenderingJob(rendering_type, mesh, transform.transform_matrix)); } }); registry.view().each([this](const TransformComponent& transform, MeshComponent& mesh_component) { - renderer->queue_job(gfx::RenderingJob(mesh_component.mesh, transform.transform_matrix)); + auto rendering_type = gfx::RenderingType::RendType_OPAQUE; + if (mesh_component.mesh.material) { + rendering_type = mesh_component.mesh.material->rendering_type; + } + + renderer->queue_job(gfx::RenderingJob(rendering_type, mesh_component.mesh, transform.transform_matrix)); }); registry.view().each([this, &delta_time](TransformComponent& transform, RotatingComponent& rotating) {