Merge pull request #2 from SeanOMik/feature/texture-maps
Feature/texture maps
This commit is contained in:
commit
62321132cc
|
@ -0,0 +1,39 @@
|
||||||
|
---
|
||||||
|
Checks: "clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,modernize-*,-modernize-use-trailing-return-type"
|
||||||
|
WarningsAsErrors: true
|
||||||
|
HeaderFilterRegex: ""
|
||||||
|
AnalyzeTemporaryDtors: false
|
||||||
|
FormatStyle: google
|
||||||
|
CheckOptions:
|
||||||
|
- key: cert-dcl16-c.NewSuffixes
|
||||||
|
value: "L;LL;LU;LLU"
|
||||||
|
- key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
|
||||||
|
value: "0"
|
||||||
|
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
|
||||||
|
value: "1"
|
||||||
|
- key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
|
||||||
|
value: "1"
|
||||||
|
- key: google-readability-braces-around-statements.ShortStatementLines
|
||||||
|
value: "1"
|
||||||
|
- key: google-readability-function-size.StatementThreshold
|
||||||
|
value: "800"
|
||||||
|
- key: google-readability-namespace-comments.ShortNamespaceLines
|
||||||
|
value: "10"
|
||||||
|
- key: google-readability-namespace-comments.SpacesBeforeComments
|
||||||
|
value: "2"
|
||||||
|
- key: modernize-loop-convert.MaxCopySize
|
||||||
|
value: "16"
|
||||||
|
- key: modernize-loop-convert.MinConfidence
|
||||||
|
value: reasonable
|
||||||
|
- key: modernize-loop-convert.NamingStyle
|
||||||
|
value: CamelCase
|
||||||
|
- key: modernize-pass-by-value.IncludeStyle
|
||||||
|
value: llvm
|
||||||
|
- key: modernize-replace-auto-ptr.IncludeStyle
|
||||||
|
value: llvm
|
||||||
|
- key: modernize-use-nullptr.NullMacros
|
||||||
|
value: "NULL"
|
||||||
|
- key: readability-magic-numbers
|
||||||
|
value: "0"
|
||||||
|
---
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
include(ExternalProject)
|
||||||
|
ExternalProject_Add(external_assimp
|
||||||
|
GIT_REPOSITORY https://github.com/assimp/assimp.git
|
||||||
|
GIT_TAG v5.2.5
|
||||||
|
GIT_SUBMODULES_RECURSE true
|
||||||
|
GIT_PROGRESS true
|
||||||
|
CMAKE_ARGS
|
||||||
|
-D CMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
-D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||||
|
-D ASSIMP_INSTALL=NO
|
||||||
|
-D ASSIMP_BUILD_TESTS=NO
|
||||||
|
)
|
||||||
|
message("Downloaded assimp library")
|
|
@ -21,7 +21,7 @@ find_package(GLEW REQUIRED)
|
||||||
find_package(glfw3 CONFIG REQUIRED)
|
find_package(glfw3 CONFIG REQUIRED)
|
||||||
find_package(glm CONFIG REQUIRED)
|
find_package(glm CONFIG REQUIRED)
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
find_package(assimp REQUIRED)
|
find_package(assimp CONFIG REQUIRED)
|
||||||
|
|
||||||
# Link sources
|
# Link sources
|
||||||
file(GLOB_RECURSE source_list src/*.cpp)
|
file(GLOB_RECURSE source_list src/*.cpp)
|
||||||
|
@ -45,7 +45,14 @@ target_link_libraries(simpleengine PUBLIC GLEW::GLEW)
|
||||||
target_link_libraries(simpleengine PUBLIC glfw)
|
target_link_libraries(simpleengine PUBLIC glfw)
|
||||||
target_link_libraries(simpleengine PUBLIC ${GLM_LIBRARIES})
|
target_link_libraries(simpleengine PUBLIC ${GLM_LIBRARIES})
|
||||||
target_link_libraries(simpleengine PUBLIC ${OPENGL_LIBRARIES})
|
target_link_libraries(simpleengine PUBLIC ${OPENGL_LIBRARIES})
|
||||||
target_link_libraries(simpleengine PUBLIC assimp)
|
if(WIN32)
|
||||||
|
target_link_libraries(simpleengine PUBLIC assimp::assimp)
|
||||||
|
else()
|
||||||
|
target_link_libraries(simpleengine PUBLIC assimp)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Link resources
|
||||||
|
target_link_libraries(simpleengine PUBLIC cmrc::base)
|
||||||
target_link_libraries(simpleengine PRIVATE simpleengine_resources)
|
target_link_libraries(simpleengine PRIVATE simpleengine_resources)
|
||||||
|
|
||||||
# Include some dependencies' include directories
|
# Include some dependencies' include directories
|
||||||
|
|
|
@ -9,17 +9,17 @@ target_sources(dev_testing PRIVATE ${source_list})
|
||||||
target_include_directories(dev_testing PUBLIC include)
|
target_include_directories(dev_testing PUBLIC include)
|
||||||
|
|
||||||
# Embed shaders
|
# Embed shaders
|
||||||
file(GLOB_RECURSE shaders_list resources/shaders/*.glsl)
|
#file(GLOB_RECURSE shaders_list resources/shaders/*.glsl)
|
||||||
cmrc_add_resource_library(
|
#cmrc_add_resource_library(
|
||||||
resource_shaders
|
# resource_shaders
|
||||||
WHENCE resources/shaders
|
# WHENCE resources/shaders
|
||||||
PREFIX shaders
|
# PREFIX shaders
|
||||||
${shaders_list}
|
# ${shaders_list}
|
||||||
)
|
#)
|
||||||
|
|
||||||
# Link simpleengine
|
# Link simpleengine
|
||||||
target_link_libraries(dev_testing PUBLIC 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 standard to C++20
|
||||||
set_target_properties(dev_testing PROPERTIES CXX_STANDARD 20 CXX_EXTENSIONS OFF)
|
set_target_properties(dev_testing PROPERTIES CXX_STANDARD 20 CXX_EXTENSIONS OFF)
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,8 +1,6 @@
|
||||||
#include "simpleengine/camera.h"
|
#include "simpleengine/camera.h"
|
||||||
#include "simpleengine/ecs/component/mesh_component.h"
|
#include "simpleengine/ecs/component/mesh_component.h"
|
||||||
#include <simpleengine/ecs/component/model_component.h>
|
|
||||||
#include "simpleengine/ecs/component/transform_component.h"
|
#include "simpleengine/ecs/component/transform_component.h"
|
||||||
#include <simpleengine/ecs/component/rotating_component.h>
|
|
||||||
#include "simpleengine/ecs/entity.h"
|
#include "simpleengine/ecs/entity.h"
|
||||||
#include "simpleengine/gfx/light.h"
|
#include "simpleengine/gfx/light.h"
|
||||||
#include "simpleengine/gfx/material.h"
|
#include "simpleengine/gfx/material.h"
|
||||||
|
@ -11,29 +9,28 @@
|
||||||
#include "simpleengine/gfx/renderer.h"
|
#include "simpleengine/gfx/renderer.h"
|
||||||
#include "simpleengine/gfx/texture.h"
|
#include "simpleengine/gfx/texture.h"
|
||||||
#include "simpleengine/vector.h"
|
#include "simpleengine/vector.h"
|
||||||
#include <simpleengine/gfx/shader.h>
|
#include <simpleengine/ecs/component/model_component.h>
|
||||||
#include <simpleengine/renderable.h>
|
#include <simpleengine/ecs/component/rotating_component.h>
|
||||||
#include <simpleengine/event/event.h>
|
#include <simpleengine/event/event.h>
|
||||||
#include <simpleengine/shader_program.h>
|
|
||||||
#include <simpleengine/game.h>
|
#include <simpleengine/game.h>
|
||||||
#include <simpleengine/vertex.h>
|
|
||||||
#include <simpleengine/gfx/shaders/core_3d_shader.h>
|
|
||||||
#include <simpleengine/gfx/model.h>
|
#include <simpleengine/gfx/model.h>
|
||||||
|
#include <simpleengine/gfx/shader.h>
|
||||||
|
#include <simpleengine/gfx/shaders/core_3d_shader.h>
|
||||||
|
#include <simpleengine/renderable.h>
|
||||||
#include <simpleengine/scene.h>
|
#include <simpleengine/scene.h>
|
||||||
|
#include <simpleengine/shader_program.h>
|
||||||
|
#include <simpleengine/vertex.h>
|
||||||
|
|
||||||
|
#include <assimp/material.h>
|
||||||
#include <glm/ext/matrix_clip_space.hpp>
|
#include <glm/ext/matrix_clip_space.hpp>
|
||||||
#include <glm/fwd.hpp>
|
#include <glm/fwd.hpp>
|
||||||
#include <assimp/material.h>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <cmrc/cmrc.hpp>
|
|
||||||
CMRC_DECLARE(resource_shaders);
|
|
||||||
|
|
||||||
namespace se = simpleengine;
|
namespace se = simpleengine;
|
||||||
|
|
||||||
class FPSCounterEvent : public se::Event {
|
class FPSCounterEvent : public se::Event {
|
||||||
|
@ -46,13 +43,13 @@ public:
|
||||||
frame_count = 0;
|
frame_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void update(const float& delta_time) {
|
virtual void update(const float &delta_time) {
|
||||||
double current_time = glfwGetTime();
|
double current_time = glfwGetTime();
|
||||||
frame_count++;
|
frame_count++;
|
||||||
|
|
||||||
// Check if the last print was 1 second ago.
|
// Check if the last print was 1 second ago.
|
||||||
if (current_time - last_frame_time >= 1.0) {
|
if (current_time - last_frame_time >= 1.0) {
|
||||||
double ms_per_frame = 1000 / (double) frame_count;
|
double ms_per_frame = 1000 / (double)frame_count;
|
||||||
|
|
||||||
printf("%d fps, %f ms/frame\n", frame_count, ms_per_frame);
|
printf("%d fps, %f ms/frame\n", frame_count, ms_per_frame);
|
||||||
frame_count = 0;
|
frame_count = 0;
|
||||||
|
@ -61,158 +58,52 @@ 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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
se::Game game(640, 480, "SimpleEngine 3D OpenGL - Developer Testing", GLFW_OPENGL_CORE_PROFILE, 4, 4, false);
|
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
|
// Load core shaders from SimpleEngine resources
|
||||||
se::gfx::shaders::Core3dShader core_shader;
|
se::gfx::shaders::Core3dShader core_shader;
|
||||||
|
|
||||||
auto light = std::make_shared<se::gfx::Light>(core_shader, glm::vec3(0.f, 1.f, -10.f), glm::vec3(1.f, 1.f, 1.f));
|
auto camera = std::make_shared<se::Camera>(game.get_window(), core_shader, 70, glm::vec3(0, 0, 0));
|
||||||
game.add_event(light);
|
game.add_event(camera);
|
||||||
|
|
||||||
auto white_texture = se::gfx::Texture::white_texture();
|
|
||||||
// white_texture.shine_damper = 10;
|
|
||||||
//white_texture.reflectivity = 1;
|
|
||||||
/* auto dragon = std::make_shared<se::objects_3d::Mesh>(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<se::objects_3d::Mesh>(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<se::objects_3d::Terrain>(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<se::objects_3d::Mesh>(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<se::Vertex> 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<GLuint> indicies = {
|
|
||||||
0, 1, 3,
|
|
||||||
1, 2, 3
|
|
||||||
};
|
|
||||||
|
|
||||||
auto square = std::make_shared<se::gfx::Model>(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<se::objects_3d::Mesh>(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<se::Vertex> 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<se::gfx::Model>(game.get_window(), core_shader, tri_vertices);
|
|
||||||
tri->translate(-1.25f, 0.f, -1.f);
|
|
||||||
tri->scale(.75f);
|
|
||||||
game.add_event(tri); */
|
|
||||||
|
|
||||||
std::vector<se::LitVertex> 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<GLuint> 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
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<se::gfx::Texture>>> textures;
|
|
||||||
textures.emplace(white_texture.type, std::vector<std::shared_ptr<se::gfx::Texture>>{ std::make_shared<se::gfx::Texture>(white_texture) });
|
|
||||||
se::gfx::Material white_material(textures, 1.f, 0.f, 0.f, 0.f, 0.f);
|
|
||||||
|
|
||||||
// Create a renderer
|
// Create a renderer
|
||||||
auto renderer = std::make_shared<se::gfx::Renderer>(game.get_window(), core_shader);
|
auto renderer = std::make_shared<se::gfx::Renderer>(game.get_window(), core_shader, camera);
|
||||||
|
renderer->initialize();
|
||||||
game.add_renderable(renderer);
|
game.add_renderable(renderer);
|
||||||
|
|
||||||
// Create a Scene and give it the renderer
|
// Create a Scene and give it the renderer
|
||||||
auto scene = std::make_shared<se::Scene>(renderer);
|
auto scene = std::make_shared<se::Scene>(renderer);
|
||||||
game.add_event(scene);
|
game.add_event(scene);
|
||||||
|
|
||||||
|
se::ecs::Entity other_e = scene->create_entity();
|
||||||
|
other_e.add_component<se::ModelComponent>("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<se::TransformComponent>();
|
||||||
|
other_transform.translate(5.f, 0.5f, 1.f);
|
||||||
|
|
||||||
// Create an Entity in the Scene and add components to it.
|
// Create an Entity in the Scene and add components to it.
|
||||||
se::ecs::Entity entity = scene->create_entity();
|
se::ecs::Entity entity = scene->create_entity();
|
||||||
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/dragon.obj");
|
|
||||||
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/stall.obj");
|
|
||||||
|
|
||||||
// Backpack model required vertically flipped texture coords.
|
// entity.add_component<se::ModelComponent>("examples/dev_testing/resources/planks/planks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE);
|
||||||
auto& model_comp = entity.add_component<se::ModelComponent>("examples/dev_testing/resources/backpack/backpack.obj");
|
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/bricks/bricks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE);
|
||||||
model_comp.model.vertically_flip_tex_coords();
|
entity.add_component<se::ModelComponent>("examples/dev_testing/resources/transparent_window.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE | simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_TRANSPARENT);
|
||||||
|
|
||||||
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/scientist/scientist.fbx");
|
auto &transform_comp = entity.add_component<se::TransformComponent>();
|
||||||
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/paradigm/paradigm.fbx");
|
transform_comp.translate(4.f, 0.f, 0.f);
|
||||||
//entity.add_component<se::RotatingComponent>();
|
|
||||||
auto& transform_comp = entity.add_component<se::TransformComponent>();
|
|
||||||
transform_comp.translate(15.f, -8.f, 0.f);
|
|
||||||
/* transform_comp.scale(0.1f);
|
|
||||||
transform_comp.rotate_z(-90.f);*/
|
|
||||||
transform_comp.rotate_x(-90.f);
|
|
||||||
|
|
||||||
|
se::ecs::Entity brick_e = scene->create_entity();
|
||||||
|
brick_e.add_component<se::ModelComponent>("examples/dev_testing/resources/bricks/bricks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE);
|
||||||
|
auto &brick_transf = brick_e.add_component<se::TransformComponent>();
|
||||||
|
brick_transf.translate(6.f, -0.5f, 1.f);
|
||||||
|
|
||||||
// Create the entity and add the model component to it.
|
auto light = std::make_shared<se::gfx::Light>(core_shader, glm::vec3(0.f, 0.f, 0.f), glm::vec3(1.f, 1.f, 1.f));
|
||||||
/* auto entity = std::make_shared<simpleengine::Entity>();
|
game.add_event(light);
|
||||||
entity->add_component<se::MeshComponent>(cube_vertices, cube_indicies, white_material, true);
|
|
||||||
entity->translate(3.5f, 0.f, 0.f); */
|
|
||||||
|
|
||||||
/* auto entity = std::make_shared<simpleengine::Entity>();
|
|
||||||
entity->add_component<se::ModelComponent>("examples/dev_testing/resources/dragon.obj");
|
|
||||||
entity->translate(12.f, -4.f, 0.f); */
|
|
||||||
|
|
||||||
auto camera = std::make_shared<se::Camera>(game.get_window(), core_shader, 70, glm::vec3(0, 0, 0));
|
|
||||||
game.add_event(camera);
|
|
||||||
|
|
||||||
auto fps_counter = std::make_shared<FPSCounterEvent>();
|
auto fps_counter = std::make_shared<FPSCounterEvent>();
|
||||||
game.add_event(fps_counter);
|
game.add_event(fps_counter);
|
||||||
|
|
||||||
game.set_enable_vsync(true);
|
game.set_enable_vsync(true);
|
||||||
//game.set_fps_limit(120);
|
// game.set_fps_limit(120);
|
||||||
int res = game.run();
|
int res = game.run();
|
||||||
|
|
||||||
renderer->destroy();
|
renderer->destroy();
|
||||||
|
|
|
@ -18,8 +18,8 @@ namespace simpleengine::gfx {
|
||||||
|
|
||||||
virtual void update(const float& delta_time) override {
|
virtual void update(const float& delta_time) override {
|
||||||
shader.use();
|
shader.use();
|
||||||
shader.set_uniform_float_vec3("light_position", position, false);
|
shader.set_uniform_float_vec3("u_light_position", position, false);
|
||||||
shader.set_uniform_float_vec3("light_color", color, false);
|
shader.set_uniform_float_vec3("u_light_color", color, false);
|
||||||
shader.unuse();
|
shader.unuse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "rendering_type.h"
|
||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
|
|
||||||
#include <assimp/material.h>
|
#include <assimp/material.h>
|
||||||
|
@ -10,17 +11,34 @@
|
||||||
namespace simpleengine::gfx {
|
namespace simpleengine::gfx {
|
||||||
class Material {
|
class Material {
|
||||||
public:
|
public:
|
||||||
|
RenderingType rendering_type;
|
||||||
|
|
||||||
|
// TODO: Only one of each texture type.
|
||||||
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> textures;
|
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> textures;
|
||||||
|
|
||||||
float ambient_scalar;
|
float ambient_strength;
|
||||||
float diffuse_scalar;
|
float diffuse_strength;
|
||||||
float specular_scalar;
|
|
||||||
float shine;
|
|
||||||
float reflectivity;
|
|
||||||
|
|
||||||
Material(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> textures, float shine = 1.f, float reflectivity = 0.f, float specular_scalar = 0.f, float ambient_scalar = 0.f, float diffuse_scalar = 0.f) :
|
/**
|
||||||
textures(textures), ambient_scalar(ambient_scalar), diffuse_scalar(diffuse_scalar), specular_scalar(specular_scalar),
|
* @brief This strengthens the brightness of a specular highlight.
|
||||||
shine(shine), reflectivity(reflectivity) {
|
*
|
||||||
|
*/
|
||||||
|
float specular_strength;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The shininess value of the highlight. (Radius of specular highlight?)
|
||||||
|
|
||||||
|
* The higher the shininess value of an object, the more it properly reflects the light
|
||||||
|
* instead of scattering it all around and thus the smaller the highlight becomes.
|
||||||
|
*
|
||||||
|
* The shader multiplies this by 32 to get the specular highlight.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
float shine_factor;
|
||||||
|
|
||||||
|
Material(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> 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) {
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "../renderable.h"
|
#include "../renderable.h"
|
||||||
#include "../transformable.h"
|
#include "../transformable.h"
|
||||||
#include "material.h"
|
#include "material.h"
|
||||||
|
#include "../vector.h"
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -23,6 +24,9 @@ namespace simpleengine::gfx {
|
||||||
std::vector<LitVertex> vertices;
|
std::vector<LitVertex> vertices;
|
||||||
std::vector<GLuint> indicies;
|
std::vector<GLuint> indicies;
|
||||||
|
|
||||||
|
std::vector<simpleengine::Vectorf> tangents;
|
||||||
|
gfx::VBO tangent_vbo;
|
||||||
|
|
||||||
bool are_buffers_created = false;
|
bool are_buffers_created = false;
|
||||||
gfx::VBO ebo;
|
gfx::VBO ebo;
|
||||||
gfx::VBO vbo;
|
gfx::VBO vbo;
|
||||||
|
@ -30,7 +34,7 @@ namespace simpleengine::gfx {
|
||||||
|
|
||||||
Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, Material material);
|
Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, Material material);
|
||||||
Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies = std::vector<GLuint>(), std::optional<Material> material = std::nullopt);
|
Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies = std::vector<GLuint>(), std::optional<Material> material = std::nullopt);
|
||||||
Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, Material material, gfx::VBO ebo, gfx::VBO vbo, gfx::VAO vao);
|
Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, Material material, gfx::VBO ebo, gfx::VBO vbo, gfx::VAO vao, gfx::VBO tangent_vbo);
|
||||||
|
|
||||||
virtual void destroy() override;
|
virtual void destroy() override;
|
||||||
|
|
||||||
|
@ -45,5 +49,12 @@ namespace simpleengine::gfx {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void calculate_normals();
|
void calculate_normals();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculate tangents and bi-tangents (tangent space) for the model.
|
||||||
|
*
|
||||||
|
* @note This **will** overwrite the existing tangents and bi-tangents.
|
||||||
|
*/
|
||||||
|
void calculate_tangents();
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "mesh.h"
|
#include "mesh.h"
|
||||||
#include "simpleengine/gfx/texture.h"
|
#include "simpleengine/gfx/texture.h"
|
||||||
|
#include "../vector.h"
|
||||||
|
|
||||||
#include <assimp/material.h>
|
#include <assimp/material.h>
|
||||||
#include <assimp/mesh.h>
|
#include <assimp/mesh.h>
|
||||||
|
@ -14,6 +15,8 @@ namespace simpleengine::gfx {
|
||||||
MdlProcFlag_NONE = 0b00000000,
|
MdlProcFlag_NONE = 0b00000000,
|
||||||
MdlProcFlag_FLIP_TEX_COORDS_VERTICALLY = 0b00000001,
|
MdlProcFlag_FLIP_TEX_COORDS_VERTICALLY = 0b00000001,
|
||||||
MdlProcFlag_FLIP_TEX_COORDS_HORIZONTALLY = 0b00000010,
|
MdlProcFlag_FLIP_TEX_COORDS_HORIZONTALLY = 0b00000010,
|
||||||
|
MdlProcFlag_CALCULATE_TANGENT_SPACE = 0b00000100,
|
||||||
|
MdlProcFlag_TRANSPARENT = 0b00001000,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,12 +42,12 @@ namespace simpleengine::gfx {
|
||||||
|
|
||||||
std::unordered_map<aiTextureType, std::vector<Texture>> load_all_textures(aiMaterial* material);
|
std::unordered_map<aiTextureType, std::vector<Texture>> load_all_textures(aiMaterial* material);
|
||||||
std::vector<std::shared_ptr<Texture>> load_material_texture(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMaterial* material, aiTextureType type);
|
std::vector<std::shared_ptr<Texture>> load_material_texture(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMaterial* material, aiTextureType type);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void post_process();
|
void post_process();
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void vertically_flip_tex_coords();
|
void vertically_flip_tex_coords();
|
||||||
void horizontally_flip_tex_coords();
|
void horizontally_flip_tex_coords();
|
||||||
|
void calculate_tangents();
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -1,36 +1,45 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../camera.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "simpleengine/gfx/mesh.h"
|
#include "../renderable.h"
|
||||||
|
#include "rendering_type.h"
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
namespace simpleengine::gfx {
|
namespace simpleengine::gfx {
|
||||||
|
class Mesh;
|
||||||
|
|
||||||
class RenderingJob {
|
class RenderingJob {
|
||||||
public:
|
public:
|
||||||
gfx::Mesh& rendering_mesh;
|
RenderingType rendering_type;
|
||||||
|
gfx::Mesh* rendering_mesh;
|
||||||
glm::mat4 transform_mat;
|
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 {
|
class Renderer : public simpleengine::Renderable {
|
||||||
private:
|
private:
|
||||||
GLFWwindow* window;
|
GLFWwindow* window;
|
||||||
|
protected:
|
||||||
public:
|
public:
|
||||||
|
std::queue<RenderingJob> transparent_render_queue;
|
||||||
|
std::queue<RenderingJob> other_render_queue;
|
||||||
|
|
||||||
std::queue<RenderingJob> rendering_queue;
|
|
||||||
gfx::Shader shader;
|
gfx::Shader shader;
|
||||||
|
std::shared_ptr<Camera> camera;
|
||||||
|
|
||||||
Renderer(GLFWwindow* window, gfx::Shader shader);
|
Renderer(GLFWwindow* window, gfx::Shader shader, std::shared_ptr<Camera> camera);
|
||||||
Renderer(GLFWwindow* window, GLuint shader_program);
|
Renderer(GLFWwindow* window, GLuint shader_program, std::shared_ptr<Camera> camera);
|
||||||
|
|
||||||
void enable_debug();
|
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 queue_job(RenderingJob job);
|
||||||
virtual void create_job_buffers(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 update(const float& delta_time) override;
|
||||||
|
|
||||||
virtual void render() 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<RenderingJob>& queue);
|
||||||
|
virtual void render_job_queue(std::map<float, RenderingJob, std::greater<>>& queue);
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace simpleengine::gfx {
|
||||||
|
enum RenderingType {
|
||||||
|
RendType_OPAQUE = 0,
|
||||||
|
RendType_TRANSPARENT = 1,
|
||||||
|
};
|
||||||
|
}
|
|
@ -23,17 +23,30 @@ namespace simpleengine::gfx {
|
||||||
TexFlags_FLIP_VERTICALLY = 0b00000010,
|
TexFlags_FLIP_VERTICALLY = 0b00000010,
|
||||||
TexFlags_FLIP_HORIZONTALLY = 0b00000100,
|
TexFlags_FLIP_HORIZONTALLY = 0b00000100,
|
||||||
TexFlags_MIPMAP = 0b00001000,
|
TexFlags_MIPMAP = 0b00001000,
|
||||||
|
/* TexFlags_NO_COLOR = 0b00010000,
|
||||||
|
TexFlags_RGB = 0b00100000,
|
||||||
|
TexFlags_RGBA = 0b01000000, */
|
||||||
};
|
};
|
||||||
|
|
||||||
class Texture {
|
class Texture {
|
||||||
private:
|
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 texture_id;
|
||||||
|
|
||||||
unsigned int image_type_gl;
|
unsigned int image_type_gl;
|
||||||
|
|
||||||
Texture() = default;
|
Texture() = default;
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief The default Texture flags including the color.
|
||||||
|
*
|
||||||
|
* The default flags are `TexFlags_IMG_2D | TexFlags_MIPMAP`
|
||||||
|
*
|
||||||
|
* @see simpleengine::gfx::Texture::default_flags_no_color
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static constexpr int default_flags = TexFlags_IMG_2D | TexFlags_MIPMAP;
|
||||||
|
|
||||||
int height;
|
int height;
|
||||||
int width;
|
int width;
|
||||||
int channels;
|
int channels;
|
||||||
|
@ -47,8 +60,7 @@ namespace simpleengine::gfx {
|
||||||
* @param img_2d Whether or not the texture is 2D.
|
* @param img_2d Whether or not the texture is 2D.
|
||||||
* @param mipmap Whether or not to generate mipmaps for this texture.
|
* @param mipmap Whether or not to generate mipmaps for this texture.
|
||||||
*/
|
*/
|
||||||
Texture(const char* path, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, int flags = TextureFlags::TexFlags_IMG_2D |
|
Texture(const char* path, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, int flags = Texture::default_flags);
|
||||||
TextureFlags::TexFlags_MIPMAP);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Construct a new Texture object from the loaded file buffer.
|
* @brief Construct a new Texture object from the loaded file buffer.
|
||||||
|
@ -58,8 +70,7 @@ namespace simpleengine::gfx {
|
||||||
* @param img_2d Whether or not the texture is 2D.
|
* @param img_2d Whether or not the texture is 2D.
|
||||||
* @param mipmap Whether or not to generate mipmaps for this texture.
|
* @param mipmap Whether or not to generate mipmaps for this texture.
|
||||||
*/
|
*/
|
||||||
Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, int flags = TextureFlags::TexFlags_IMG_2D |
|
Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, int flags = Texture::default_flags);
|
||||||
TextureFlags::TexFlags_MIPMAP);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Construct a new Texture object from the loaded file buffer.
|
* @brief Construct a new Texture object from the loaded file buffer.
|
||||||
|
@ -68,8 +79,7 @@ namespace simpleengine::gfx {
|
||||||
* @param img_2d Whether or not the texture is 2D.
|
* @param img_2d Whether or not the texture is 2D.
|
||||||
* @param mipmap Whether or not to generate mipmaps for this texture.
|
* @param mipmap Whether or not to generate mipmaps for this texture.
|
||||||
*/
|
*/
|
||||||
Texture(std::vector<unsigned char> buffer, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, int flags = TextureFlags::TexFlags_IMG_2D |
|
Texture(std::vector<unsigned char> buffer, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, int flags = Texture::default_flags);
|
||||||
TextureFlags::TexFlags_MIPMAP);
|
|
||||||
|
|
||||||
static Texture white_texture();
|
static Texture white_texture();
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,10 @@ namespace simpleengine::gfx {
|
||||||
glBindVertexArray(handle);
|
glBindVertexArray(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unbind() const {
|
||||||
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Fix this.
|
// TODO: Fix this.
|
||||||
void enable_attrib(const VBO& vbo, GLuint index, GLint size, GLenum type, GLsizei stride, size_t offset, bool should_bind = true) const {
|
void enable_attrib(const VBO& vbo, GLuint index, GLint size, GLenum type, GLsizei stride, size_t offset, bool should_bind = true) const {
|
||||||
if (should_bind) {
|
if (should_bind) {
|
||||||
|
|
|
@ -40,6 +40,10 @@ namespace simpleengine::gfx {
|
||||||
glBindBuffer(type, handle);
|
glBindBuffer(type, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unbind() const {
|
||||||
|
glBindBuffer(type, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void buffer(void *data, size_t offset, size_t size) {
|
void buffer(void *data, size_t offset, size_t size) {
|
||||||
bind();
|
bind();
|
||||||
glBufferData(type, size - offset, data, dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
|
glBufferData(type, size - offset, data, dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
|
||||||
|
|
|
@ -26,22 +26,21 @@ namespace simpleengine {
|
||||||
glm::vec3 color;
|
glm::vec3 color;
|
||||||
glm::vec2 tex_coord;
|
glm::vec2 tex_coord;
|
||||||
glm::vec3 normal;
|
glm::vec3 normal;
|
||||||
float texture_id = -1.f;
|
|
||||||
|
|
||||||
LitVertex() = default;
|
LitVertex() = default;
|
||||||
|
|
||||||
LitVertex(simpleengine::Vectorf position, glm::vec3 color, glm::vec2 tex_coord, int texture_id = -1.f) :
|
LitVertex(simpleengine::Vectorf position, glm::vec3 color, glm::vec2 tex_coord, int texture_id = -1.f) :
|
||||||
position(position), color(color), tex_coord(tex_coord), normal(glm::vec3(0.f)), texture_id((float) texture_id) {
|
position(position), color(color), tex_coord(tex_coord), normal(glm::vec3(0.f)) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LitVertex(simpleengine::Vectorf position, glm::vec3 color, glm::vec2 tex_coord, glm::vec3 normal, int texture_id = -1.f) :
|
LitVertex(simpleengine::Vectorf position, glm::vec3 color, glm::vec2 tex_coord, glm::vec3 normal, int texture_id = -1.f) :
|
||||||
position(position), color(color), tex_coord(tex_coord), normal(normal), texture_id((float) texture_id) {
|
position(position), color(color), tex_coord(tex_coord), normal(normal) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LitVertex(simpleengine::Vectorf position, glm::vec2 tex_coord, glm::vec3 normal, int texture_id = -1.f) :
|
LitVertex(simpleengine::Vectorf position, glm::vec2 tex_coord, glm::vec3 normal, int texture_id = -1.f) :
|
||||||
position(position), color(glm::vec3(1.f)), tex_coord(tex_coord), normal(normal), texture_id((float) texture_id) {
|
position(position), color(glm::vec3(1.f)), tex_coord(tex_coord), normal(normal) {
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,56 +3,94 @@
|
||||||
in vec3 vs_position;
|
in vec3 vs_position;
|
||||||
in vec3 vs_color;
|
in vec3 vs_color;
|
||||||
in vec3 vs_normal;
|
in vec3 vs_normal;
|
||||||
|
in vec3 vs_world_normal; // Normal in world space
|
||||||
in vec2 vs_texcoord;
|
in vec2 vs_texcoord;
|
||||||
flat in float vs_tex_id; // < 0 is reserved for solid colored objects.
|
|
||||||
|
|
||||||
in mat4 vs_transform;
|
in mat4 vs_transform;
|
||||||
in vec3 vs_to_light;
|
|
||||||
in vec3 vs_to_camera;
|
|
||||||
|
|
||||||
uniform sampler2D u_textures[16];
|
in vec3 vs_view_pos;
|
||||||
uniform float u_texture_shine[16];
|
in vec3 vs_light_pos;
|
||||||
uniform float u_texture_reflectivity[16];
|
in vec3 vs_frag_pos;
|
||||||
|
|
||||||
uniform vec3 light_color;
|
//in mat3 vs_tbn;
|
||||||
|
|
||||||
|
in vec3 vs_tangent_light_pos;
|
||||||
|
in vec3 vs_tangent_view_pos;
|
||||||
|
in vec3 vs_tangent_frag_pos;
|
||||||
|
|
||||||
|
const int SAMP_DIFFUSE = 0;
|
||||||
|
const int SAMP_SPECULAR = 1;
|
||||||
|
|
||||||
|
struct Material {
|
||||||
|
sampler2D diffuse;
|
||||||
|
|
||||||
|
bool has_specular_map;
|
||||||
|
sampler2D specular_map;
|
||||||
|
|
||||||
|
// TODO: Make Optional
|
||||||
|
bool has_normal_map;
|
||||||
|
sampler2D normal_map;
|
||||||
|
|
||||||
|
float ambient_strength;
|
||||||
|
float diffuse_strength;
|
||||||
|
float specular_strength;
|
||||||
|
|
||||||
|
float shine_factor;
|
||||||
|
};
|
||||||
|
|
||||||
|
uniform Material u_material;
|
||||||
|
|
||||||
|
uniform vec3 u_light_color;
|
||||||
|
|
||||||
out vec4 fs_color;
|
out vec4 fs_color;
|
||||||
|
|
||||||
vec3 calculate_specular(vec3 unit_normal, float shine_damper, float reflectivity);
|
vec3 calculate_lighting();
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// Lighting
|
// Skip completely transparent fragments.
|
||||||
vec3 unit_normal = normalize(vs_normal);
|
/* vec4 diffuse = texture(u_material.diffuse, vs_texcoord);
|
||||||
vec3 unit_light_vector = normalize(vs_to_light);
|
if (diffuse.a < 0.1) {
|
||||||
|
discard;
|
||||||
|
} */
|
||||||
|
|
||||||
float dot_prod = dot(unit_normal, unit_light_vector);
|
vec3 lighting = calculate_lighting();
|
||||||
float brightness = max(dot_prod, 0.f);
|
|
||||||
vec3 diffuse = brightness * light_color;
|
|
||||||
|
|
||||||
if (vs_tex_id > -1) {
|
fs_color = vec4(lighting, 1.f) * texture(u_material.diffuse, vs_texcoord);
|
||||||
int id = int(vs_tex_id);
|
|
||||||
|
|
||||||
float shine_damper = u_texture_shine[id];
|
|
||||||
float reflectivity = u_texture_reflectivity[id];
|
|
||||||
vec3 final_specular = calculate_specular(unit_normal, shine_damper, reflectivity);
|
|
||||||
|
|
||||||
fs_color = vec4(diffuse, 1.f) * texture(u_textures[id], vs_texcoord) + vec4(final_specular, 1.f);
|
|
||||||
} else {
|
|
||||||
fs_color = vec4(vs_color, 1.f); // We don't add any reflectivity to solid colored vectors.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 calculate_specular(vec3 unit_normal, float shine_damper, float reflectivity) {
|
vec3 calculate_lighting() {
|
||||||
vec3 final_specular = vec3(0.f);
|
vec3 normal = vec3(0.f, 0.f, 1.f); // default tangent-space normal
|
||||||
if (reflectivity > 0) {
|
|
||||||
vec3 unit_vector_to_camera = normalize(vs_to_camera);
|
// Check if the normal map is set before trying to apply it.
|
||||||
vec3 light_direction = -unit_vector_to_camera;
|
if (u_material.has_normal_map) {
|
||||||
vec3 reflected_light_dir = reflect(light_direction, unit_normal);
|
normal = texture(u_material.normal_map, vs_texcoord).rgb;
|
||||||
float specular_factor = dot(reflected_light_dir, unit_vector_to_camera);
|
|
||||||
specular_factor = max(specular_factor, 0.f);
|
// transform normal vector to range [-1,1]
|
||||||
float damped_specular = pow(specular_factor, shine_damper);
|
normal = normalize(normal * 2.f - 1.f); // this normal is in tangent space
|
||||||
final_specular = damped_specular * reflectivity * light_color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return final_specular;
|
// Get diffuse color
|
||||||
|
vec3 diffuse_map = texture(u_material.diffuse, vs_texcoord).rgb;
|
||||||
|
|
||||||
|
// Ambient lighting
|
||||||
|
vec3 ambient = 0.1f * u_material.ambient_strength * diffuse_map;
|
||||||
|
|
||||||
|
// Diffuse lighting
|
||||||
|
vec3 light_dir = normalize(vs_tangent_light_pos - vs_tangent_frag_pos);
|
||||||
|
float diff = max(dot(light_dir, normal), 0.f);
|
||||||
|
vec3 diffuse = diff * u_material.diffuse_strength * diffuse_map;
|
||||||
|
|
||||||
|
// Specular lighting
|
||||||
|
vec3 view_dir = normalize(vs_tangent_view_pos - vs_tangent_frag_pos);
|
||||||
|
vec3 reflect_dir = reflect(-light_dir, normal);
|
||||||
|
vec3 halfway_dir = normalize(light_dir + view_dir);
|
||||||
|
float spec = pow(max(dot(normal, halfway_dir), 0.f), 32.f * u_material.shine_factor);
|
||||||
|
vec3 specular = vec3(0.2f * u_material.specular_strength) * spec;
|
||||||
|
|
||||||
|
// Check if the specular map is set before trying to apply it.
|
||||||
|
if (u_material.has_specular_map) {
|
||||||
|
specular = specular * texture(u_material.specular_map, vs_texcoord).r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ambient + diffuse + specular;
|
||||||
}
|
}
|
|
@ -4,38 +4,62 @@ layout (location = 0) in vec3 vertex_position;
|
||||||
layout (location = 1) in vec3 vertex_color;
|
layout (location = 1) in vec3 vertex_color;
|
||||||
layout (location = 2) in vec3 vertex_normal;
|
layout (location = 2) in vec3 vertex_normal;
|
||||||
layout (location = 3) in vec2 vertex_texcoord;
|
layout (location = 3) in vec2 vertex_texcoord;
|
||||||
layout (location = 4) in float vertex_tex_id;
|
// TODO: Make these optional
|
||||||
|
layout (location = 4) in vec3 vertex_tangent;
|
||||||
|
|
||||||
out vec3 vs_position;
|
out vec3 vs_position;
|
||||||
out vec3 vs_color;
|
out vec3 vs_color;
|
||||||
out vec3 vs_normal;
|
out vec3 vs_normal;
|
||||||
|
out vec3 vs_world_normal; // normal in world space
|
||||||
out vec2 vs_texcoord;
|
out vec2 vs_texcoord;
|
||||||
flat out float vs_tex_id;
|
|
||||||
|
|
||||||
out mat4 vs_transform;
|
out mat4 vs_transform;
|
||||||
out vec3 vs_to_light;
|
|
||||||
out vec3 vs_to_camera;
|
|
||||||
|
|
||||||
uniform mat4 transform_matrix;
|
out vec3 vs_view_pos;
|
||||||
uniform mat4 view_matrix;
|
out vec3 vs_light_pos;
|
||||||
uniform mat4 projection_matrix;
|
out vec3 vs_frag_pos;
|
||||||
uniform vec3 light_position;
|
|
||||||
|
//out mat3 vs_tbn;
|
||||||
|
|
||||||
|
out vec3 vs_tangent_light_pos;
|
||||||
|
out vec3 vs_tangent_view_pos;
|
||||||
|
out vec3 vs_tangent_frag_pos;
|
||||||
|
|
||||||
|
uniform mat4 u_transform_matrix;
|
||||||
|
uniform mat4 u_view_matrix;
|
||||||
|
uniform mat4 u_projection_matrix;
|
||||||
|
|
||||||
|
uniform vec3 u_view_pos;
|
||||||
|
uniform vec3 u_light_position;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 world_pos = (transform_matrix * vec4(vertex_position, 1.f));
|
vec4 world_pos = (u_transform_matrix * vec4(vertex_position, 1.f));
|
||||||
|
|
||||||
// Directly pass things to the fragment shader.
|
// Directly pass things to the fragment shader.
|
||||||
vs_position = world_pos.xyz;
|
vs_position = world_pos.xyz;
|
||||||
vs_transform = transform_matrix;
|
vs_transform = u_transform_matrix;
|
||||||
vs_texcoord = vertex_texcoord;
|
vs_texcoord = vertex_texcoord;
|
||||||
vs_color = vertex_color;
|
vs_color = vertex_color;
|
||||||
|
|
||||||
vs_tex_id = vertex_tex_id;
|
gl_Position = u_projection_matrix * u_view_matrix * world_pos;
|
||||||
|
|
||||||
|
// Apply transform matrix to normal.
|
||||||
|
vs_normal = (u_transform_matrix * vec4(vertex_normal, 0.f)).xyz;
|
||||||
|
|
||||||
gl_Position = projection_matrix * view_matrix * world_pos;
|
vs_view_pos = u_view_pos;
|
||||||
|
vs_light_pos = u_light_position;
|
||||||
|
vs_frag_pos = vec3(u_transform_matrix * vec4(vertex_position, 1.f));
|
||||||
|
vs_world_normal = mat3(transpose(inverse(u_transform_matrix))) * vertex_normal; // TODO: Do this calculation on the CPU then send to GPU via a uniform
|
||||||
|
|
||||||
vs_normal = (transform_matrix * vec4(vertex_normal, 0.f)).xyz;
|
// Calculate tangent space stuff.
|
||||||
vs_to_light = light_position - world_pos.xyz;
|
mat3 normal_matrix = transpose(inverse(mat3(u_transform_matrix)));
|
||||||
vs_to_camera = (inverse(view_matrix) * vec4(0.f, 0.f, 0.f, 1.f)).xyz - world_pos.xyz;
|
vec3 T = normalize(normal_matrix * vertex_tangent);
|
||||||
|
vec3 N = normalize(normal_matrix * vertex_normal);
|
||||||
|
T = normalize(T - dot(T, N) * N);
|
||||||
|
vec3 B = cross(N, T);
|
||||||
|
|
||||||
|
mat3 TBN = transpose(mat3(T, B, N));
|
||||||
|
vs_tangent_light_pos = TBN * u_light_position;
|
||||||
|
vs_tangent_view_pos = TBN * u_view_pos;
|
||||||
|
vs_tangent_frag_pos = TBN * vs_frag_pos;
|
||||||
}
|
}
|
|
@ -63,19 +63,19 @@ namespace simpleengine {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {
|
if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {
|
||||||
rotation.z += camera_speed * .3;
|
rotation.z += camera_speed * .4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) {
|
if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) {
|
||||||
rotation.z -= camera_speed * .3;
|
rotation.z -= camera_speed * .4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) {
|
if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) {
|
||||||
rotation.y -= camera_speed * .3;
|
rotation.y -= camera_speed * .4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) {
|
if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) {
|
||||||
rotation.y += camera_speed * .3;
|
rotation.y += camera_speed * .4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit the pitch of the camera.
|
// Limit the pitch of the camera.
|
||||||
|
@ -96,8 +96,9 @@ namespace simpleengine {
|
||||||
view_matrix = glm::lookAt(position, position + camera_front, camera_up);
|
view_matrix = glm::lookAt(position, position + camera_front, camera_up);
|
||||||
|
|
||||||
shader.use();
|
shader.use();
|
||||||
shader.set_uniform_matrix_4f("view_matrix", view_matrix, false);
|
shader.set_uniform_float_vec3("u_view_pos", position, false);
|
||||||
shader.set_uniform_matrix_4f("projection_matrix", projection_matrix, false);
|
shader.set_uniform_matrix_4f("u_view_matrix", view_matrix, false);
|
||||||
|
shader.set_uniform_matrix_4f("u_projection_matrix", projection_matrix, false);
|
||||||
shader.unuse();
|
shader.unuse();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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 {
|
void simpleengine::Game::enable_default_gl_options() const {
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
glCullFace(GL_BACK);
|
|
||||||
//glFrontFace(GL_CW);
|
//glFrontFace(GL_CW);
|
||||||
|
|
||||||
update_enabled_vsync();
|
update_enabled_vsync();
|
||||||
|
|
|
@ -1,23 +1,26 @@
|
||||||
#include "gfx/mesh.h"
|
#include "gfx/mesh.h"
|
||||||
|
#include "gfx/vbo.h"
|
||||||
|
#include "vector.h"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace simpleengine::gfx {
|
namespace simpleengine::gfx {
|
||||||
Mesh::Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, Material material) :
|
Mesh::Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, Material material) :
|
||||||
material(std::make_optional(material)), vertices(vertices), indicies(indicies),
|
material(std::make_optional(material)), vertices(vertices), indicies(indicies),
|
||||||
vbo(gfx::VBO::init(GL_ARRAY_BUFFER, false)), ebo(gfx::VBO::init(GL_ELEMENT_ARRAY_BUFFER, false)),
|
vbo(gfx::VBO::init(GL_ARRAY_BUFFER, false)), ebo(gfx::VBO::init(GL_ELEMENT_ARRAY_BUFFER, false)),
|
||||||
vao(gfx::VAO::init()) {
|
vao(gfx::VAO::init()), tangent_vbo(gfx::VBO::init(GL_ARRAY_BUFFER, false)) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh::Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, std::optional<Material> material) :
|
Mesh::Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, std::optional<Material> material) :
|
||||||
material(material), vertices(vertices), indicies(indicies),
|
material(material), vertices(vertices), indicies(indicies),
|
||||||
vbo(gfx::VBO::init(GL_ARRAY_BUFFER, false)), ebo(gfx::VBO::init(GL_ELEMENT_ARRAY_BUFFER, false)),
|
vbo(gfx::VBO::init(GL_ARRAY_BUFFER, false)), ebo(gfx::VBO::init(GL_ELEMENT_ARRAY_BUFFER, false)),
|
||||||
vao(gfx::VAO::init()) {
|
vao(gfx::VAO::init()), tangent_vbo(gfx::VBO::init(GL_ARRAY_BUFFER, false)) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh::Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, Material material, gfx::VBO ebo, gfx::VBO vbo, gfx::VAO vao) :
|
Mesh::Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, Material material, gfx::VBO ebo, gfx::VBO vbo, gfx::VAO vao,
|
||||||
vertices(vertices), indicies(indicies), material(material), ebo(ebo), vbo(vbo), vao(vao) {
|
gfx::VBO tangent_vbo) :
|
||||||
|
vertices(vertices), indicies(indicies), material(material), ebo(ebo), vbo(vbo), vao(vao), tangent_vbo(tangent_vbo) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,4 +79,40 @@ namespace simpleengine::gfx {
|
||||||
vertices[i].normal = normals[i];
|
vertices[i].normal = normals[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mesh::calculate_tangents() {
|
||||||
|
// Resize the tangents vector, they will overwritten,
|
||||||
|
// so no need to clear the vector.
|
||||||
|
tangents.resize(vertices.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < indicies.size(); i += 3) {
|
||||||
|
int index0 = indicies[i];
|
||||||
|
int index1 = indicies[i+1];
|
||||||
|
int index2 = indicies[i+2];
|
||||||
|
|
||||||
|
LitVertex& lit_vertex0 = vertices[index0];
|
||||||
|
LitVertex& lit_vertex1 = vertices[index1];
|
||||||
|
LitVertex& lit_vertex2 = vertices[index2];
|
||||||
|
|
||||||
|
glm::vec3 pos0 = lit_vertex0.position;
|
||||||
|
glm::vec3 pos1 = lit_vertex1.position;
|
||||||
|
glm::vec3 pos2 = lit_vertex2.position;
|
||||||
|
|
||||||
|
// Edges of the triangle : postion delta
|
||||||
|
glm::vec3 delta_pos1 = pos1 - pos0;
|
||||||
|
glm::vec3 delta_pos2 = pos2 - pos0;
|
||||||
|
|
||||||
|
// UV delta
|
||||||
|
glm::vec2 delta_uv1 = lit_vertex1.tex_coord - lit_vertex0.tex_coord;
|
||||||
|
glm::vec2 delta_uv2 = lit_vertex2.tex_coord - lit_vertex0.tex_coord;
|
||||||
|
|
||||||
|
float r = 1.0f / (delta_uv1.x * delta_uv2.y - delta_uv1.y * delta_uv2.x);
|
||||||
|
glm::vec3 tangent = (delta_pos1 * delta_uv2.y - delta_pos2 * delta_uv1.y)*r;
|
||||||
|
//glm::vec3 bitangent = (delta_pos2 * delta_uv1.x - delta_pos1 * delta_uv2.x)*r;
|
||||||
|
|
||||||
|
tangents[index0] = tangent;
|
||||||
|
tangents[index1] = tangent;
|
||||||
|
tangents[index2] = tangent;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
#include "gfx/model.h"
|
#include "gfx/model.h"
|
||||||
#include "gfx/material.h"
|
#include "gfx/material.h"
|
||||||
|
#include "gfx/rendering_type.h"
|
||||||
#include "gfx/texture.h"
|
#include "gfx/texture.h"
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
|
|
||||||
|
@ -10,6 +11,7 @@
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -32,6 +34,10 @@ namespace simpleengine::gfx {
|
||||||
void Model::load_model(std::string path) {
|
void Model::load_model(std::string path) {
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
|
|
||||||
|
if (model_processing_flags & ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE) {
|
||||||
|
additional_assimp_flags |= aiProcess_CalcTangentSpace;
|
||||||
|
}
|
||||||
|
|
||||||
// assimp post processing options: http://assimp.sourceforge.net/lib_html/postprocess_8h.html
|
// assimp post processing options: http://assimp.sourceforge.net/lib_html/postprocess_8h.html
|
||||||
const aiScene *scene = importer.ReadFile(path, additional_assimp_flags | aiProcess_Triangulate | aiProcess_FlipUVs);
|
const aiScene *scene = importer.ReadFile(path, additional_assimp_flags | aiProcess_Triangulate | aiProcess_FlipUVs);
|
||||||
|
|
||||||
|
@ -63,27 +69,33 @@ namespace simpleengine::gfx {
|
||||||
|
|
||||||
gfx::Mesh Model::process_mesh(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMesh* mesh, const aiScene* scene) {
|
gfx::Mesh Model::process_mesh(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMesh* mesh, const aiScene* scene) {
|
||||||
std::vector<LitVertex> vertices;
|
std::vector<LitVertex> vertices;
|
||||||
std::vector<unsigned int> indices;
|
std::vector<unsigned int> indicies;
|
||||||
|
std::vector<Vectorf> tangents;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
|
for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
|
||||||
LitVertex vertex;
|
LitVertex vertex;
|
||||||
vertex.color = glm::vec3(1.f);
|
vertex.color = glm::vec3(1.f);
|
||||||
vertex.texture_id = 0;
|
|
||||||
|
|
||||||
simpleengine::Vectorf position(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z);
|
simpleengine::Vectorf position(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z);
|
||||||
vertex.position = position;
|
vertex.position = position;
|
||||||
|
|
||||||
|
// Only process normals if they exist.
|
||||||
if (mesh->HasNormals()) {
|
if (mesh->HasNormals()) {
|
||||||
glm::vec3 normal(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z);
|
glm::vec3 normal(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z);
|
||||||
vertex.normal = normal;
|
vertex.normal = normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh->mTextureCoords[0]) {
|
// Only process texture coords if they exist.
|
||||||
|
if (mesh->HasTextureCoords(0)) {
|
||||||
glm::vec2 tex_coord(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y);
|
glm::vec2 tex_coord(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y);
|
||||||
|
|
||||||
vertex.tex_coord = tex_coord;
|
vertex.tex_coord = tex_coord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mesh->HasTangentsAndBitangents()) {
|
||||||
|
tangents.emplace_back(mesh->mTangents[i].x, mesh->mTangents[i].y, mesh->mTangents[i].z);
|
||||||
|
}
|
||||||
|
|
||||||
vertices.push_back(vertex);
|
vertices.push_back(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,15 +104,21 @@ namespace simpleengine::gfx {
|
||||||
aiFace face = mesh->mFaces[i];
|
aiFace face = mesh->mFaces[i];
|
||||||
|
|
||||||
for (int j = 0; j < face.mNumIndices; j++) {
|
for (int j = 0; j < face.mNumIndices; j++) {
|
||||||
indices.push_back(face.mIndices[j]);
|
indicies.push_back(face.mIndices[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.
|
// Create a default material and white texture.
|
||||||
auto white_texture = gfx::Texture::white_texture();
|
auto white_texture = gfx::Texture::white_texture();
|
||||||
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> default_textures;
|
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> default_textures;
|
||||||
default_textures.emplace(white_texture.type, std::vector<std::shared_ptr<Texture>>{ std::make_shared<Texture>(white_texture) });
|
default_textures.emplace(white_texture.type, std::vector<std::shared_ptr<Texture>>{ std::make_shared<Texture>(white_texture) });
|
||||||
gfx::Material mat(default_textures, 1.f, 0.f, 0.f, 0.f, 0.f);
|
gfx::Material mat(default_textures, rendering_type);
|
||||||
|
|
||||||
if (mesh->mMaterialIndex >= 0) {
|
if (mesh->mMaterialIndex >= 0) {
|
||||||
std::cout << "TODO: Process model materials!" << std::endl;
|
std::cout << "TODO: Process model materials!" << std::endl;
|
||||||
|
@ -109,14 +127,30 @@ namespace simpleengine::gfx {
|
||||||
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
|
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
|
||||||
|
|
||||||
// Load Diffuse texture maps
|
// Load Diffuse texture maps
|
||||||
std::vector<std::shared_ptr<Texture>> diffuse_maps = load_material_texture(processed_textures, material, aiTextureType_DIFFUSE);
|
aiTextureType loading_type = aiTextureType_DIFFUSE;
|
||||||
if (!diffuse_maps.empty()) textures.emplace(aiTextureType_DIFFUSE, diffuse_maps);
|
std::vector<std::shared_ptr<Texture>> 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<std::shared_ptr<Texture>> 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<std::shared_ptr<Texture>> normal_maps = load_material_texture(processed_textures, material, loading_type);
|
||||||
|
if (!normal_maps.empty()) {
|
||||||
|
textures.emplace(loading_type, normal_maps);
|
||||||
|
|
||||||
|
// Force calculation of tangent space.
|
||||||
|
model_processing_flags |= MdlProcFlag_CALCULATE_TANGENT_SPACE;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO Handle other types of texture maps
|
// TODO Handle other types of texture maps
|
||||||
|
|
||||||
if (!textures.empty()) {
|
if (!textures.empty()) {
|
||||||
// TODO: Find a way to let the user set the scalars.
|
// TODO: Find a way to let the user set the scalars.
|
||||||
mat = Material(textures, 1.f, 0.f, 0.f, 0.f, 0.f);
|
mat = Material(textures, rendering_type);
|
||||||
|
|
||||||
// Add `textures` into the `processed_textures` list.
|
// Add `textures` into the `processed_textures` list.
|
||||||
for (const auto& pair : textures) {
|
for (const auto& pair : textures) {
|
||||||
|
@ -144,12 +178,16 @@ namespace simpleengine::gfx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh se_mesh(vertices, indices, mat);
|
Mesh se_mesh(vertices, indicies, mat);
|
||||||
|
|
||||||
if (!mesh->HasNormals()) {
|
if (!mesh->HasNormals()) {
|
||||||
se_mesh.calculate_normals();
|
se_mesh.calculate_normals();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mesh->HasTangentsAndBitangents()) {
|
||||||
|
se_mesh.tangents = tangents;
|
||||||
|
}
|
||||||
|
|
||||||
return se_mesh;
|
return se_mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +223,7 @@ namespace simpleengine::gfx {
|
||||||
ss << model_directory << "/" << texture_path;
|
ss << model_directory << "/" << texture_path;
|
||||||
std::string full_path = ss.str();
|
std::string full_path = ss.str();
|
||||||
|
|
||||||
Texture texture(full_path.c_str(), type, /* TextureFlags::TexFlags_FLIP_VERTICALLY | */ TextureFlags::TexFlags_IMG_2D | TextureFlags::TexFlags_MIPMAP);
|
Texture texture(full_path.c_str(), type);
|
||||||
texture.path = texture_path;
|
texture.path = texture_path;
|
||||||
textures.emplace_back(std::make_shared<Texture>(texture));
|
textures.emplace_back(std::make_shared<Texture>(texture));
|
||||||
|
|
||||||
|
@ -210,4 +248,50 @@ namespace simpleengine::gfx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Model::calculate_tangents() {
|
||||||
|
for (auto& mesh : meshes) {
|
||||||
|
// TODO: Find a way to check if normals and UVs are set before calculating tangents
|
||||||
|
mesh.calculate_tangents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* std::vector<std::pair<simpleengine::Vectorf, simpleengine::Vectorf>> calculate_tangent_space(
|
||||||
|
std::vector<LitVertex> vertices, std::vector<unsigned int> indices) {
|
||||||
|
|
||||||
|
std::vector<std::pair<simpleengine::Vectorf, simpleengine::Vectorf>> tangents;
|
||||||
|
tangents.resize(vertices.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < indices.size(); i += 3) {
|
||||||
|
int index0 = indices[i];
|
||||||
|
int index1 = indices[i+1];
|
||||||
|
int index2 = indices[i+2];
|
||||||
|
|
||||||
|
LitVertex& lit_vertex0 = vertices[index0];
|
||||||
|
LitVertex& lit_vertex1 = vertices[index1];
|
||||||
|
LitVertex& lit_vertex2 = vertices[index2];
|
||||||
|
|
||||||
|
glm::vec3 pos0 = lit_vertex0.position;
|
||||||
|
glm::vec3 pos1 = lit_vertex1.position;
|
||||||
|
glm::vec3 pos2 = lit_vertex2.position;
|
||||||
|
|
||||||
|
// Edges of the triangle : postion delta
|
||||||
|
glm::vec3 delta_pos1 = pos1 - pos0;
|
||||||
|
glm::vec3 delta_pos2 = pos2 - pos0;
|
||||||
|
|
||||||
|
// UV delta
|
||||||
|
glm::vec2 delta_uv1 = lit_vertex1.tex_coord - lit_vertex0.tex_coord;
|
||||||
|
glm::vec2 delta_uv2 = lit_vertex2.tex_coord - lit_vertex0.tex_coord;
|
||||||
|
|
||||||
|
float r = 1.0f / (delta_uv1.x * delta_uv2.y - delta_uv1.y * delta_uv2.x);
|
||||||
|
glm::vec3 tangent = (delta_pos1 * delta_uv2.y - delta_pos2 * delta_uv1.y)*r;
|
||||||
|
glm::vec3 bitangent = (delta_pos2 * delta_uv1.x - delta_pos1 * delta_uv2.x)*r;
|
||||||
|
|
||||||
|
tangents[0] = {tangent, bitangent};
|
||||||
|
tangents[1] = {tangent, bitangent};
|
||||||
|
tangents[2] = {tangent, bitangent};
|
||||||
|
}
|
||||||
|
|
||||||
|
return tangents;
|
||||||
|
} */
|
||||||
} // namespace simpleengine::gfx
|
} // namespace simpleengine::gfx
|
|
@ -5,28 +5,31 @@
|
||||||
|
|
||||||
#include "ecs/component/mesh_component.h"
|
#include "ecs/component/mesh_component.h"
|
||||||
#include "ecs/component/model_component.h"
|
#include "ecs/component/model_component.h"
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <assimp/material.h>
|
#include <assimp/material.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <glm/geometric.hpp>
|
||||||
|
|
||||||
|
// TODO: Check if initialized before trying to do stuff
|
||||||
namespace simpleengine::gfx {
|
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, gfx::Shader shader, std::shared_ptr<Camera> camera)
|
||||||
|
: window(window), shader(shader), camera(camera)/* , transparent_render_queue(CameraDistanceComparator(camera)) */ {}
|
||||||
|
|
||||||
Renderer::Renderer(GLFWwindow* window, GLuint shader_program): Renderer(window,
|
Renderer::Renderer(GLFWwindow *window, GLuint shader_program, std::shared_ptr<Camera> camera)
|
||||||
gfx::Shader(shader_program)) {
|
: 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",
|
fprintf(stderr, "%s type = 0x%x, severity = 0x%x, message = %s\n",
|
||||||
(type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
|
(type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), type, severity, message);
|
||||||
type, severity, message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::enable_debug() {
|
void Renderer::enable_debug() {
|
||||||
|
@ -34,24 +37,49 @@ namespace simpleengine::gfx {
|
||||||
glDebugMessageCallback(debug_message_callback, 0);
|
glDebugMessageCallback(debug_message_callback, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::queue_job(RenderingJob job) {
|
void Renderer::sort_jobs() {
|
||||||
RenderingJob& emplace = rendering_queue.emplace(job);
|
// Sort transparents
|
||||||
create_job_buffers(emplace);
|
|
||||||
|
// std::sort()
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::create_job_buffers(RenderingJob& job) {
|
void Renderer::queue_job(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 position) {
|
||||||
Mesh& rendering_mesh = job.rendering_mesh;
|
RenderingJob job(rendering_type, mesh, position);
|
||||||
|
|
||||||
if (!rendering_mesh.are_buffers_created) {
|
this->queue_job(job);
|
||||||
gfx::VBO& vbo = rendering_mesh.vbo;
|
}
|
||||||
gfx::VBO& ebo = rendering_mesh.ebo;
|
|
||||||
gfx::VAO& vao = rendering_mesh.vao;
|
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();
|
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()) {
|
if (!rendering_mesh->indicies.empty()) {
|
||||||
ebo.buffer(rendering_mesh.indicies.data(), 0, rendering_mesh.indicies.size() * sizeof(GLuint));
|
ebo.buffer(rendering_mesh->indicies.data(), 0, rendering_mesh->indicies.size() * sizeof(GLuint));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable VAO attributes
|
// Enable VAO attributes
|
||||||
|
@ -59,22 +87,30 @@ namespace simpleengine::gfx {
|
||||||
vao.enable_attrib(vbo, 1, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, color), false);
|
vao.enable_attrib(vbo, 1, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, color), false);
|
||||||
vao.enable_attrib(vbo, 2, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, normal), false);
|
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);
|
vao.enable_attrib(vbo, 3, 2, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, tex_coord), false);
|
||||||
vao.enable_attrib(vbo, 4, 1, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, texture_id), false);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
rendering_mesh->tangent_vbo.buffer(rendering_mesh->tangents.data(), 0,
|
||||||
glBindVertexArray(0);
|
rendering_mesh->tangents.size() * sizeof(Vectorf));
|
||||||
|
vao.enable_attrib(rendering_mesh->tangent_vbo, 4, 3, GL_FLOAT, sizeof(Vectorf), 0, false);
|
||||||
|
|
||||||
rendering_mesh.are_buffers_created = true;
|
vbo.unbind();
|
||||||
|
vao.unbind();
|
||||||
|
|
||||||
|
rendering_mesh->are_buffers_created = true;
|
||||||
|
|
||||||
std::cout << "Created render job buffers" << std::endl;
|
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() {
|
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;
|
std::cout << "Base Renderer initialized" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,48 +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> &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<RenderingJob> &rendering_queue) {
|
||||||
shader.use();
|
shader.use();
|
||||||
|
|
||||||
while (!rendering_queue.empty()) {
|
while (!rendering_queue.empty()) {
|
||||||
// Get the job from the queue, we'll remove it after we render.
|
// Get the job from the queue, we'll remove it after we render.
|
||||||
RenderingJob& job = rendering_queue.front();
|
RenderingJob &job = rendering_queue.front();
|
||||||
Mesh& mesh = job.rendering_mesh;
|
|
||||||
|
|
||||||
shader.set_uniform_matrix_4f("transform_matrix", job.transform_mat, false);
|
bool res = this->render_job(job);
|
||||||
|
|
||||||
std::optional<Material>& material = mesh.material;
|
if (res) {
|
||||||
|
// Now we'll remove the job from the queue.
|
||||||
shader.set_uniform_int("u_textures", 0, false);
|
rendering_queue.pop();
|
||||||
|
|
||||||
if (material.has_value()) {
|
|
||||||
shader.set_uniform_float("u_texture_shine", material->shine, false);
|
|
||||||
shader.set_uniform_float("u_texture_reflectivity", material->reflectivity, false);
|
|
||||||
|
|
||||||
int texture_count = 0;
|
|
||||||
auto diffuse_maps = material->textures.find(aiTextureType_DIFFUSE);
|
|
||||||
for (const auto& texture : diffuse_maps->second) {
|
|
||||||
// We can only bind to 16 textures at a time (indexes are 0-15)
|
|
||||||
if (texture_count >= 16) break;
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + texture_count);
|
|
||||||
glBindTextureUnit(texture_count, texture->get_texture_id());
|
|
||||||
|
|
||||||
texture_count++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
shader.unuse();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
void Renderer::render_job_queue(std::map<float, RenderingJob, std::greater<>>& 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<float, RenderingJob, std::greater<>> 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
|
|
@ -1,4 +1,5 @@
|
||||||
#include "gfx/texture.h"
|
#include "gfx/texture.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
|
@ -23,8 +24,7 @@ namespace simpleengine::gfx {
|
||||||
|
|
||||||
stbi_set_flip_vertically_on_load(flip_vertically);
|
stbi_set_flip_vertically_on_load(flip_vertically);
|
||||||
|
|
||||||
// Read 4 channels (RGBA)
|
unsigned char*img_data = stbi_load(path, &width, &height, &channels, 0);
|
||||||
img_data = stbi_load(path, &width, &height, &channels, 4);
|
|
||||||
if(!img_data) {
|
if(!img_data) {
|
||||||
const char* failure = stbi_failure_reason();
|
const char* failure = stbi_failure_reason();
|
||||||
std::cerr << "Failed to load texture! (" << failure << ")" << std::endl;
|
std::cerr << "Failed to load texture! (" << failure << ")" << std::endl;
|
||||||
|
@ -32,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;
|
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_RGBA, width, height, 0, GL_RGBA, 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) {
|
if (mipmap) {
|
||||||
glGenerateMipmap(image_type_gl);
|
glGenerateMipmap(image_type_gl);
|
||||||
}
|
}
|
||||||
|
|
||||||
stbi_set_flip_vertically_on_load(false);
|
stbi_set_flip_vertically_on_load(false);
|
||||||
|
stbi_image_free(img_data);
|
||||||
|
|
||||||
unbind();
|
unbind();
|
||||||
}
|
}
|
||||||
|
@ -62,8 +76,7 @@ namespace simpleengine::gfx {
|
||||||
|
|
||||||
stbi_set_flip_vertically_on_load(flip_vertically);
|
stbi_set_flip_vertically_on_load(flip_vertically);
|
||||||
|
|
||||||
// Read 4 channels (RGBA)
|
unsigned char* img_data = stbi_load_from_memory(buffer, buffer_length, &width, &height, &channels, 0);
|
||||||
img_data = stbi_load_from_memory(buffer, buffer_length, &width, &height, &channels, 4);
|
|
||||||
if(!img_data) {
|
if(!img_data) {
|
||||||
const char* failure = stbi_failure_reason();
|
const char* failure = stbi_failure_reason();
|
||||||
std::cerr << "Failed to load texture! (" << failure << ")" << std::endl;
|
std::cerr << "Failed to load texture! (" << failure << ")" << std::endl;
|
||||||
|
@ -71,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;
|
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_RGBA, width, height, 0, GL_RGBA, 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) {
|
if (mipmap) {
|
||||||
glGenerateMipmap(image_type_gl);
|
glGenerateMipmap(image_type_gl);
|
||||||
}
|
}
|
||||||
|
|
||||||
stbi_set_flip_vertically_on_load(false);
|
stbi_set_flip_vertically_on_load(false);
|
||||||
|
stbi_image_free(img_data);
|
||||||
|
|
||||||
unbind();
|
unbind();
|
||||||
}
|
}
|
||||||
|
@ -103,7 +130,6 @@ namespace simpleengine::gfx {
|
||||||
texture.height = height;
|
texture.height = height;
|
||||||
texture.channels = 4;
|
texture.channels = 4;
|
||||||
texture.type = aiTextureType::aiTextureType_DIFFUSE;
|
texture.type = aiTextureType::aiTextureType_DIFFUSE;
|
||||||
texture.img_data = data;
|
|
||||||
|
|
||||||
glGenTextures(1, &texture.texture_id);
|
glGenTextures(1, &texture.texture_id);
|
||||||
texture.bind();
|
texture.bind();
|
||||||
|
@ -113,11 +139,11 @@ namespace simpleengine::gfx {
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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();
|
texture.unbind();
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,22 @@ namespace simpleengine {
|
||||||
// Is there a way these can be grouped?
|
// Is there a way these can be grouped?
|
||||||
registry.view<const TransformComponent, ModelComponent>().each([this](const TransformComponent& transform, ModelComponent& model_component) {
|
registry.view<const TransformComponent, ModelComponent>().each([this](const TransformComponent& transform, ModelComponent& model_component) {
|
||||||
for (auto& mesh : model_component.model.meshes) {
|
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<const TransformComponent, MeshComponent>().each([this](const TransformComponent& transform, MeshComponent& mesh_component) {
|
registry.view<const TransformComponent, MeshComponent>().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<TransformComponent, RotatingComponent>().each([this, &delta_time](TransformComponent& transform, RotatingComponent& rotating) {
|
registry.view<TransformComponent, RotatingComponent>().each([this, &delta_time](TransformComponent& transform, RotatingComponent& rotating) {
|
||||||
|
|
Loading…
Reference in New Issue