diff --git a/.gitignore b/.gitignore index 834cb7f..fda8550 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,5 @@ .fips-settings.yml *.pyc *.ktx +tests/07-gltf/assets/Buggy.gltf +tests/07-gltf/assets/Buggy0.bin diff --git a/README.md b/README.md index 65c3cdf..be73c58 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,13 @@ done! it's ready to rock. # Changes +## Ariyana Game Engine 0.4 + +- Implement material system +- Phong lighting +- Directional light and omni light +- Fix some bugs + ## Ariyana Game Engine 0.3 - Adding gltf mesh loader diff --git a/src/3d/FrameData.hpp b/src/3d/FrameData.hpp index 870c530..5b8db6a 100644 --- a/src/3d/FrameData.hpp +++ b/src/3d/FrameData.hpp @@ -2,6 +2,7 @@ #include #include #include "core/containers/Array.hpp" +#include "sx/math.h" namespace ari::en { @@ -13,6 +14,7 @@ namespace ari::en core::Array Nodes; uint32_t FrameNumber = 0; Camera* CameraObj; + sx_vec3 CameraPos; int FrameDataTurnIndex = 0; }; // FrameData diff --git a/src/3d/MeshNode.cpp b/src/3d/MeshNode.cpp index 0abc865..48ab45c 100644 --- a/src/3d/MeshNode.cpp +++ b/src/3d/MeshNode.cpp @@ -9,7 +9,7 @@ namespace ari::en { if (Mesh.IsValid()) { - sx_mat4 mvp = gfx::GetViewProjMatrix() * _finalMat[_frameTurnIndex]; + gfx::SetWorldMatrix(_finalMat[_frameTurnIndex]); auto mesh = core::ObjectPool::GetByIndex(Mesh.Index); for (auto sub_mesh_hdl: mesh->SubMeshes) @@ -17,9 +17,9 @@ namespace ari::en if (sub_mesh_hdl.IsValid()) { const auto sub_mesh = core::ObjectPool::GetByIndex(sub_mesh_hdl.Index); - gfx::ApplyPipeline(sub_mesh->Pipeline); + gfx::SetMaterialShader(sub_mesh->Material); + gfx::ApplyPipelineAndMaterial(sub_mesh->Pipeline, &sub_mesh->Material); gfx::ApplyBindings(sub_mesh->Binding); - ApplyUniforms(gfx::ShaderStage::VertexShader, 0, &mvp, sizeof(sx_mat4)); gfx::Draw(0, sub_mesh->ElementsCount, 1); } } diff --git a/src/3d/RenderSystem.cpp b/src/3d/RenderSystem.cpp index 14d40fa..64cad32 100644 --- a/src/3d/RenderSystem.cpp +++ b/src/3d/RenderSystem.cpp @@ -40,6 +40,7 @@ namespace ari::en // TODO: Set viewport gfx::Viewport* pViewport = m_pFrameDataCurrent->CameraObj->GetViewport(); gfx::SetViewProjMatrix(m_pFrameDataCurrent->CameraObj->_view, m_pFrameDataCurrent->CameraObj->_proj); + gfx::SetCameraPosition(m_pFrameDataCurrent->CameraPos); } for (auto node : m_pFrameDataCurrent->Nodes) { diff --git a/src/3d/SceneSystem.cpp b/src/3d/SceneSystem.cpp index 9879a0e..b5c39be 100644 --- a/src/3d/SceneSystem.cpp +++ b/src/3d/SceneSystem.cpp @@ -35,6 +35,7 @@ namespace ari::en m_pFrameDataTransforms = &m_aFrameData[m_FameDataTurnIndex]; m_pFrameDataTransforms->FrameNumber = gfx::GetFrameNumber(); m_pFrameDataTransforms->CameraObj = m_pActiveCamera; + m_pFrameDataTransforms->CameraPos = m_pActiveCamera->Position; m_pFrameDataTransforms->Nodes.Clear(); // Get all entities and calc transforms @@ -57,7 +58,7 @@ namespace ari::en rect = io::GetWindowSize(TargetWindow); } m_pActiveCamera->_proj = sx_mat4_perspectiveFOV(sx_torad(m_pActiveCamera->Fov), - float(rect.width) / float(rect.height), m_pActiveCamera->zNear, m_pActiveCamera->zFar, true); + float(rect.width) / float(rect.height), m_pActiveCamera->zNear, m_pActiveCamera->zFar, true); } m_FameDataTurnIndex++; @@ -99,7 +100,7 @@ namespace ari::en } } - void SceneSystem::CalcTransform(Node3D* node, sx_mat4* parentMat) + void SceneSystem::CalcTransform(Node3D* node, Node3D* parent) { sx_mat4 m; if (node->has_mat) @@ -112,22 +113,26 @@ namespace ari::en node->Rotation.x, node->Rotation.y, node->Rotation.z, node->Position.x, node->Position.y, node->Position.z); } - if (parentMat) - node->_finalMat[m_FameDataTurnIndex] = m * (*parentMat); + if (parent) + { + node->_finalMat[m_FameDataTurnIndex] = parent->_finalMat[m_FameDataTurnIndex] * m; + } else + { node->_finalMat[m_FameDataTurnIndex] = m; - parentMat = &node->_finalMat[m_FameDataTurnIndex]; + } + parent = node; if (node->_isRenderable) { // Add it to frame data m_pFrameDataTransforms->Nodes.Add(node); } - node->GetChildren([parentMat, this](Node* n) + node->GetChildren([parent, this](Node* n) { if (n->GetBaseId() == Node3D::Id) { - CalcTransform(reinterpret_cast(n), parentMat); + CalcTransform(reinterpret_cast(n), parent); } }); } // CalcTransform diff --git a/src/3d/SceneSystem.hpp b/src/3d/SceneSystem.hpp index 8c8900b..ef27245 100644 --- a/src/3d/SceneSystem.hpp +++ b/src/3d/SceneSystem.hpp @@ -45,7 +45,7 @@ namespace ari::en * m_pFrameDataTransforms, // This is the transform calculated nodes * m_pFrameDataVisible; // This is the visible nodes that must be rendered. - void CalcTransform(Node3D* node, sx_mat4* parentMat); + void CalcTransform(Node3D* node, Node3D* parent); }; // SceneSystem diff --git a/src/3d/private/gltf.cpp b/src/3d/private/gltf.cpp index 6f673a4..5dc7181 100644 --- a/src/3d/private/gltf.cpp +++ b/src/3d/private/gltf.cpp @@ -65,6 +65,21 @@ namespace ari::en core::String BasePath; }; + core::Array> g_aGltfPipelines; + + gfx::PipelineHandle GetPipelineHandle(const gfx::PipelineSetup& setup) + { + for (auto& pair: g_aGltfPipelines) + { + const auto& p = pair.Key(); + if (p == setup) + return pair.Value(); + } + const auto pipe = gfx::CreatePipeline(setup); + g_aGltfPipelines.Add({ setup, pipe }); + return pipe; + } + void SetPipelineAttribute(gfx::VertexAttrSetup& attr, cgltf_attribute* gltf_attr) { switch (gltf_attr->data->component_type) @@ -330,8 +345,8 @@ namespace ari::en // parse the meshes - core::ObjectPool::Setup(64); - core::ObjectPool::Setup(128); + core::ObjectPool::Setup(512); + core::ObjectPool::Setup(512); p_scene_data->NumMeshes = int(gltf->meshes_count); p_scene_data->Meshes.Reserve(p_scene_data->NumMeshes); for (int i = 0; i < p_scene_data->NumMeshes; i++) @@ -355,18 +370,23 @@ namespace ari::en gfx::Bindings bindings; // Set the textures - if (gltf_prim->material - && gltf_prim->material->has_pbr_metallic_roughness - && gltf_prim->material->pbr_metallic_roughness.base_color_texture.texture) + if (gltf_prim->material) { - int tex_index = gltf_prim->material->pbr_metallic_roughness.base_color_texture.texture - gltf->textures; - bindings.fsTextures[0] = p_scene_data->Textures[tex_index]; - pipeline_setup.shader = gfx::GetShader(gfx::ShaderType::BasicTexture); - } - else - { - pipeline_setup.shader = gfx::GetShader(gfx::ShaderType::Basic); + if (gltf_prim->material->has_pbr_metallic_roughness) + { + if (gltf_prim->material->pbr_metallic_roughness.base_color_texture.texture) + { + int tex_index = gltf_prim->material->pbr_metallic_roughness.base_color_texture.texture - gltf->textures; + bindings.fsTextures[0] = p_scene_data->Textures[tex_index]; + } + core::Memory::Copy(gltf_prim->material->pbr_metallic_roughness.base_color_factor, sub_mesh->Material.BaseColor.f, 16); + } + else if(gltf_prim->material->has_pbr_specular_glossiness) + { + core::Memory::Copy(gltf_prim->material->pbr_specular_glossiness.diffuse_factor, sub_mesh->Material.BaseColor.f, 16); + } } + pipeline_setup.shader = gfx::GetShader(gfx::ShaderType::Basic); sub_mesh->Type = gfx::PrimitiveType(int(gltf_prim->type)); if (gltf_prim->indices) @@ -374,6 +394,7 @@ namespace ari::en // Add indices const int accessor_index = int(gltf_prim->indices - gltf->accessors); sub_mesh->IndexBuffer = p_scene_data->Accessors[accessor_index].GfxBuffer; + bindings.indexBufferOffset = p_scene_data->Accessors[accessor_index].Offset; sub_mesh->ElementsCount = int(gltf_prim->indices->count); pipeline_setup.index_type = gfx::IndexType::Uint16; bindings.indexBuffer = sub_mesh->IndexBuffer; @@ -394,7 +415,6 @@ namespace ari::en case cgltf_attribute_type_position: sub_mesh->Position = accessor->GfxBuffer; buffer_index = 0; - // TODO: add bounding box if (accessor->HasMax) { sub_mesh->AABB.xmax = accessor->Max[0]; @@ -407,12 +427,15 @@ namespace ari::en break; case cgltf_attribute_type_texcoord: sub_mesh->Texcoord = accessor->GfxBuffer; + if (sub_mesh->Material.HasVertexColor) + continue; buffer_index = 1; + sub_mesh->Material.HasTexcoord = true; break; case cgltf_attribute_type_normal: - continue; sub_mesh->Normal = accessor->GfxBuffer; buffer_index = 2; + sub_mesh->Material.HasNormal = true; break; case cgltf_attribute_type_tangent: sub_mesh->Tangent = accessor->GfxBuffer; @@ -420,8 +443,10 @@ namespace ari::en break; case cgltf_attribute_type_color: sub_mesh->Color = p_scene_data->Accessors[accessor_index].GfxBuffer; - buffer_index = 2; + buffer_index = 1; pipeline_setup.shader = gfx::GetShader(gfx::ShaderType::BasicVertexColor); + sub_mesh->Material.HasVertexColor = true; + sub_mesh->Material.HasTexcoord = false; break; case cgltf_attribute_type_joints: sub_mesh->Joints = p_scene_data->Accessors[accessor_index].GfxBuffer; @@ -442,8 +467,18 @@ namespace ari::en bindings.vertexBufferOffsets[buffer_index] = accessor->Offset; } } - - sub_mesh->Pipeline = gfx::CreatePipeline(pipeline_setup); + if (!sub_mesh->Material.HasTexcoord && !sub_mesh->Material.HasVertexColor && sub_mesh->Material.HasNormal) + { + // set the normal to stage 1 + pipeline_setup.layout.attrs[1] = pipeline_setup.layout.attrs[2]; + pipeline_setup.layout.attrs[1].bufferIndex = 1; + pipeline_setup.layout.attrs[2] = pipeline_setup.layout.attrs[7]; + bindings.vertexBufferOffsets[1] = bindings.vertexBufferOffsets[2]; + bindings.vertexBuffers[1] = bindings.vertexBuffers[2]; + bindings.vertexBufferOffsets[2] = bindings.vertexBufferOffsets[7]; + bindings.vertexBuffers[2] = bindings.vertexBuffers[7]; + } + sub_mesh->Pipeline = GetPipelineHandle(pipeline_setup); sub_mesh->Binding = gfx::CreateBinding(bindings); } } diff --git a/src/core/containers/Array.hpp b/src/core/containers/Array.hpp index 0ca2bea..5adbaa0 100644 --- a/src/core/containers/Array.hpp +++ b/src/core/containers/Array.hpp @@ -63,6 +63,8 @@ class Array /// increase capacity to hold at least numElements more elements void Reserve(int numElements); + /// fill the array with dummy data + void FillDumyData(); /// trim capacity to size (this involves a re-alloc) void Trim(); /// clear the array (deletes elements, keeps capacity) @@ -322,6 +324,12 @@ void Array::Reserve(int numElements) } } +template +inline void Array::FillDumyData() +{ + this->buffer.end = this->buffer.cap; +} + //------------------------------------------------------------------------------ template void Array::Trim() diff --git a/src/en/World.hpp b/src/en/World.hpp index a3b0d68..27a50f0 100644 --- a/src/en/World.hpp +++ b/src/en/World.hpp @@ -183,7 +183,7 @@ namespace ari::en template ComponentHandle World::CreateComponent() { - core::MemoryPool::Setup(102400); + core::MemoryPool::Setup(302400); uint32_t i; const uint32_t h = core::HandleManager::GetNewHandle(i); diff --git a/src/gfx/CMakeLists.txt b/src/gfx/CMakeLists.txt index 42a9868..8139fbc 100644 --- a/src/gfx/CMakeLists.txt +++ b/src/gfx/CMakeLists.txt @@ -4,6 +4,9 @@ fips_begin_module(ari_gfx) fips_files( Application.hpp gfx.hpp gfx.cpp + Material.hpp + MaterialInstance.hpp + MaterialParams.hpp Mesh.hpp SubMesh.hpp Vertices.hpp @@ -31,6 +34,8 @@ fips_begin_module(ari_gfx) fips_libs(GLESv3 EGL android log) endif() + fips_dir(shaders) + sokol_shader(mesh.glsl ${slang}) fips_dir(shaders/basic) sokol_shader(basic.glsl ${slang}) diff --git a/src/gfx/Material.hpp b/src/gfx/Material.hpp new file mode 100644 index 0000000..c468499 --- /dev/null +++ b/src/gfx/Material.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "gfx.hpp" +#include "core/string/StringAtom.hpp" + +namespace ari::gfx +{ + struct MaterialUniformInfo + { + core::StringAtom Name; + int Size; + int Offset; + ShaderStage Stage; + bool SystemData; //! This uniform is filled by engine or can be set by user + }; + + //! The material base class. This class dose not store the uniform params. They are in MaterialInstance + struct Material + { + bool HasTexcoord = false; + bool HasVertexColor = false; + bool HasNormal = false; + + // User controlled values + float SpecularStrength = 1.0f; + sx_vec4 BaseColor = sx_vec4f(1.f, 1.f, 1.f, 1.f); + + sg_shader_desc* shader_desc = nullptr; + ShaderHandle shader; + const core::Array* Uniforms; + int VS_UniformSize; + int FS_UniformSize; + core::Array Vs_UniformData; + core::Array Fs_UniformData; + }; + +} // namespace ari::gfx diff --git a/src/gfx/MaterialInstance.hpp b/src/gfx/MaterialInstance.hpp new file mode 100644 index 0000000..037412f --- /dev/null +++ b/src/gfx/MaterialInstance.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace ari::gfx +{ + struct MaterialInstance + { + // Ambient color + // Diffuse color + // Specular color + // Textures + // Parent Material + }; + +} // namespace ari::gfx diff --git a/src/gfx/MaterialParams.hpp b/src/gfx/MaterialParams.hpp new file mode 100644 index 0000000..9022d85 --- /dev/null +++ b/src/gfx/MaterialParams.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace ari::gfx +{ + struct MaterialParams + { + + }; + +} // namespace ari::gfx diff --git a/src/gfx/SubMesh.hpp b/src/gfx/SubMesh.hpp index 23c22e7..30fb0e7 100644 --- a/src/gfx/SubMesh.hpp +++ b/src/gfx/SubMesh.hpp @@ -3,6 +3,7 @@ #include "core/containers/Array.hpp" #include "gfx.hpp" #include "core/defines.hpp" +#include "gfx/Material.hpp" namespace ari::gfx { @@ -22,6 +23,7 @@ namespace ari::gfx int ElementsCount; gfx::PipelineHandle Pipeline; gfx::BindingHandle Binding; + gfx::Material Material; sx_aabb AABB = {{SX_FLOAT_MAX, SX_FLOAT_MAX, SX_FLOAT_MAX, -SX_FLOAT_MAX, -SX_FLOAT_MAX, -SX_FLOAT_MAX}}; }; diff --git a/src/gfx/gfx.cpp b/src/gfx/gfx.cpp index 3cf5fb0..b2647f0 100644 --- a/src/gfx/gfx.cpp +++ b/src/gfx/gfx.cpp @@ -5,28 +5,178 @@ #include "private/tinyktx.h" #include "core/log.h" #include "core/string/StringBuilder.hpp" +#include "sx/hash.h" +#include "Material.hpp" // Include shaders #include "basic.glsl.h" +#include "mesh.glsl.h" namespace ari { - namespace gfx - { + namespace gfx + { + // Shader uniform names string atoms + core::StringAtom str_uni_mvp = "mvp", + str_uni_matWorld = "matWorld", + str_uni_baseColor = "baseColor", + str_uni_camPos = "camPos", + str_uni_specularStrength = "specularStrength", + str_uni_lightDir = "lightDir", + str_uni_lightColor = "lightColor", + str_uni_lightPos = "lightPos"; + + // struct + struct ShaderDescShaderHandle + { + const sg_shader_desc* desc = nullptr; + ShaderHandle shader; + uint32_t hash; + core::Array Uniforms; + int VS_UniformSize; + int FS_UniformSize; + + void Setup(core::StringBuilder name) + { + hash = sx_hash_xxh32(name.AsCStr(), name.Length(), 0); + Uniforms.Clear(); + + // Prepare uniform data + VS_UniformSize = desc->vs.uniform_blocks[0].size; + FS_UniformSize = desc->fs.uniform_blocks[0].size; + int vs_offset = 0; + int fs_offset = 0; + if (name.Contains("mesh_")) + { + Uniforms.Add({ str_uni_mvp, 16, 0, ShaderStage::VertexShader, true }); + vs_offset = 16; + Uniforms.Add({ str_uni_baseColor, 4, 0, ShaderStage::FragmentShader, false }); + fs_offset = 4; + int index = 5; + while (name.Length() > index) + { + switch (name.At(index)) + { + case 'T': + // nothing to do + break; + case 'V': + if (name.Length() > index && name.At(index + 1) == 'C') + index++; + break; + case 'N': // Normal + Uniforms.Add({ str_uni_matWorld, 16, vs_offset, ShaderStage::VertexShader, true }); + vs_offset += 16; + Uniforms.Add({ str_uni_camPos, 3, fs_offset, ShaderStage::FragmentShader, true }); + Uniforms.Add({ str_uni_specularStrength, 1, fs_offset + 3, ShaderStage::FragmentShader, false }); + fs_offset += 4; + break; + case 'D': // Dir light + Uniforms.Add({ str_uni_lightDir, 3, fs_offset, ShaderStage::FragmentShader, true }); + Uniforms.Add({ str_uni_lightColor, 3, fs_offset + 4, ShaderStage::FragmentShader, true }); + fs_offset += 8; + break; + case 'P': // Point light + Uniforms.Add({ str_uni_lightPos, 3, fs_offset, ShaderStage::FragmentShader, true }); + Uniforms.Add({ str_uni_lightColor, 3, fs_offset + 4, ShaderStage::FragmentShader, true }); + fs_offset += 8; + break; + default: + log_warn("Unknown shader stage %s", name.At(index)); + } + index++; + } + } + } + }; + core::Array g_binds_array; + core::Map MaterialShaders; - static sx_mat4 g_mView, g_mProj, g_mViewProj; + static sx_mat4 g_mView, g_mProj, g_mViewProj, g_mWorld, g_mWorldViewProj; + static sx_vec3 g_vLightDir, g_vLightPos, g_vCamPos; + static sx_vec4 g_cLightColor; + static bool g_bHasDirLight = false, g_bHasOmniLight = false; - ShaderHanlde g_shaders[int(ShaderType::Count)]; + ShaderHandle g_shaders[int(ShaderType::Count)]; void SetupShaders() { g_shaders[int(ShaderType::Basic)] = CreateShader(ari_basic_shader_desc()); g_shaders[int(ShaderType::BasicTexture)] = CreateShader(ari_basic_tex_shader_desc()); g_shaders[int(ShaderType::BasicVertexColor)] = CreateShader(ari_basic_vertex_color_shader_desc()); + + // Init material shaders + ShaderDescShaderHandle sh; + sh.desc = ari_mesh__shader_desc(); + sh.Setup("mesh_"); + MaterialShaders.Add(sh.hash, sh); + sh.desc = ari_mesh_T_shader_desc(); + sh.Setup("mesh_T"); + MaterialShaders.Add(sh.hash, sh); + sh.desc = ari_mesh_VC_shader_desc(); + sh.Setup("mesh_VC"); + MaterialShaders.Add(sh.hash, sh); + sh.desc = ari_mesh_TND_shader_desc(); + sh.Setup("mesh_TND"); + MaterialShaders.Add(sh.hash, sh); + sh.desc = ari_mesh_TNP_shader_desc(); + sh.Setup("mesh_TNP"); + MaterialShaders.Add(sh.hash, sh); + sh.desc = ari_mesh_VCND_shader_desc(); + sh.Setup("mesh_VCND"); + MaterialShaders.Add(sh.hash, sh); + sh.desc = ari_mesh_VCNP_shader_desc(); + sh.Setup("mesh_VCNP"); + MaterialShaders.Add(sh.hash, sh); + sh.desc = ari_mesh_ND_shader_desc(); + sh.Setup("mesh_ND"); + MaterialShaders.Add(sh.hash, sh); + sh.desc = ari_mesh_NP_shader_desc(); + sh.Setup("mesh_NP"); + MaterialShaders.Add(sh.hash, sh); + } + + void SetMaterialShader(Material& material) + { + static core::StringBuilder str; + str.Set("mesh_"); + if (material.HasTexcoord) + str.Append("T"); + if (material.HasVertexColor) + str.Append("VC"); + if (material.HasNormal && (g_bHasDirLight || g_bHasOmniLight)) + { + str.Append("N"); + if (g_bHasDirLight) + str.Append("D"); + if (g_bHasOmniLight) + str.Append("P"); + } + uint32_t hash = sx_hash_xxh32(str.AsCStr(), str.Length(), 0); + if (MaterialShaders.Contains(hash)) + { + ShaderDescShaderHandle& mat = MaterialShaders[hash]; + if (!mat.shader.IsValid()) + mat.shader = CreateShader(mat.desc); + if (material.shader.Handle == mat.shader.Handle) + return; + material.shader = mat.shader; + material.FS_UniformSize = mat.FS_UniformSize; + material.VS_UniformSize = mat.VS_UniformSize; + material.Uniforms = &mat.Uniforms; + material.Fs_UniformData.Reserve(material.FS_UniformSize - material.Fs_UniformData.Size()); + material.Fs_UniformData.FillDumyData(); + material.Vs_UniformData.Reserve(material.VS_UniformSize - material.Vs_UniformData.Size()); + material.Vs_UniformData.FillDumyData(); + } + else + { + log_error("Shader for material %s not found.", str.AsCStr()); + } } - ShaderHanlde GetShader(ShaderType shader) + ShaderHandle GetShader(ShaderType shader) { return g_shaders[int(shader)]; } @@ -65,17 +215,17 @@ namespace ari } //------------------------------------------------------------------------------ - ShaderHanlde CreateShader(const sg_shader_desc* desc) + ShaderHandle CreateShader(const sg_shader_desc* desc) { const sg_shader shader = sg_make_shader(desc); - return { core::HandleManager::CreateHandleByIndex(shader.id), shader.id }; + return { core::HandleManager::CreateHandleByIndex(shader.id), shader.id }; } //------------------------------------------------------------------------------ - void DestroyShader(ShaderHanlde& shader) + void DestroyShader(ShaderHandle& shader) { sg_destroy_shader({ shader.Index }); - core::HandleManager::RemoveHandle(shader.Handle); + core::HandleManager::RemoveHandle(shader.Handle); shader.Handle = shader.Index = core::aInvalidHandle; } @@ -120,6 +270,73 @@ namespace ari sg_apply_pipeline({ pipeline.Index }); } + void SetUniformData(const MaterialUniformInfo& ui, Material* material, float* data) + { + if (ui.Stage == ShaderStage::VertexShader) + { + core::Memory::Copy(data, &material->Vs_UniformData[ui.Offset], ui.Size * 4); + } + else + { + core::Memory::Copy(data, &material->Fs_UniformData[ui.Offset], ui.Size * 4); + } + } + + //------------------------------------------------------------------------------ + void SetMaterialUniforms(Material* material) + { + for(int i = 0; i < material->Uniforms->Size(); i++) + { + const auto& ui = material->Uniforms->operator[](i); + if (ui.Name == str_uni_mvp) + { + SetUniformData(ui, material, g_mWorldViewProj.f); + } + else if (ui.Name == str_uni_matWorld) + { + SetUniformData(ui, material, g_mWorld.f); + } + else if (ui.Name == str_uni_baseColor) + { + SetUniformData(ui, material, material->BaseColor.f); + } + else if (ui.Name == str_uni_camPos) + { + SetUniformData(ui, material, g_vCamPos.f); + } + else if (ui.Name == str_uni_lightDir) + { + SetUniformData(ui, material, g_vLightDir.f); + } + else if (ui.Name == str_uni_lightPos) + { + SetUniformData(ui, material, g_vLightPos.f); + } + else if (ui.Name == str_uni_lightColor) + { + SetUniformData(ui, material, g_cLightColor.f); + } + else if (ui.Name == str_uni_specularStrength) + { + SetUniformData(ui, material, &material->SpecularStrength); + } + } + + } + + //------------------------------------------------------------------------------ + void ApplyPipelineAndMaterial(const PipelineHandle& pipeline, Material* material) + { + // update engine uniforms data + SetMaterialUniforms(material); + + SetPipelineShader(pipeline, material->shader); + ApplyPipeline(pipeline); + ApplyUniforms(ShaderStage::VertexShader, 0, &material->Vs_UniformData.Front(), material->VS_UniformSize); + if (material->FS_UniformSize > 0) + ApplyUniforms(ShaderStage::FragmentShader, 0, &material->Fs_UniformData.Front(), material->FS_UniformSize); + } + //------------------------------------------------------------------------------ BindingHandle CreateBinding(const Bindings& bindings) { @@ -232,6 +449,17 @@ namespace ari return g_mProj; } + void SetWorldMatrix(const sx_mat4& _world) + { + g_mWorld = _world; + g_mWorldViewProj = g_mViewProj * g_mWorld; + } + + sx_mat4 GetWorldMatrix() + { + return g_mWorld; + } + //------------------------------------------------------------------------------ void SetViewProjMatrix(const sx_mat4& _view, const sx_mat4& _proj) { @@ -246,6 +474,17 @@ namespace ari return g_mViewProj; } + void SetWorldViewProjMatrix(const sx_mat4& _world, const sx_mat4& _view, const sx_mat4& _proj) + { + SetViewProjMatrix(_view, _proj); + SetWorldMatrix(_world); + } + + sx_mat4 GetWorldViewProjMatrix() + { + return g_mWorldViewProj; + } + //------------------------------------------------------------------------------ static void tinyktxCallbackError(void* user, char const* msg) { log_error("Tiny_Ktx ERROR: %s", msg); @@ -369,6 +608,27 @@ namespace ari return { core::HandleManager::CreateHandleByIndex(img.id), img.id }; } + void SetDirLight(const sx_vec3& dir, const sx_vec4& color) + { + g_vLightDir = dir; + g_cLightColor = color; + g_bHasDirLight = true; + g_bHasOmniLight = false; + } + + void SetOmniLight(const sx_vec3& pos, const sx_vec4& color) + { + g_vLightPos = pos; + g_cLightColor = color; + g_bHasDirLight = false; + g_bHasOmniLight = true; + } + + void SetCameraPosition(const sx_vec3& pos) + { + g_vCamPos = pos; + } + } // namespace gfx } // namespace ari diff --git a/src/gfx/gfx.hpp b/src/gfx/gfx.hpp index bc61785..ccd2338 100644 --- a/src/gfx/gfx.hpp +++ b/src/gfx/gfx.hpp @@ -13,7 +13,7 @@ namespace ari namespace gfx { ARI_HANDLE(BufferHandle); - ARI_HANDLE(ShaderHanlde); + ARI_HANDLE(ShaderHandle); ARI_HANDLE(PipelineHandle); ARI_HANDLE(TextureHandle); ARI_HANDLE(BindingHandle); @@ -86,8 +86,31 @@ namespace ari struct PipelineSetup { LayoutSetup layout; - ShaderHanlde shader; + ShaderHandle shader; IndexType index_type = IndexType::None; + + /// equality operator + bool operator==(const PipelineSetup& rhs) const + { + if (shader.Handle != rhs.shader.Handle + || index_type != rhs.index_type) + return false; + for (int i = 0; i < ARI_MAX_SHADERSTAGE_BUFFERS; ++i) + { + if (layout.buffers[i].step != rhs.layout.buffers[i].step + || layout.buffers[i].stepRate != rhs.layout.buffers[i].stepRate + || layout.buffers[i].stride != rhs.layout.buffers[i].stride) + return false; + } + for (int i = 0; i < ARI_MAX_VERTEX_ATTRIBUTES; ++i) + { + if (layout.attrs[i].bufferIndex != rhs.layout.attrs[i].bufferIndex + || layout.attrs[i].offset != rhs.layout.attrs[i].offset + || layout.attrs[i].format != rhs.layout.attrs[i].format) + return false; + } + return true; + } }; struct Bindings @@ -98,6 +121,27 @@ namespace ari int indexBufferOffset = 0; TextureHandle vsTextures[ARI_MAX_SHADERSTAGE_TEXTURES]; TextureHandle fsTextures[ARI_MAX_SHADERSTAGE_TEXTURES]; + + /// equality operator + bool operator==(const Bindings& rhs) const + { + if (indexBuffer.Handle != rhs.indexBuffer.Handle + || indexBufferOffset != rhs.indexBufferOffset) + return false; + for (int i = 0; i < ARI_MAX_SHADERSTAGE_BUFFERS; ++i) + { + if (vertexBufferOffsets[i] != rhs.vertexBufferOffsets[i] + || vertexBuffers[i].Handle != rhs.vertexBuffers[i].Handle) + return false; + } + for (int i = 0; i < ARI_MAX_SHADERSTAGE_TEXTURES; ++i) + { + if (fsTextures[i].Handle != rhs.fsTextures[i].Handle + || vsTextures[i].Handle != rhs.vsTextures[i].Handle) + return false; + } + return true; + } }; enum class ShaderStage @@ -205,11 +249,15 @@ namespace ari Count }; + struct Material; + bool SetupGfx(GfxSetup& setup); void SetupShaders(); - ShaderHanlde GetShader(ShaderType shader); + ShaderHandle GetShader(ShaderType shader); + + void SetMaterialShader(Material& material); void RenderToWindow(const io::WindowHandle& handle); @@ -223,9 +271,9 @@ namespace ari void DestroyBuffer(BufferHandle& buffer); - ShaderHanlde CreateShader(const sg_shader_desc* desc); + ShaderHandle CreateShader(const sg_shader_desc* desc); - void DestroyShader(ShaderHanlde& shader); + void DestroyShader(ShaderHandle& shader); PipelineHandle CreatePipeline(const PipelineSetup& setup); @@ -233,6 +281,10 @@ namespace ari void ApplyPipeline(const PipelineHandle& pipeline); + void ApplyPipelineAndMaterial(const PipelineHandle& pipeline, Material* material); + + void SetPipelineShader(const PipelineHandle& pipeline, const ShaderHandle& shader); + BindingHandle CreateBinding(const Bindings& bindings); void DestroyBinding(BindingHandle& binding); @@ -259,11 +311,26 @@ namespace ari sx_mat4 GetProjMatrix(); + /// Set world after view and projection matrix + void SetWorldMatrix(const sx_mat4& _world); + + sx_mat4 GetWorldMatrix(); + void SetViewProjMatrix(const sx_mat4& _view, const sx_mat4& _proj); sx_mat4 GetViewProjMatrix(); - TextureHandle LoadTexture(core::String _path); + void SetWorldViewProjMatrix(const sx_mat4& _world, const sx_mat4& _view, const sx_mat4& _proj); + + sx_mat4 GetWorldViewProjMatrix(); + + TextureHandle LoadTexture(core::String _path); + + void SetDirLight(const sx_vec3& dir, const sx_vec4& color); + + void SetOmniLight(const sx_vec3& pos, const sx_vec4& color); + + void SetCameraPosition(const sx_vec3& pos); } // namespace gfx diff --git a/src/gfx/private/glfw/gfx_glfw.cpp b/src/gfx/private/glfw/gfx_glfw.cpp index 06204fd..b4f2c8a 100644 --- a/src/gfx/private/glfw/gfx_glfw.cpp +++ b/src/gfx/private/glfw/gfx_glfw.cpp @@ -17,7 +17,7 @@ namespace ari { bool SetupGfx(GfxSetup& setup) { - const io::WindowHandle window = io::CreateAriWindow(setup.window, "Ari 0.3"); + const io::WindowHandle window = io::CreateAriWindow(setup.window, "Ari 0.4"); if (!window.IsValid()) return false; @@ -51,6 +51,15 @@ namespace ari return g_FrameNumber; } + void SetPipelineShader(const PipelineHandle& pipeline, const ShaderHandle& shader) + { + _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pipeline.Index); + if (pip->cmn.shader_id.id == shader.Index) + return; + pip->shader = _sg_lookup_shader(&_sg.pools, shader.Index); + pip->cmn.shader_id.id = shader.Index; + } + } // namespace gfx } // namespace ari diff --git a/src/gfx/private/sapp/gfx_sapp.cpp b/src/gfx/private/sapp/gfx_sapp.cpp index 1993e8b..047add1 100644 --- a/src/gfx/private/sapp/gfx_sapp.cpp +++ b/src/gfx/private/sapp/gfx_sapp.cpp @@ -109,6 +109,15 @@ namespace ari return g_FrameNumber; } + void SetPipelineShader(const PipelineHandle& pipeline, const ShaderHandle& shader) + { + _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pipeline.Index); + if (pip->cmn.shader_id.id == shader.Index) + return; + pip->shader = _sg_lookup_shader(&_sg.pools, shader.Index); + pip->cmn.shader_id.id = shader.Index; + } + } } diff --git a/src/gfx/shaders/basic/basic.glsl b/src/gfx/shaders/basic/basic.glsl index 7d71f74..a69ef2f 100644 --- a/src/gfx/shaders/basic/basic.glsl +++ b/src/gfx/shaders/basic/basic.glsl @@ -19,7 +19,7 @@ void main() { @fs fs out vec4 frag_color; void main() { - frag_color = vec4(1,1,1,1); + frag_color = vec4(1.0); } @end diff --git a/src/gfx/shaders/fs_main.glsl b/src/gfx/shaders/fs_main.glsl new file mode 100644 index 0000000..61158fa --- /dev/null +++ b/src/gfx/shaders/fs_main.glsl @@ -0,0 +1,49 @@ +@block fs_main + +out vec4 frag_color; + +#if HAS_TEXCOORD +uniform sampler2D tex; +in vec2 uv; +#endif +#if HAS_VERTEXCOLOR +in vec4 color; +#endif +#if HAS_NORMAL +in vec3 FragPos; +in vec3 Normal; +#endif + +void main() +{ + frag_color = baseColor; +#if HAS_TEXCOORD + frag_color *= texture(tex, uv); +#endif + +#if HAS_VERTEXCOLOR + frag_color *= color; +#endif + +#if HAS_NORMAL + vec3 norm = normalize(Normal); + float diff = 0.0; + +# if HAS_DIR_LIGHT + diff += max(dot(norm, lightDir), 0.0); +# endif +# if HAS_POINT_LIGHT + vec3 lightDir = normalize(lightPos - FragPos); + diff += max(dot(norm, lightDir), 0.0); +# endif + + vec3 viewDir = normalize(camPos - FragPos); + vec3 reflectDir = reflect(-lightDir, norm); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); + float specular = specularStrength * spec; + + frag_color = frag_color * 0.1 + frag_color * vec4((diff + specular ) * lightColor, 1.0); +#endif +} + +@end \ No newline at end of file diff --git a/src/gfx/shaders/fs_params.glsl b/src/gfx/shaders/fs_params.glsl new file mode 100644 index 0000000..6b93870 --- /dev/null +++ b/src/gfx/shaders/fs_params.glsl @@ -0,0 +1,15 @@ +@block fs_params + vec4 baseColor; +#if HAS_NORMAL + vec3 camPos; + float specularStrength; +#endif +#if HAS_DIR_LIGHT + vec3 lightDir; + vec3 lightColor; +#endif +#if HAS_POINT_LIGHT + vec3 lightPos; + vec3 lightColor; +#endif +@end \ No newline at end of file diff --git a/src/gfx/shaders/mesh.glsl b/src/gfx/shaders/mesh.glsl new file mode 100644 index 0000000..6472a44 --- /dev/null +++ b/src/gfx/shaders/mesh.glsl @@ -0,0 +1,241 @@ +@module ari + +@include shared/ctypes.glsl +@include vs_params.glsl +@include vs_main.glsl +@include fs_params.glsl +@include fs_main.glsl + +//================================================================================ +// vs_mesh_ +@vs vs_mesh_ +uniform vs_params_mesh_ +{ +@include_block vs_params +}; +@include_block vs_main +@end + +// fs_mesh_ +@fs fs_mesh_ +uniform fs_params_mesh_ +{ +@include_block fs_params +}; +@include_block fs_main +@end + +// mesh_ +@program mesh_ vs_mesh_ fs_mesh_ + +//================================================================================ +// vs_mesh_T +@vs vs_mesh_T +#define HAS_TEXCOORD 1 +uniform vs_params_mesh_T +{ +@include_block vs_params +}; +@include_block vs_main +@end + +// fs_mesh_T +@fs fs_mesh_T +#define HAS_TEXCOORD 1 +uniform fs_params_mesh_T +{ +@include_block fs_params +}; +@include_block fs_main +@end + +// mesh_T +@program mesh_T vs_mesh_T fs_mesh_T + +//================================================================================ +// vs_mesh_VC +@vs vs_mesh_VC +#define HAS_VERTEXCOLOR 1 +uniform vs_params_mesh_VC +{ +@include_block vs_params +}; +@include_block vs_main +@end + +// fs_mesh_VC +@fs fs_mesh_VC +#define HAS_VERTEXCOLOR 1 +uniform fs_params_mesh_VC +{ +@include_block fs_params +}; +@include_block fs_main +@end + +// mesh_VC +@program mesh_VC vs_mesh_VC fs_mesh_VC + +//================================================================================ +// vs_mesh_TND +@vs vs_mesh_TND +#define HAS_TEXCOORD 1 +#define HAS_NORMAL 1 +#define HAS_DIR_LIGHT 1 +uniform vs_params_mesh_TND +{ +@include_block vs_params +}; +@include_block vs_main +@end + +// fs_mesh_TND +@fs fs_mesh_TND +#define HAS_TEXCOORD 1 +#define HAS_NORMAL 1 +#define HAS_DIR_LIGHT 1 +uniform fs_params_mesh_TND +{ +@include_block fs_params +}; +@include_block fs_main +@end + +// mesh_TND +@program mesh_TND vs_mesh_TND fs_mesh_TND + +//================================================================================ +// vs_mesh_TNP +@vs vs_mesh_TNP +#define HAS_TEXCOORD 1 +#define HAS_NORMAL 1 +#define HAS_POINT_LIGHT 1 +uniform vs_params_mesh_TNP +{ +@include_block vs_params +}; +@include_block vs_main +@end + +// fs_mesh_TNP +@fs fs_mesh_TNP +#define HAS_TEXCOORD 1 +#define HAS_NORMAL 1 +#define HAS_POINT_LIGHT 1 +uniform fs_params_mesh_TNP +{ +@include_block fs_params +}; +@include_block fs_main +@end + +// mesh_TNP +@program mesh_TNP vs_mesh_TNP fs_mesh_TNP + +//================================================================================ +// vs_mesh_VCND +@vs vs_mesh_VCND +#define HAS_VERTEXCOLOR 1 +#define HAS_NORMAL 1 +#define HAS_DIR_LIGHT 1 +uniform vs_params_mesh_VCND +{ +@include_block vs_params +}; +@include_block vs_main +@end + +// fs_mesh_VCND +@fs fs_mesh_VCND +#define HAS_VERTEXCOLOR 1 +#define HAS_NORMAL 1 +#define HAS_DIR_LIGHT 1 +uniform fs_params_mesh_VCND +{ +@include_block fs_params +}; +@include_block fs_main +@end + +// mesh_VCND +@program mesh_VCND vs_mesh_VCND fs_mesh_VCND + +//================================================================================ +// vs_mesh_VCNP +@vs vs_mesh_VCNP +#define HAS_VERTEXCOLOR 1 +#define HAS_NORMAL 1 +#define HAS_POINT_LIGHT 1 +uniform vs_params_mesh_VCNP +{ +@include_block vs_params +}; +@include_block vs_main +@end + +// fs_mesh_VCNP +@fs fs_mesh_VCNP +#define HAS_VERTEXCOLOR 1 +#define HAS_NORMAL 1 +#define HAS_POINT_LIGHT 1 +uniform fs_params_mesh_VCNP +{ +@include_block fs_params +}; +@include_block fs_main +@end + +// mesh_VCNP +@program mesh_VCNP vs_mesh_VCNP fs_mesh_VCNP + +//================================================================================ +// vs_mesh_ND +@vs vs_mesh_ND +#define HAS_NORMAL 1 +#define HAS_DIR_LIGHT 1 +uniform vs_params_mesh_ND +{ +@include_block vs_params +}; +@include_block vs_main +@end + +// fs_mesh_ND +@fs fs_mesh_ND +#define HAS_NORMAL 1 +#define HAS_DIR_LIGHT 1 +uniform fs_params_mesh_ND +{ +@include_block fs_params +}; +@include_block fs_main +@end + +// mesh_ND +@program mesh_ND vs_mesh_ND fs_mesh_ND + +//================================================================================ +// vs_mesh_NP +@vs vs_mesh_NP +#define HAS_NORMAL 1 +#define HAS_POINT_LIGHT 1 +uniform vs_params_mesh_NP +{ +@include_block vs_params +}; +@include_block vs_main +@end + +// fs_mesh_NP +@fs fs_mesh_NP +#define HAS_NORMAL 1 +#define HAS_POINT_LIGHT 1 +uniform fs_params_mesh_NP +{ +@include_block fs_params +}; +@include_block fs_main +@end + +// mesh_NP +@program mesh_NP vs_mesh_NP fs_mesh_NP diff --git a/src/gfx/shaders/shared/ctypes.glsl b/src/gfx/shaders/shared/ctypes.glsl index 7c0864d..27ebf7d 100644 --- a/src/gfx/shaders/shared/ctypes.glsl +++ b/src/gfx/shaders/shared/ctypes.glsl @@ -1 +1,3 @@ @ctype mat4 sx_mat4 +@ctype vec4 sx_vec4 +@ctype vec3 sx_vec3 diff --git a/src/gfx/shaders/vs_main.glsl b/src/gfx/shaders/vs_main.glsl new file mode 100644 index 0000000..a727e4f --- /dev/null +++ b/src/gfx/shaders/vs_main.glsl @@ -0,0 +1,32 @@ +@block vs_main + +in vec4 pos; +#if HAS_TEXCOORD +in vec2 texcoord0; +out vec2 uv; +#endif +#if HAS_VERTEXCOLOR +in vec4 color0; +out vec4 color; +#endif +#if HAS_NORMAL +in vec3 normal0; +out vec3 FragPos; +out vec3 Normal; +#endif + +void main() +{ + gl_Position = mvp * pos; +#if HAS_TEXCOORD + uv = texcoord0; +#endif +#if HAS_VERTEXCOLOR + color = color0; +#endif +#if HAS_NORMAL + FragPos = vec3(matWorld * pos); + Normal = mat3(matWorld) * normal0; +#endif +} +@end diff --git a/src/gfx/shaders/vs_params.glsl b/src/gfx/shaders/vs_params.glsl new file mode 100644 index 0000000..d87a9f0 --- /dev/null +++ b/src/gfx/shaders/vs_params.glsl @@ -0,0 +1,8 @@ +@block vs_params + + mat4 mvp; +#if HAS_NORMAL + mat4 matWorld; +#endif + +@end \ No newline at end of file diff --git a/tests/02-triangle/triangle.cpp b/tests/02-triangle/triangle.cpp index 86a0515..d3f44fb 100644 --- a/tests/02-triangle/triangle.cpp +++ b/tests/02-triangle/triangle.cpp @@ -64,7 +64,7 @@ class TriangleApp : public ari::Application ari::gfx::GfxSetup m_setup; ari::gfx::BufferHandle vb; - ari::gfx::ShaderHanlde shader; + ari::gfx::ShaderHandle shader; ari::gfx::PipelineSetup pipeline_setup; ari::gfx::PipelineHandle pipeline; ari::gfx::BindingHandle binding; diff --git a/tests/07-gltf/gltf.cpp b/tests/07-gltf/gltf.cpp index 57f79ca..d17ee67 100644 --- a/tests/07-gltf/gltf.cpp +++ b/tests/07-gltf/gltf.cpp @@ -52,6 +52,9 @@ class GltfApp : public ari::Application TotalTime += _elapsedTime; m_camera.Component->Position.x = sx_sin(TotalTime) * 3; m_camera.Component->Position.z = sx_cos(TotalTime) * 3; + ari::gfx::SetOmniLight(sx_vec3f(m_camera.Component->Position.x, m_camera.Component->Position.y + 1, m_camera.Component->Position.z), + sx_vec4f(1.f, 1.f, 1.f, 1.f)); + ari::gfx::SetOmniLight(sx_vec3f(3.0, 3, 3), sx_vec4f(1, 1, 1, 1)); m_world.Update(_elapsedTime); }