diff --git a/cmake_modules/gcc.cmake b/cmake_modules/gcc.cmake index a8afa14..a484d89 100644 --- a/cmake_modules/gcc.cmake +++ b/cmake_modules/gcc.cmake @@ -12,7 +12,6 @@ # Generic warnings. set(FGL_WARNINGS "-Wall -Wundef -Wextra -Wpedantic") - #AppendFlag("-Wno-changes-meaning") # Prevents accidently changing the type of things. Cannot define 1 things as another later AppendFlag("-Wdouble-promotion") #Prevents issue where you can do math as a double which might not be intended. AppendFlag("-Wnonnull") #Prevents passing null as an argument marked as nonnull attribute @@ -109,7 +108,7 @@ #set(FGL_WARNINGS "${FGL_WARNINGS_GENERIC} -Wpessimizing-move -Wpedantic -Weffc++ -pedantic-errors -Wnoexcept -Wuninitialized -Wunused -Wunused-parameter -Winit-self -Wconversion -Wuseless-cast -Wextra-semi -Wsuggest-final-types -Wsuggest-final-methods -Wsuggest-override -Wformat-signedness -Wno-format-zero-length -Wmissing-include-dirs -Wshift-overflow=2 -Walloc-zero -Walloca -Wsign-promo -Wconversion -Wduplicated-branches -Wduplicated-cond -Wshadow -Wshadow=local -Wvirtual-inheritance -Wno-virtual-move-assign -Wunsafe-loop-optimizations -Wnormalized -Wpacked -Wredundant-decls -Wctor-dtor-privacy -Wdeprecated-copy-dtor -Wstrict-null-sentinel -Wold-style-cast -Woverloaded-virtual -Wzero-as-null-pointer-constant -Wconditionally-supported -Wwrite-strings -Wunused-const-variable=2 -Wdouble-promotion -Wpointer-arith -Wcast-align=strict -Wcast-qual -Wconversion -Wsign-conversion -Wimplicit-fallthrough=1 -Wmisleading-indentation -Wdangling-else -Wdate-time -Wformat=2 -Wformat-overflow=2 -Wformat-signedness -Wformat-truncation=2 -Wswitch-default -Wstringop-overflow=4 -Warray-bounds=2 -Wattribute-alias=2 -Wcatch-value=2 -Wplacement-new=2 -Wtrampolines -Winvalid-imported-macros -Winvalid-imported-macros") - set(FGL_CONFIG "-std=c++20 -fmax-errors=3 -fconcepts-diagnostics-depth=8") + set(FGL_CONFIG "-std=c++20 -fmax-errors=1 -fconcepts-diagnostics-depth=8 -Werror") # Optimization flags set(FGL_OPTIMIZATION_FLAGS_RELEASE "-O2 -s -fdevirtualize-at-ltrans -fdevirtualize-speculatively -funroll-loops") # System agonistc flags @@ -118,7 +117,7 @@ set(FGL_OPTIMIZATION_FLAGS_RELWITHDEBINFO "-O2 -g -fdevirtualize-at-ltrans -fdevirtualize-speculatively -fdeclone-ctor-dtor -funroll-loops") # Final sets - set(FGL_FLAGS "${FGL_OPTIMIZATION_FLAGS_${UPPER_BUILD_TYPE}} ${FLG_WARNINGS}" PARENT_SCOPE) # Flags for our shit + set(FGL_FLAGS "${FGL_CONFIG} ${FGL_OPTIMIZATION_FLAGS_${UPPER_BUILD_TYPE}} ${FLG_WARNINGS}" PARENT_SCOPE) # Flags for our shit #set(FGL_FLAGS "${FGL_OPTIMIZATION_FLAGS_${UPPER_BUILD_TYPE}}" PARENT_SCOPE) set(FGL_CHILD_FLAGS "${FGL_OPTIMIZATION_FLAGS_${UPPER_BUILD_TYPE}}" PARENT_SCOPE) # Child flags for adding optmization to anything we build ourselves but doesn't follow our standard #set(CMAKE_CXX_FLAGS "${FGL_CHILD_FLAGS}") diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt index 8c4ffb9..febbf31 100644 --- a/src/engine/CMakeLists.txt +++ b/src/engine/CMakeLists.txt @@ -31,3 +31,6 @@ if (CMAKE_UPPER_BUILD_TYPE STREQUAL "DEBUG") else () target_compile_definitions(FGLEngine PRIVATE ENABLE_IMGUI=0) endif () + +#GLM settings +target_compile_definitions(FGLEngine PUBLIC GLM_FORCE_RADIANS GLM_FORCE_DEPTH_ZERO_TO_ONE) diff --git a/src/engine/Camera.cpp b/src/engine/Camera.cpp index 51fd8d2..a5bcba4 100644 --- a/src/engine/Camera.cpp +++ b/src/engine/Camera.cpp @@ -4,6 +4,9 @@ #include "Camera.hpp" +#define GLM_ENABLE_EXPERIMENTAL +#include + #include #include @@ -13,13 +16,7 @@ namespace fgl::engine void Camera::setOrthographicProjection( float left, float right, float top, float bottom, float near, float far ) { ZoneScoped; - projection_matrix = glm::mat4 { 1.0f }; - projection_matrix[ 0 ][ 0 ] = 2.0f / ( right - left ); - projection_matrix[ 1 ][ 1 ] = 2.0f / ( bottom - top ); - projection_matrix[ 2 ][ 2 ] = 1.0f / ( far - near ); - projection_matrix[ 3 ][ 0 ] = -( right + left ) / ( right - left ); - projection_matrix[ 3 ][ 1 ] = -( bottom + top ) / ( bottom - top ); - projection_matrix[ 3 ][ 2 ] = -near / ( far - near ); + projection_matrix = glm::orthoLH( left, right, bottom, top, near, far ); //TODO: Figure out frustum culling for orthographic projection. (If we even wanna use it) } @@ -27,14 +24,7 @@ namespace fgl::engine void Camera::setPerspectiveProjection( float fovy, float aspect, float near, float far ) { ZoneScoped; - assert( glm::abs( aspect - std::numeric_limits< float >::epsilon() ) > 0 ); - const float tan_half_fovy { std::tan( fovy / 2.0f ) }; - projection_matrix = glm::mat4 { 0.0f }; - projection_matrix[ 0 ][ 0 ] = 1.0f / ( aspect * tan_half_fovy ); - projection_matrix[ 1 ][ 1 ] = 1.0f / ( tan_half_fovy ); - projection_matrix[ 2 ][ 2 ] = far / ( far - near ); - projection_matrix[ 2 ][ 3 ] = 1.0f; - projection_matrix[ 3 ][ 2 ] = -( far * near ) / ( far - near ); + projection_matrix = glm::perspectiveLH( fovy, aspect, near, far ); base_frustum = createFrustum( *this, aspect, fovy, near, far ); } @@ -42,40 +32,9 @@ namespace fgl::engine void Camera::setViewDirection( glm::vec3 position, glm::vec3 direction, glm::vec3 up ) { ZoneScoped; - const glm::vec3 w_direction { glm::normalize( direction ) }; - const glm::vec3 u_right { glm::normalize( glm::cross( w_direction, up ) ) }; - const glm::vec3 v_up { glm::cross( w_direction, u_right ) }; - - /* - * view_matrix - * u_r = view_right - * v_u = view_up - * w_d = view_direction - * - * | u_r.x u_r.y u_r.z 0 | - * | v_u.x v_u.y v_u.z 0 | - * | w_d.x w_d.y w_d.z 0 | - * | 0 0 0 1 | - */ - - view_matrix = glm::mat4 { 1.0f }; - view_matrix[ 0 ][ 0 ] = u_right.x; - view_matrix[ 1 ][ 0 ] = u_right.y; - view_matrix[ 2 ][ 0 ] = u_right.z; - - view_matrix[ 0 ][ 1 ] = v_up.x; - view_matrix[ 1 ][ 1 ] = v_up.y; - view_matrix[ 2 ][ 1 ] = v_up.z; - - view_matrix[ 0 ][ 2 ] = w_direction.x; - view_matrix[ 1 ][ 2 ] = w_direction.y; - view_matrix[ 2 ][ 2 ] = w_direction.z; - - view_matrix[ 3 ][ 0 ] = -glm::dot( u_right, position ); - view_matrix[ 3 ][ 1 ] = -glm::dot( v_up, position ); - view_matrix[ 3 ][ 2 ] = -glm::dot( w_direction, position ); - + glm::lookAt( position, position + direction, up ); frustum = base_frustum * view_matrix; + return; } void Camera::setViewTarget( glm::vec3 position, glm::vec3 target, glm::vec3 up ) @@ -83,37 +42,110 @@ namespace fgl::engine setViewDirection( position, glm::normalize( target - position ), up ); } - void Camera::setViewYXZ( glm::vec3 position, glm::vec3 rotation ) + enum RotationOrder { - ZoneScoped; + XYZ, + XZY, + YXZ, + YZX, + ZXY, + ZYX + }; + + glm::mat4 taitBryanMatrix( const glm::vec3 rotation, const RotationOrder order = XYZ ) + { + glm::mat4 mat { 1.0f }; + + const float c1 { glm::cos( rotation.x ) }; + const float s1 { glm::sin( rotation.x ) }; + + const float c2 { glm::cos( rotation.y ) }; + const float s2 { glm::sin( rotation.y ) }; + const float c3 { glm::cos( rotation.z ) }; const float s3 { glm::sin( rotation.z ) }; - const float c2 { glm::cos( rotation.x ) }; - const float s2 { glm::sin( rotation.x ) }; - const float c1 { glm::cos( rotation.y ) }; - const float s1 { glm::sin( rotation.y ) }; - const glm::vec3 u { ( c1 * c3 + s1 * s2 * s3 ), ( c2 * s3 ), ( c1 * s2 * s3 - c3 * s1 ) }; - const glm::vec3 v { ( c3 * s1 * s2 - c1 * s3 ), ( c2 * c3 ), ( c1 * c3 * s2 + s1 * s3 ) }; - const glm::vec3 w { ( c2 * s1 ), ( -s2 ), ( c1 * c2 ) }; - view_matrix = glm::mat4 { 1.0f }; - view_matrix[ 0 ][ 0 ] = u.x; - view_matrix[ 1 ][ 0 ] = u.y; - view_matrix[ 2 ][ 0 ] = u.z; + switch ( order ) + { + case RotationOrder::XYZ: // Pitch, Yaw, Roll + { + const glm::vec3 row_0 { ( c2 * c3 ), -( c2 * s3 ), s2 }; + const glm::vec3 row_1 { ( c1 * s3 ) + ( c3 * s1 * s2 ), + ( c1 * c3 ) - ( s1 * s2 * s3 ), + -( c2 * s1 ) }; + const glm::vec3 row_2 { ( s1 * s3 ) - ( c1 * c3 * s2 ), + ( c3 * s1 ) + ( c1 * s2 * s3 ), + ( c1 * c2 ) }; - view_matrix[ 0 ][ 1 ] = v.x; - view_matrix[ 1 ][ 1 ] = v.y; - view_matrix[ 2 ][ 1 ] = v.z; + mat[ 0 ] = glm::vec4( row_0, 0.0f ); + mat[ 1 ] = glm::vec4( row_1, 0.0f ); + mat[ 2 ] = glm::vec4( row_2, 0.0f ); + return mat; + } + case RotationOrder::ZYX: // Yaw, Roll, Pitch + { + const glm::vec3 row_0 { ( c1 * c2 ), + ( c1 * s2 * s3 ) - ( c3 * s1 ), + ( s1 * s3 ) + ( c1 * c3 * s2 ) }; + const glm::vec3 row_1 { ( c2 * s1 ), + ( c1 * c3 ) + ( s1 * s2 * s3 ), + ( c3 * s1 * s2 ) - ( c1 * s3 ) }; + const glm::vec3 row_2 { -s2, c2 * s3, c2 * c3 }; - view_matrix[ 0 ][ 2 ] = w.x; - view_matrix[ 1 ][ 2 ] = w.y; - view_matrix[ 2 ][ 2 ] = w.z; + mat[ 0 ] = glm::vec4( row_0, 0.0f ); + mat[ 1 ] = glm::vec4( row_1, 0.0f ); + mat[ 2 ] = glm::vec4( row_2, 0.0f ); + return mat; + } + case RotationOrder::YXZ: // Roll, Pitch, Yaw + { + const glm::vec3 row_0 { ( c1 * c3 ) + ( s1 * s2 * s3 ), ( c3 * s1 * s2 ) - ( c1 * s3 ), c2 * s1 }; + const glm::vec3 row_1 { c2 * s3, c2 * c3, -s2 }; + const glm::vec3 row_2 { ( c1 * s2 * s3 ) - ( c3 * s1 ), ( c1 * c3 * s2 ) + ( s1 * s3 ), c1 * c2 }; + + mat[ 0 ] = glm::vec4( row_0, 0.0f ); + mat[ 1 ] = glm::vec4( row_1, 0.0f ); + mat[ 2 ] = glm::vec4( row_2, 0.0f ); + return mat; + } + default: + throw std::runtime_error( "Unimplemented rotation order" ); + } + } + + void Camera::setViewYXZ( glm::vec3 position, glm::vec3 rotation, const ViewMode mode ) + { + ZoneScoped; + + switch ( mode ) + { + case ViewMode::TaitBryan: + { + const glm::mat4 rotation_matrix { taitBryanMatrix( rotation ) }; + + const glm::vec3 forward { rotation_matrix * glm::vec4( constants::WORLD_FORWARD, 0.0f ) }; + + const glm::vec3 camera_up { rotation_matrix * glm::vec4( constants::WORLD_UP, 0.0f ) }; view_matrix[ 3 ][ 0 ] = -glm::dot( u, position ); view_matrix[ 3 ][ 1 ] = -glm::dot( v, position ); view_matrix[ 3 ][ 2 ] = -glm::dot( w, position ); + view_matrix = glm::lookAtLH( position, position + forward, camera_up ); + + break; + } + case ViewMode::Euler: + { + //TODO: Implement + //view_matrix = glm::lookAtLH(position, position + ); + } + default: + throw std::runtime_error( "Unimplemented view mode" ); + } frustum = base_frustum * view_matrix; + + return; } Frustum diff --git a/src/engine/Camera.hpp b/src/engine/Camera.hpp index e38479e..f0384c6 100644 --- a/src/engine/Camera.hpp +++ b/src/engine/Camera.hpp @@ -70,9 +70,16 @@ namespace fgl::engine const glm::vec3 getDown() const { return -getUp(); } - void setViewDirection( glm::vec3 pos, glm::vec3 direction, glm::vec3 up = WORLD_UP ); - void setViewTarget( glm::vec3 pos, glm::vec3 target, glm::vec3 up = WORLD_UP ); - void setViewYXZ( glm::vec3 pos, glm::vec3 rotation ); + void setViewDirection( glm::vec3 pos, glm::vec3 direction, glm::vec3 up = constants::WORLD_UP ); + void setViewTarget( glm::vec3 pos, glm::vec3 target, glm::vec3 up = constants::WORLD_UP ); + + enum ViewMode + { + Euler, + TaitBryan + }; + + void setViewYXZ( glm::vec3 pos, glm::vec3 rotation, const ViewMode mode = TaitBryan ); }; } // namespace fgl::engine diff --git a/src/engine/EngineContext.cpp b/src/engine/EngineContext.cpp index a252d6e..ab77ca8 100644 --- a/src/engine/EngineContext.cpp +++ b/src/engine/EngineContext.cpp @@ -98,7 +98,7 @@ namespace fgl::engine Camera camera {}; auto viewer { GameObject::createGameObject() }; - viewer.transform.translation.z = -2.5f; + viewer.transform.translation = constants::WORLD_CENTER + glm::vec3( 0.0f, 0.0f, -2.5f ); KeyboardMovementController camera_controller {}; auto current_time { std::chrono::high_resolution_clock::now() }; diff --git a/src/engine/GameObject.hpp b/src/engine/GameObject.hpp index dcecef9..b93c7ad 100644 --- a/src/engine/GameObject.hpp +++ b/src/engine/GameObject.hpp @@ -4,13 +4,13 @@ #pragma once -#define GLM_FORCE_RADIANS -#define GLM_FORCE_DEPTH_ZERO_TO_ONE #include #include #include +#include "constants.hpp" + namespace fgl::engine { @@ -18,7 +18,7 @@ namespace fgl::engine struct TransformComponent { - glm::vec3 translation { 0.0f, 0.0f, 0.0f }; + glm::vec3 translation { constants::DEFAULT_VEC3 }; glm::vec3 scale { 1.0f, 1.0f, 1.0f }; glm::vec3 rotation { 0.0f, 0.0f, 0.0f }; diff --git a/src/engine/constants.hpp b/src/engine/constants.hpp new file mode 100644 index 0000000..7c83b8c --- /dev/null +++ b/src/engine/constants.hpp @@ -0,0 +1,30 @@ +// +// Created by kj16609 on 1/30/24. +// + +#pragma once + +#include + +namespace fgl::engine::constants +{ + + constexpr glm::vec3 DEFAULT_VEC3 { std::numeric_limits< float >::max() }; + + constexpr glm::vec3 WORLD_CENTER { 0.0f, 0.0f, 0.0f }; + + // Z UP + constexpr glm::vec3 WORLD_UP { 0.0f, 0.0f, 1.0f }; + constexpr glm::vec3 WORLD_DOWN { -WORLD_UP }; + + // X RIGHT + constexpr glm::vec3 WORLD_RIGHT { 1.0f, 0.0f, 0.0f }; + constexpr glm::vec3 WORLD_LEFT { -WORLD_RIGHT }; + + // Y FORWARD + constexpr glm::vec3 WORLD_FORWARD { 0.0f, 1.0f, 0.0f }; + constexpr glm::vec3 WORLD_BACKWARD { -WORLD_FORWARD }; + + constexpr float DEFAULT_FLOAT { std::numeric_limits< float >::max() }; + +} // namespace fgl::engine::constants diff --git a/src/engine/model/Model.cpp b/src/engine/model/Model.cpp index ae5cba8..ec17e3a 100644 --- a/src/engine/model/Model.cpp +++ b/src/engine/model/Model.cpp @@ -8,8 +8,6 @@ #include #define GLM_ENABLE_EXPERIMENTAL -#define GLM_FORCE_RADIANS -#define GLM_FORCE_DEPTH_ZERO_TO_ONE #include #include @@ -21,30 +19,6 @@ #include "engine/image/ImageView.hpp" #include "engine/image/Sampler.hpp" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" -#pragma GCC diagnostic ignored "-Weffc++" -#include "objectloaders/tiny_gltf.h" -#include "objectloaders/tiny_obj_loader.h" -#pragma GCC diagnostic pop - -#include "engine/utils.hpp" - -namespace std -{ - template <> - struct hash< fgl::engine::Vertex > - { - size_t operator()( const fgl::engine::Vertex& vertex ) const - { - std::size_t seed { 0 }; - fgl::engine::hashCombine( seed, vertex.m_position, vertex.m_color, vertex.m_normal, vertex.m_uv ); - return seed; - } - }; - -} // namespace std - namespace fgl::engine { @@ -102,7 +76,7 @@ namespace fgl::engine m_draw_parameters( buildParameters( builder.m_primitives ) ), m_bounding_box( bounding_box ) { - assert( bounding_box.middle != DEFAULT_COORDINATE_VEC3 ); + assert( bounding_box.middle != constants::DEFAULT_VEC3 ); m_primitives = std::move( builder.m_primitives ); } @@ -127,38 +101,6 @@ namespace fgl::engine } } - std::vector< vk::VertexInputBindingDescription > Vertex::getBindingDescriptions() - { - std::vector< vk::VertexInputBindingDescription > binding_descriptions { - { 0, sizeof( Vertex ), vk::VertexInputRate::eVertex }, - { 1, sizeof( ModelMatrixInfo ), vk::VertexInputRate::eInstance } - }; - - return binding_descriptions; - } - - std::vector< vk::VertexInputAttributeDescription > Vertex::getAttributeDescriptions() - { - std::vector< vk::VertexInputAttributeDescription > attribute_descriptions {}; - - attribute_descriptions.emplace_back( 0, 0, vk::Format::eR32G32B32Sfloat, offsetof( Vertex, m_position ) ); - attribute_descriptions.emplace_back( 1, 0, vk::Format::eR32G32B32Sfloat, offsetof( Vertex, m_color ) ); - attribute_descriptions.emplace_back( 2, 0, vk::Format::eR32G32B32Sfloat, offsetof( Vertex, m_normal ) ); - attribute_descriptions.emplace_back( 3, 0, vk::Format::eR32G32Sfloat, offsetof( Vertex, m_uv ) ); - - //Normal Matrix - attribute_descriptions.emplace_back( 4, 1, vk::Format::eR32G32B32A32Sfloat, 0 ); - attribute_descriptions.emplace_back( 5, 1, vk::Format::eR32G32B32A32Sfloat, 1 * sizeof( glm::vec4 ) ); - attribute_descriptions.emplace_back( 6, 1, vk::Format::eR32G32B32A32Sfloat, 2 * sizeof( glm::vec4 ) ); - attribute_descriptions.emplace_back( 7, 1, vk::Format::eR32G32B32A32Sfloat, 3 * sizeof( glm::vec4 ) ); - - attribute_descriptions.emplace_back( 8, 1, vk::Format::eR32Sint, 4 * sizeof( glm::vec4 ) ); - - static_assert( 4 * sizeof( glm::vec4 ) + sizeof( int ) == sizeof( ModelMatrixInfo ) ); - - return attribute_descriptions; - } - void ModelBuilder::loadModel( const std::filesystem::path& filepath ) { if ( filepath.extension() == ".obj" ) @@ -170,381 +112,7 @@ namespace fgl::engine loadGltf( filepath ); } else - //Dunno throw std::runtime_error( "Unknown model file extension" ); } - template < typename T > - std::vector< T > extractData( const tinygltf::Model& model, const tinygltf::Accessor& accessor ) - { - if ( accessor.sparse.isSparse ) - { - //Sparse loading required - - throw std::runtime_error( "Sparse loading not implemeneted" ); - } - else - { - auto& buffer_view { model.bufferViews.at( accessor.bufferView ) }; - auto& buffer { model.buffers.at( buffer_view.buffer ) }; - - std::vector< T > data; - - std::uint16_t copy_size { 0 }; - switch ( accessor.componentType ) - { - default: - throw std::runtime_error( "Unhandled access size" ); - case TINYGLTF_COMPONENT_TYPE_FLOAT: - copy_size = sizeof( float ); - break; - case TINYGLTF_COMPONENT_TYPE_BYTE: - copy_size = sizeof( std::byte ); - break; - case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT: - copy_size = sizeof( unsigned int ); - break; - case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: - copy_size = sizeof( unsigned short ); - break; - } - - switch ( accessor.type ) - { - default: - throw std::runtime_error( "UNhandled access type" ); - case TINYGLTF_TYPE_VEC3: - copy_size *= 3; - break; - case TINYGLTF_TYPE_VEC2: - copy_size *= 2; - break; - case TINYGLTF_TYPE_SCALAR: - //noop - break; - } - - constexpr auto T_SIZE { sizeof( T ) }; - - assert( T_SIZE == copy_size && "Accessor copy values not greater than or matching sizeof(T)" ); - - const auto real_size { copy_size * accessor.count }; - - data.resize( real_size ); - - std::memcpy( data.data(), buffer.data.data() + buffer_view.byteOffset + accessor.byteOffset, real_size ); - - return data; - } - }; - - void ModelBuilder::loadGltf( const std::filesystem::path& filepath ) - { - std::cout << "Loading gltf model " << filepath << std::endl; - - if ( !std::filesystem::exists( filepath ) ) throw std::runtime_error( "File does not exist" ); - - m_primitives.clear(); - - tinygltf::Model model {}; - tinygltf::TinyGLTF loader {}; - std::string err; - std::string warn; - - loader.RemoveImageLoader(); - - loader.LoadASCIIFromFile( &model, &err, &warn, filepath.string() ); - - if ( !err.empty() ) throw std::runtime_error( err ); - - if ( !warn.empty() ) - std::cout << "Warning while loading model \"" << filepath.string() << "\"\nWarning:" << warn << std::endl; - - for ( const tinygltf::Mesh& mesh : model.meshes ) - { - std::vector< glm::vec3 > model_positions; - - for ( const tinygltf::Primitive& primitive : mesh.primitives ) - { - //TODO: Implement modes - - std::cout << "Attributes: \n"; - for ( const auto& thing : primitive.attributes ) - { - std::cout << "\t" << thing.first << "\n"; - } - std::cout << std::endl; - - //Load indicies - auto& indicies_accessor { model.accessors.at( primitive.indices ) }; - - std::vector< std::uint32_t > indicies_data {}; - - if ( indicies_accessor.componentType == TINYGLTF_COMPONENT_TYPE_INT ) - { - indicies_data = extractData< std::uint32_t >( model, model.accessors.at( primitive.indices ) ); - } - else if ( indicies_accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT ) - { - auto tmp { extractData< std::uint16_t >( model, model.accessors.at( primitive.indices ) ) }; - - indicies_data.reserve( tmp.size() ); - - for ( auto& val : tmp ) - { - indicies_data.emplace_back( val ); - } - } - - //Load positions - auto& position_accessor { model.accessors.at( primitive.attributes.at( "POSITION" ) ) }; - std::vector< glm::vec3 > position_data { extractData< glm::vec3 >( model, position_accessor ) }; - model_positions.insert( model_positions.end(), position_data.begin(), position_data.end() ); - - BoundingBox bounding_box { generateBoundingFromPoints( position_data ) }; - - std::vector< glm::vec3 > normals; - - if ( primitive.attributes.find( "NORMAL" ) != primitive.attributes.end() ) - { - normals = - extractData< glm::vec3 >( model, model.accessors.at( primitive.attributes.at( "NORMAL" ) ) ); - } - else // TODO: Precompute normals if required - normals.resize( position_data.size() ); - - //TODO: Implement TANGENT reading - std::vector< glm::vec3 > tangents; - - std::vector< glm::vec2 > texcoords; - - for ( const auto& [ attr_name, attr_idx ] : primitive.attributes ) - { - if ( attr_name.starts_with( "TEXCOORD_" ) ) - { - //Rip out name and figure out index - const auto idx { std::stoi( attr_name.substr( strlen( "TEXCOORD_" ) ) ) }; - - if ( idx != 0 ) throw std::runtime_error( "Multiple tex coordinates not supported" ); - - auto& texcoord_accessor { model.accessors.at( attr_idx ) }; - - texcoords = extractData< glm::vec2 >( model, texcoord_accessor ); - } - } - - std::vector< Vertex > verts; - verts.resize( position_data.size() ); - for ( std::size_t i = 0; i < position_data.size(); i++ ) - { - //Fix position to be -Z UP - //verts[ i ].m_position = position_data[ i ]; - verts[ i ].m_position = { position_data[ i ].x, -position_data[ i ].y, position_data[ i ].z }; - verts[ i ].m_normal = normals[ i ]; - verts[ i ].m_uv = texcoords[ i ]; - } - - VertexBufferSuballocation vertex_buffer { m_vertex_buffer, verts }; - IndexBufferSuballocation index_buffer { m_index_buffer, indicies_data }; - - if ( primitive.material >= 0 && primitive.material < model.materials.size() ) - { - const auto& material { model.materials.at( primitive.material ) }; - - //TODO: Implement material normals - - //Color texture - if ( material.values.contains( "baseColorTexture" ) ) - { - const auto& color_texture { material.values.at( "baseColorTexture" ) }; - const auto color_index { color_texture.TextureIndex() }; - - const auto& texture { model.textures.at( color_index ) }; - - const auto& source { model.images.at( texture.source ) }; - const auto& sampler { model.samplers.at( texture.sampler ) }; - - auto translateFilterToVK = []( const int val ) -> vk::Filter - { - switch ( val ) - { - default: - throw std::runtime_error( "Failed to translate filter value to vk filter value" ); - case GL_NEAREST: - return vk::Filter::eNearest; - case GL_LINEAR: - [[fallthrough]]; - case GL_LINEAR_MIPMAP_LINEAR: - return vk::Filter::eLinear; - } - }; - - auto translateWarppingToVk = []( const int val ) -> vk::SamplerAddressMode - { - switch ( val ) - { - default: - throw std:: - runtime_error( "Failed to translate wrapping filter to vk address mode" ); - case GL_REPEAT: - return vk::SamplerAddressMode::eRepeat; -#ifdef GL_CLAMP_TO_BORDER - case GL_CLAMP_TO_BORDER: - return vk::SamplerAddressMode::eClampToBorder; -#endif -#ifdef GL_CLAMP_TO_EDGE - case GL_CLAMP_TO_EDGE: - return vk::SamplerAddressMode::eClampToEdge; -#endif - } - }; - - assert( - sampler.wrapS == sampler.wrapT - && "Can't support different wrap modes for textures on each axis" ); - - Texture tex { Texture::loadFromFile( filepath.parent_path() / source.uri ) }; - Sampler smp { translateFilterToVK( sampler.minFilter ), - translateFilterToVK( sampler.magFilter ), - vk::SamplerMipmapMode::eLinear, - translateWarppingToVk( sampler.wrapS ) }; - - tex.getImageView().getSampler() = std::move( smp ); - tex.createImGuiSet(); - - Texture::getTextureDescriptorSet().bindTexture( 0, tex ); - Texture::getTextureDescriptorSet().update(); - - //Stage texture - auto cmd { Device::getInstance().beginSingleTimeCommands() }; - - tex.stage( cmd ); - Device::getInstance().endSingleTimeCommands( cmd ); - tex.dropStaging(); - - Primitive prim { - std::move( vertex_buffer ), std::move( index_buffer ), bounding_box, std::move( tex ) - }; - - m_primitives.emplace_back( std::move( prim ) ); - - continue; - } - } - else - std::cout << "No material" << std::endl; - - Primitive prim { std::move( vertex_buffer ), std::move( index_buffer ), bounding_box }; - - m_primitives.emplace_back( std::move( prim ) ); - } - - std::cout << "Mesh has " << mesh.primitives.size() << " primitives" << std::endl; - } - - for ( const tinygltf::Scene& scene : model.scenes ) - { - std::cout << "Loading scene " << scene.name << std::endl; - std::cout << "Scene has " << scene.nodes.size() << " nodes" << std::endl; - - for ( auto child : scene.nodes ) - { - std::cout << "Child: " << child << std::endl; - } - } - - std::cout << "Scenes: " << model.scenes.size() << std::endl; - - std::cout << "Meshes: " << model.meshes.size() << std::endl; - } - - void ModelBuilder::loadObj( const std::filesystem::path& filepath ) - { - m_primitives.clear(); - - tinyobj::attrib_t attrib {}; - std::vector< tinyobj::shape_t > shapes {}; - std::vector< tinyobj::material_t > materials {}; - std::string warn {}; - std::string error {}; - - if ( !tinyobj::LoadObj( &attrib, &shapes, &materials, &warn, &error, filepath.string< char >().c_str() ) ) - throw std::runtime_error( warn + error ); - - std::unordered_map< Vertex, std::uint32_t > unique_verts {}; - - std::vector< Vertex > verts; - std::vector< std::uint32_t > indicies; - - for ( const auto& shape : shapes ) - { - for ( const auto& index : shape.mesh.indices ) - { - Vertex vert {}; - if ( index.vertex_index >= 0 ) - { - vert.m_position = { - attrib.vertices[ static_cast< std::uint64_t >( 3 * index.vertex_index + 0 ) ], - attrib.vertices[ static_cast< std::uint64_t >( 3 * index.vertex_index + 1 ) ], - attrib.vertices[ static_cast< std::uint64_t >( 3 * index.vertex_index + 2 ) ], - }; - - vert.m_color = { attrib.colors[ static_cast< std::uint64_t >( 3 * index.vertex_index + 0 ) ], - attrib.colors[ static_cast< std::uint64_t >( 3 * index.vertex_index + 1 ) ], - attrib.colors[ static_cast< std::uint64_t >( 3 * index.vertex_index + 2 ) ] }; - - assert( vert.m_color[ 0 ] > 0.2f ); - assert( vert.m_color[ 1 ] > 0.2f ); - assert( vert.m_color[ 2 ] > 0.2f ); - } - - if ( index.normal_index >= 0 ) - { - vert.m_normal = { - attrib.normals[ static_cast< std::uint64_t >( 3 * index.normal_index + 0 ) ], - attrib.normals[ static_cast< std::uint64_t >( 3 * index.normal_index + 1 ) ], - attrib.normals[ static_cast< std::uint64_t >( 3 * index.normal_index + 2 ) ], - }; - } - - if ( index.texcoord_index >= 0 ) - { - vert.m_uv = { - attrib.texcoords[ static_cast< std::uint64_t >( 3 * index.texcoord_index + 0 ) ], - attrib.texcoords[ static_cast< std::uint64_t >( 3 * index.texcoord_index + 1 ) ], - }; - } - - if ( auto itter = unique_verts.find( vert ); itter != unique_verts.end() ) - { - indicies.push_back( unique_verts[ vert ] ); - } - else - { - const auto insert_op { unique_verts.insert( std::make_pair( vert, verts.size() ) ) }; - verts.emplace_back( vert ); - - if ( insert_op.second ) - indicies.push_back( insert_op.first->second ); - else - throw std::runtime_error( "Failed to insert new vertex" ); - } - } - } - - std::vector< glm::vec3 > vert_pos; - for ( const auto& vert : verts ) - { - vert_pos.emplace_back( vert.m_position ); - } - - BoundingBox bounding_box { generateBoundingFromPoints( vert_pos ) }; - - m_primitives.emplace_back( - VertexBufferSuballocation( m_vertex_buffer, std::move( verts ) ), - IndexBufferSuballocation( m_index_buffer, std::move( indicies ) ), - bounding_box ); - - std::cout << unique_verts.size() << " unique verts" << std::endl; - } } // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/model/Model.hpp b/src/engine/model/Model.hpp index 08c585a..839c3d7 100644 --- a/src/engine/model/Model.hpp +++ b/src/engine/model/Model.hpp @@ -4,8 +4,6 @@ #pragma once -#define GLM_FORCE_RADIANS -#define GLM_FORCE_DEPTH_ZERO_TO_ONE #include #include @@ -15,6 +13,7 @@ #include #include "BoundingBox.hpp" +#include "Vertex.hpp" #include "engine/Device.hpp" #include "engine/buffers/Buffer.hpp" #include "engine/buffers/BufferSuballocation.hpp" @@ -26,25 +25,6 @@ namespace fgl::engine { - struct Vertex - { - glm::vec3 m_position { 0.0f, 0.0f, 0.0f }; - glm::vec3 m_color { 1.0f, 1.0f, 1.0f }; - glm::vec3 m_normal { 0.0f, 0.0f, 0.0f }; - glm::vec2 m_uv { 0.0f, 0.0f }; - - static std::vector< vk::VertexInputBindingDescription > getBindingDescriptions(); - static std::vector< vk::VertexInputAttributeDescription > getAttributeDescriptions(); - - Vertex() noexcept = default; - - bool operator==( const Vertex& other ) const - { - return m_position == other.m_position && m_color == other.m_color && m_normal == other.m_normal - && m_uv == other.m_uv; - } - }; - struct ModelMatrixInfo { glm::mat4 model_matrix; diff --git a/src/engine/model/Vertex.cpp b/src/engine/model/Vertex.cpp new file mode 100644 index 0000000..ae9e6e0 --- /dev/null +++ b/src/engine/model/Vertex.cpp @@ -0,0 +1,64 @@ +// +// Created by kj16609 on 2/5/24. +// + +#include "Vertex.hpp" + +#define GLM_ENABLE_EXPERIMENTAL +#include + +#include "Model.hpp" +#include "engine/utils.hpp" + +namespace fgl::engine +{ + + bool Vertex::operator==( const Vertex& other ) const + { + return m_position == other.m_position && m_color == other.m_color && m_normal == other.m_normal + && m_uv == other.m_uv; + } + + std::vector< vk::VertexInputBindingDescription > Vertex::getBindingDescriptions() + { + std::vector< vk::VertexInputBindingDescription > binding_descriptions { + { 0, sizeof( Vertex ), vk::VertexInputRate::eVertex }, + { 1, sizeof( ModelMatrixInfo ), vk::VertexInputRate::eInstance } + }; + + return binding_descriptions; + } + + std::vector< vk::VertexInputAttributeDescription > Vertex::getAttributeDescriptions() + { + std::vector< vk::VertexInputAttributeDescription > attribute_descriptions {}; + + attribute_descriptions.emplace_back( 0, 0, vk::Format::eR32G32B32Sfloat, offsetof( Vertex, m_position ) ); + attribute_descriptions.emplace_back( 1, 0, vk::Format::eR32G32B32Sfloat, offsetof( Vertex, m_color ) ); + attribute_descriptions.emplace_back( 2, 0, vk::Format::eR32G32B32Sfloat, offsetof( Vertex, m_normal ) ); + attribute_descriptions.emplace_back( 3, 0, vk::Format::eR32G32Sfloat, offsetof( Vertex, m_uv ) ); + + //Normal Matrix + attribute_descriptions.emplace_back( 4, 1, vk::Format::eR32G32B32A32Sfloat, 0 ); + attribute_descriptions.emplace_back( 5, 1, vk::Format::eR32G32B32A32Sfloat, 1 * sizeof( glm::vec4 ) ); + attribute_descriptions.emplace_back( 6, 1, vk::Format::eR32G32B32A32Sfloat, 2 * sizeof( glm::vec4 ) ); + attribute_descriptions.emplace_back( 7, 1, vk::Format::eR32G32B32A32Sfloat, 3 * sizeof( glm::vec4 ) ); + + attribute_descriptions.emplace_back( 8, 1, vk::Format::eR32Sint, 4 * sizeof( glm::vec4 ) ); + + static_assert( 4 * sizeof( glm::vec4 ) + sizeof( int ) == sizeof( ModelMatrixInfo ) ); + + return attribute_descriptions; + } + +} // namespace fgl::engine + +namespace std +{ + std::size_t hash< fgl::engine::Vertex >::operator()( const fgl::engine::Vertex& vertex ) const + { + std::size_t seed { 0 }; + fgl::engine::hashCombine( seed, vertex.m_position, vertex.m_color, vertex.m_normal, vertex.m_uv ); + return seed; + } +} // namespace std diff --git a/src/engine/model/Vertex.hpp b/src/engine/model/Vertex.hpp new file mode 100644 index 0000000..e31063a --- /dev/null +++ b/src/engine/model/Vertex.hpp @@ -0,0 +1,40 @@ +// +// Created by kj16609 on 2/5/24. +// + +#pragma once + +#include +#include +#include + +namespace fgl::engine +{ + + struct Vertex + { + glm::vec3 m_position { 0.0f, 0.0f, 0.0f }; + glm::vec3 m_color { 1.0f, 1.0f, 1.0f }; + glm::vec3 m_normal { 0.0f, 0.0f, 0.0f }; + glm::vec2 m_uv { 0.0f, 0.0f }; + + static std::vector< vk::VertexInputBindingDescription > getBindingDescriptions(); + static std::vector< vk::VertexInputAttributeDescription > getAttributeDescriptions(); + + Vertex() noexcept = default; + + bool operator==( const Vertex& other ) const; + }; + +} // namespace fgl::engine + +namespace std +{ + + template <> + struct hash< fgl::engine::Vertex > + { + std::size_t operator()( const fgl::engine::Vertex& vertex ) const; + }; + +} // namespace std diff --git a/src/engine/model/gltfLoading.cpp b/src/engine/model/gltfLoading.cpp new file mode 100644 index 0000000..746dd31 --- /dev/null +++ b/src/engine/model/gltfLoading.cpp @@ -0,0 +1,323 @@ +// +// Created by kj16609 on 2/5/24. +// + +#include "Model.hpp" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Weffc++" +#include "engine/image/Sampler.hpp" +#include "objectloaders/tiny_gltf.h" +#pragma GCC diagnostic pop + +#include "engine/descriptors/DescriptorSet.hpp" +#include "engine/image/ImageView.hpp" + +namespace fgl::engine +{ + + template < typename T > + std::vector< T > extractData( const tinygltf::Model& model, const tinygltf::Accessor& accessor ) + { + if ( accessor.sparse.isSparse ) + { + //Sparse loading required + + throw std::runtime_error( "Sparse loading not implemeneted" ); + } + else + { + auto& buffer_view { model.bufferViews.at( accessor.bufferView ) }; + auto& buffer { model.buffers.at( buffer_view.buffer ) }; + + std::vector< T > data; + + std::uint16_t copy_size { 0 }; + switch ( accessor.componentType ) + { + default: + throw std::runtime_error( "Unhandled access size" ); + case TINYGLTF_COMPONENT_TYPE_FLOAT: + copy_size = sizeof( float ); + break; + case TINYGLTF_COMPONENT_TYPE_BYTE: + copy_size = sizeof( std::byte ); + break; + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT: + copy_size = sizeof( unsigned int ); + break; + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: + copy_size = sizeof( unsigned short ); + break; + } + + switch ( accessor.type ) + { + default: + throw std::runtime_error( "UNhandled access type" ); + case TINYGLTF_TYPE_VEC3: + copy_size *= 3; + break; + case TINYGLTF_TYPE_VEC2: + copy_size *= 2; + break; + case TINYGLTF_TYPE_SCALAR: + //noop + break; + } + + constexpr auto T_SIZE { sizeof( T ) }; + + assert( T_SIZE == copy_size && "Accessor copy values not greater than or matching sizeof(T)" ); + + const auto real_size { copy_size * accessor.count }; + + data.resize( real_size ); + + std::memcpy( data.data(), buffer.data.data() + buffer_view.byteOffset + accessor.byteOffset, real_size ); + + return data; + } + } + + template <> + std::vector< ModelCoordinate > extractData< + ModelCoordinate >( const tinygltf::Model& model, const tinygltf::Accessor& accessor ) + { + const std::vector< glm::vec3 > data { extractData< glm::vec3 >( model, accessor ) }; + + std::vector< ModelCoordinate > ret; + ret.reserve( data.size() ); + + for ( const auto& val : data ) + { + ret.emplace_back( val ); + } + + return ret; + } + + void ModelBuilder::loadGltf( const std::filesystem::path& filepath ) + { + std::cout << "Loading gltf model " << filepath << std::endl; + + if ( !std::filesystem::exists( filepath ) ) throw std::runtime_error( "File does not exist" ); + + m_primitives.clear(); + + tinygltf::Model model {}; + tinygltf::TinyGLTF loader {}; + std::string err; + std::string warn; + + loader.RemoveImageLoader(); + + loader.LoadASCIIFromFile( &model, &err, &warn, filepath.string() ); + + if ( !err.empty() ) throw std::runtime_error( err ); + + if ( !warn.empty() ) + std::cout << "Warning while loading model \"" << filepath.string() << "\"\nWarning:" << warn << std::endl; + + for ( const tinygltf::Mesh& mesh : model.meshes ) + { + std::vector< glm::vec3 > model_positions; + + for ( const tinygltf::Primitive& primitive : mesh.primitives ) + { + //TODO: Implement modes + + std::cout << "Attributes: \n"; + for ( const auto& thing : primitive.attributes ) + { + std::cout << "\t" << thing.first << "\n"; + } + std::cout << std::endl; + + //Load indicies + auto& indicies_accessor { model.accessors.at( primitive.indices ) }; + + std::vector< std::uint32_t > indicies_data {}; + + if ( indicies_accessor.componentType == TINYGLTF_COMPONENT_TYPE_INT ) + { + indicies_data = extractData< std::uint32_t >( model, model.accessors.at( primitive.indices ) ); + } + else if ( indicies_accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT ) + { + auto tmp { extractData< std::uint16_t >( model, model.accessors.at( primitive.indices ) ) }; + + indicies_data.reserve( tmp.size() ); + + for ( auto& val : tmp ) + { + indicies_data.emplace_back( val ); + } + } + + //Load positions + auto& position_accessor { model.accessors.at( primitive.attributes.at( "POSITION" ) ) }; + std::vector< ModelCoordinate > position_data { + extractData< ModelCoordinate >( model, position_accessor ) + }; + model_positions.insert( model_positions.end(), position_data.begin(), position_data.end() ); + + ModelBoundingBox bounding_box { generateBoundingFromPoints< CoordinateType::Model >( position_data ) }; + + std::vector< glm::vec3 > normals; + + if ( primitive.attributes.find( "NORMAL" ) != primitive.attributes.end() ) + { + normals = + extractData< glm::vec3 >( model, model.accessors.at( primitive.attributes.at( "NORMAL" ) ) ); + } + else // TODO: Precompute normals if required + normals.resize( position_data.size() ); + + //TODO: Implement TANGENT reading + std::vector< glm::vec3 > tangents; + + std::vector< glm::vec2 > texcoords; + + for ( const auto& [ attr_name, attr_idx ] : primitive.attributes ) + { + if ( attr_name.starts_with( "TEXCOORD_" ) ) + { + //Rip out name and figure out index + const auto idx { std::stoi( attr_name.substr( strlen( "TEXCOORD_" ) ) ) }; + + if ( idx != 0 ) throw std::runtime_error( "Multiple tex coordinates not supported" ); + + auto& texcoord_accessor { model.accessors.at( attr_idx ) }; + + texcoords = extractData< glm::vec2 >( model, texcoord_accessor ); + } + } + + std::vector< Vertex > verts; + verts.resize( position_data.size() ); + for ( std::size_t i = 0; i < position_data.size(); i++ ) + { + //Fix position to be -Z UP + //verts[ i ].m_position = position_data[ i ]; + verts[ i ].m_position = + glm::vec3( position_data[ i ].x, -position_data[ i ].z, -position_data[ i ].y ); + verts[ i ].m_normal = normals[ i ]; + verts[ i ].m_uv = texcoords[ i ]; + } + + VertexBufferSuballocation vertex_buffer { m_vertex_buffer, verts }; + IndexBufferSuballocation index_buffer { m_index_buffer, indicies_data }; + + if ( primitive.material >= 0 && primitive.material < model.materials.size() ) + { + const auto& material { model.materials.at( primitive.material ) }; + + //TODO: Implement material normals + + //Color texture + if ( material.values.contains( "baseColorTexture" ) ) + { + const auto& color_texture { material.values.at( "baseColorTexture" ) }; + const auto color_index { color_texture.TextureIndex() }; + + const auto& texture { model.textures.at( color_index ) }; + + const auto& source { model.images.at( texture.source ) }; + const auto& sampler { model.samplers.at( texture.sampler ) }; + + auto translateFilterToVK = []( const int val ) -> vk::Filter + { + switch ( val ) + { + default: + throw std::runtime_error( "Failed to translate filter value to vk filter value" ); + case GL_NEAREST: + return vk::Filter::eNearest; + case GL_LINEAR: + [[fallthrough]]; + case GL_LINEAR_MIPMAP_LINEAR: + return vk::Filter::eLinear; + } + }; + + auto translateWarppingToVk = []( const int val ) -> vk::SamplerAddressMode + { + switch ( val ) + { + default: + throw std:: + runtime_error( "Failed to translate wrapping filter to vk address mode" ); + case GL_REPEAT: + return vk::SamplerAddressMode::eRepeat; +#ifdef GL_CLAMP_TO_BORDER + case GL_CLAMP_TO_BORDER: + return vk::SamplerAddressMode::eClampToBorder; +#endif +#ifdef GL_CLAMP_TO_EDGE + case GL_CLAMP_TO_EDGE: + return vk::SamplerAddressMode::eClampToEdge; +#endif + } + }; + + assert( + sampler.wrapS == sampler.wrapT + && "Can't support different wrap modes for textures on each axis" ); + + Texture tex { Texture::loadFromFile( filepath.parent_path() / source.uri ) }; + Sampler smp { translateFilterToVK( sampler.minFilter ), + translateFilterToVK( sampler.magFilter ), + vk::SamplerMipmapMode::eLinear, + translateWarppingToVk( sampler.wrapS ) }; + + tex.getImageView().getSampler() = std::move( smp ); + tex.createImGuiSet(); + + Texture::getTextureDescriptorSet().bindTexture( 0, tex ); + Texture::getTextureDescriptorSet().update(); + + //Stage texture + auto cmd { Device::getInstance().beginSingleTimeCommands() }; + + tex.stage( cmd ); + Device::getInstance().endSingleTimeCommands( cmd ); + tex.dropStaging(); + + Primitive prim { + std::move( vertex_buffer ), std::move( index_buffer ), bounding_box, std::move( tex ) + }; + + m_primitives.emplace_back( std::move( prim ) ); + + continue; + } + } + else + std::cout << "No material" << std::endl; + + Primitive prim { std::move( vertex_buffer ), std::move( index_buffer ), bounding_box }; + + m_primitives.emplace_back( std::move( prim ) ); + } + + std::cout << "Mesh has " << mesh.primitives.size() << " primitives" << std::endl; + } + + for ( const tinygltf::Scene& scene : model.scenes ) + { + std::cout << "Loading scene " << scene.name << std::endl; + std::cout << "Scene has " << scene.nodes.size() << " nodes" << std::endl; + + for ( auto child : scene.nodes ) + { + std::cout << "Child: " << child << std::endl; + } + } + + std::cout << "Scenes: " << model.scenes.size() << std::endl; + + std::cout << "Meshes: " << model.meshes.size() << std::endl; + } +} // namespace fgl::engine diff --git a/src/engine/model/objLoading.cpp b/src/engine/model/objLoading.cpp new file mode 100644 index 0000000..97b3367 --- /dev/null +++ b/src/engine/model/objLoading.cpp @@ -0,0 +1,107 @@ +// +// Created by kj16609 on 2/5/24. +// + +#include "Model.hpp" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Weffc++" +#include "objectloaders/tiny_obj_loader.h" +#pragma GCC diagnostic pop + +#include "Vertex.hpp" + +namespace fgl::engine +{ + + void ModelBuilder::loadObj( const std::filesystem::path& filepath ) + { + m_primitives.clear(); + + tinyobj::attrib_t attrib {}; + std::vector< tinyobj::shape_t > shapes {}; + std::vector< tinyobj::material_t > materials {}; + std::string warn {}; + std::string error {}; + + if ( !tinyobj::LoadObj( &attrib, &shapes, &materials, &warn, &error, filepath.string< char >().c_str() ) ) + throw std::runtime_error( warn + error ); + + std::unordered_map< Vertex, std::uint32_t > unique_verts {}; + + std::vector< Vertex > verts; + std::vector< std::uint32_t > indicies; + + for ( const auto& shape : shapes ) + { + for ( const auto& index : shape.mesh.indices ) + { + Vertex vert {}; + if ( index.vertex_index >= 0 ) + { + vert.m_position = { + attrib.vertices[ static_cast< std::uint64_t >( 3 * index.vertex_index + 0 ) ], + attrib.vertices[ static_cast< std::uint64_t >( 3 * index.vertex_index + 1 ) ], + attrib.vertices[ static_cast< std::uint64_t >( 3 * index.vertex_index + 2 ) ], + }; + + vert.m_color = { attrib.colors[ static_cast< std::uint64_t >( 3 * index.vertex_index + 0 ) ], + attrib.colors[ static_cast< std::uint64_t >( 3 * index.vertex_index + 1 ) ], + attrib.colors[ static_cast< std::uint64_t >( 3 * index.vertex_index + 2 ) ] }; + + assert( vert.m_color[ 0 ] > 0.2f ); + assert( vert.m_color[ 1 ] > 0.2f ); + assert( vert.m_color[ 2 ] > 0.2f ); + } + + if ( index.normal_index >= 0 ) + { + vert.m_normal = { + attrib.normals[ static_cast< std::uint64_t >( 3 * index.normal_index + 0 ) ], + attrib.normals[ static_cast< std::uint64_t >( 3 * index.normal_index + 1 ) ], + attrib.normals[ static_cast< std::uint64_t >( 3 * index.normal_index + 2 ) ], + }; + } + + if ( index.texcoord_index >= 0 ) + { + vert.m_uv = { + attrib.texcoords[ static_cast< std::uint64_t >( 3 * index.texcoord_index + 0 ) ], + attrib.texcoords[ static_cast< std::uint64_t >( 3 * index.texcoord_index + 1 ) ], + }; + } + + if ( auto itter = unique_verts.find( vert ); itter != unique_verts.end() ) + { + indicies.push_back( unique_verts[ vert ] ); + } + else + { + const auto insert_op { unique_verts.insert( std::make_pair( vert, verts.size() ) ) }; + verts.emplace_back( vert ); + + if ( insert_op.second ) + indicies.push_back( insert_op.first->second ); + else + throw std::runtime_error( "Failed to insert new vertex" ); + } + } + } + + std::vector< ModelCoordinate > vert_pos; + for ( const auto& vert : verts ) + { + vert_pos.emplace_back( vert.m_position ); + } + + BoundingBox bounding_box { generateBoundingFromPoints( vert_pos ) }; + + m_primitives.emplace_back( + VertexBufferSuballocation( m_vertex_buffer, std::move( verts ) ), + IndexBufferSuballocation( m_index_buffer, std::move( indicies ) ), + bounding_box ); + + std::cout << unique_verts.size() << " unique verts" << std::endl; + } +} // namespace fgl::engine diff --git a/src/engine/systems/EntityRendererSystem.cpp b/src/engine/systems/EntityRendererSystem.cpp index 4899bb7..2f2a94a 100644 --- a/src/engine/systems/EntityRendererSystem.cpp +++ b/src/engine/systems/EntityRendererSystem.cpp @@ -4,12 +4,9 @@ #include "EntityRendererSystem.hpp" -#define GLM_FORCE_RADIANS -#define GLM_FORCE_DEPTH_ZERO_TO_ON #include #include #include -#include #include #include #include @@ -102,7 +99,7 @@ namespace fgl::engine debug::world::drawBoundingBox( model_bounding_box, info.camera ); - if ( !model_bounding_box.isInFrustum( info.camera_frustum ) ) continue; + //if ( !model_bounding_box.isInFrustum( info.camera_frustum ) ) continue; for ( const auto& primitive : obj.model->m_primitives ) { diff --git a/src/engine/utils.hpp b/src/engine/utils.hpp index 7f3186e..e0a87c3 100644 --- a/src/engine/utils.hpp +++ b/src/engine/utils.hpp @@ -10,7 +10,7 @@ namespace fgl::engine { template < typename T, typename... Ts > - void hashCombine( std::size_t& seed, const T& v, const Ts&... ts ) + inline void hashCombine( std::size_t& seed, const T& v, const Ts&... ts ) { std::hash< T > hasher; seed ^= hasher( v ) + 0x9e3779b9 + ( seed << 6 ) + ( seed >> 2 );