Mostly fixes rotation shit and other obscure bugs

This commit is contained in:
2024-09-29 01:31:59 -04:00
parent af2cd5db61
commit c6236eda98
41 changed files with 623 additions and 797 deletions

View File

@@ -104,7 +104,7 @@
AppendFlag("-fdiagnostics-show-template-tree") # Shows the template diagnostic info as a tree instead.
AppendFlag("-fdiagnostics-path-format=inline-events")
set(FGL_CONFIG "-std=c++23 -fmax-errors=6 -fconcepts-diagnostics-depth=8 -flto=auto -ftree-vectorize")
set(FGL_CONFIG "-std=c++23 -fmax-errors=6 -fconcepts-diagnostics-depth=8 -ftree-vectorize")
if (DEFINED USE_WERROR)
set(FGL_CONFIG "${FGL_CONFIG} -Werror")
@@ -128,7 +128,7 @@
#set(FGL_FLAGS "${FGL_OPTIMIZATION_FLAGS_${UPPER_BUILD_TYPE}}" PARENT_SCOPE)
set(FGL_CHILD_FLAGS "${FGL_OPTIMIZATION_FLAGS_RELEASE}" PARENT_SCOPE) # Child flags for adding optimization to anything we build ourselves but doesn't follow our standard
# We use release flags since we really don't need to be using debug flags for anything not ours
set(CMAKE_CXX_FLAGS "${FGL_CHILD_FLAGS}")
#set(CMAKE_CXX_FLAGS "${FGL_CHILD_FLAGS}")
endif ()
endfunction()

View File

@@ -14,3 +14,4 @@ target_link_libraries(TitorEditor PRIVATE FGLEngine)
target_include_directories(TitorEditor PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_compile_definitions(TitorEditor PUBLIC TITOR_EDITOR)
target_compile_features(TitorEditor PRIVATE cxx_std_23)
target_link_libraries(TitorEditor PRIVATE glfw ImGui)

View File

@@ -4,8 +4,8 @@
#include "engine/gameobjects/components/ModelComponent.hpp"
#include "engine/gameobjects/components/drawers.hpp"
#include "engine/assets/model/Model.hpp"
#include "engine/gameobjects/components/drawers.hpp"
#include "gui/safe_include.hpp"
namespace fgl::engine
@@ -16,15 +16,25 @@ namespace fgl::engine
{
drawComponentTransform( m_transform );
ImGui::Text( "MODEL COMPONENT WOOOOOO" );
//ImGui::Text( "MODEL COMPONENT WOOOOOO" );
// TODO: If the model is not set then we should be able to set it to one from the file selection
if ( this->m_model == nullptr )
{
ImGui::Text( "Undefined model" );
return;
}
const auto& model { *this->m_model };
ImGui::Text( "%i primitives", model.m_primitives.size() );
}
std::string_view ModelComponent::name() const
{
if ( m_model )
if ( !m_model ) return "Empty";
return m_model->getName();
else
return "Empty Model";
}
#endif

View File

@@ -28,24 +28,26 @@ namespace fgl::engine::gui
constexpr double pitch_rate { 1.0 };
constexpr double yaw_rate { 1.0 };
if ( ImGui::IsKeyDown( ImGuiKey_DownArrow ) )
{
yaw_change.pitch() -= ( delta_time * pitch_rate );
}
if ( ImGui::IsKeyDown( ImGuiKey_UpArrow ) )
{
yaw_change.pitch() += ( delta_time * pitch_rate );
// yaw_change.xAngle() += ( delta_time * pitch_rate );
yaw_change.addY( delta_time * pitch_rate );
}
if ( ImGui::IsKeyDown( ImGuiKey_LeftArrow ) )
if ( ImGui::IsKeyDown( ImGuiKey_DownArrow ) )
{
pitch_change.yaw() -= ( delta_time * yaw_rate );
// yaw_change.xAngle() -= ( delta_time * pitch_rate );
yaw_change.addY( -( delta_time * pitch_rate ) );
}
if ( ImGui::IsKeyDown( ImGuiKey_RightArrow ) )
{
pitch_change.yaw() += ( delta_time * yaw_rate );
pitch_change.addZ( delta_time * yaw_rate );
}
if ( ImGui::IsKeyDown( ImGuiKey_LeftArrow ) )
{
pitch_change.addZ( -( delta_time * yaw_rate ) );
}
Vector move_dir { 0.0f };

View File

@@ -44,17 +44,17 @@ namespace fgl::engine::gui
if ( changed[ Pitch ] )
{
rot.pitch() = dat[ Pitch ];
//TODO: rot.xAngle() = dat[ Pitch ];
}
if ( changed[ Roll ] )
{
rot.roll() = dat[ Roll ];
//TODO: rot.zAngle() = dat[ Roll ];
}
if ( changed[ Yaw ] )
{
rot.yaw() = dat[ Yaw ];
//TODO: rot.yAngle() = dat[ Yaw ];
}
}

View File

@@ -33,10 +33,11 @@ target_compile_definitions(FGLEngine PUBLIC VULKAN_HPP_FLAGS_MASK_TYPE_AS_PUBLIC
include(dependencies/spdlog)
include(dependencies/imgui)
target_link_libraries(FGLEngine PUBLIC Vulkan::Vulkan glfw glm ImGui Tracy::TracyClient VMA FGLLoader spdlog shaderc)
target_link_libraries(FGLEngine PUBLIC Vulkan::Vulkan glm ImGui FGLLoader spdlog shaderc)
target_link_libraries(FGLEngine PUBLIC glfw Tracy::TracyClient VMA)
target_include_directories(FGLEngine PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..)
set_target_properties(FGLEngine PROPERTIES COMPILE_FLAGS ${FGL_FLAGS})
target_compile_features(FGLEngine PRIVATE cxx_std_23)
target_compile_features(FGLEngine PUBLIC cxx_std_23)
string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_UPPER_BUILD_TYPE)
@@ -56,7 +57,6 @@ endif ()
if (DEFINED FGL_ENABLE_TESTS AND FGL_ENABLE_TESTS)
target_compile_definitions(FGLEngine PUBLIC FGL_TESTS=1)
target_link_libraries(FGLEngine PUBLIC Catch2)
else ()
target_compile_definitions(FGLEngine PUBLIC FGL_TESTS=0)
endif ()
@@ -67,7 +67,7 @@ target_compile_definitions(FGLEngine PUBLIC TRACK_BUFFERS)
#GLM settings
# GLM_FORCE_NO_CTOR_INIT
target_compile_definitions(FGLEngine PUBLIC GLM_FORCE_RADIANS GLM_FORCE_DEPTH_ZERO_TO_ONE GLM_FORCE_LEFT_HANDED)
target_compile_definitions(FGLEngine PUBLIC GLM_FORCE_RADIANS GLM_FORCE_DEPTH_ZERO_TO_ONE)
if (DEFINED FGL_ENABLE_CALIBRATED_PROFILING AND FGL_ENABLE_CALIBRATED_PROFILING)
target_compile_definitions(FGLEngine PUBLIC ENABLE_CALIBRATED_PROFILING=1)

View File

@@ -42,8 +42,8 @@
#ifndef NDEBUG
#include <stdexcept>
#define FGL_ASSERT( test, msg ) \
if ( !( test ) ) throw std::runtime_error( msg );
#define FGL_ASSERT( test, msg ) assert( ( test ) && "msg" );
//if ( !( test ) ) throw std::runtime_error( msg );
#else
#define FGL_ASSERT( test, msg )
#endif

View File

@@ -78,19 +78,13 @@ namespace fgl::engine
if ( cursor_enabled )
{
const auto& original_rotation { target.getTransform().rotation };
Rotation yaw_rotation {};
Rotation pitch_rotation {};
if ( pitch_change > std::numeric_limits< float >::epsilon()
|| pitch_change < -std::numeric_limits< float >::epsilon() )
pitch_rotation.pitch() += dt * pitch_change;
target.getTransform().rotation.addX( dt * pitch_change );
if ( yaw_change > std::numeric_limits< float >::epsilon()
|| yaw_change < -std::numeric_limits< float >::epsilon() )
yaw_rotation.yaw() += dt * yaw_change;
target.getTransform().rotation = yaw_rotation * original_rotation * pitch_rotation;
target.getTransform().rotation.addY( dt * yaw_change );
}
else // No cursor
{
@@ -100,8 +94,8 @@ namespace fgl::engine
Rotation target_rotation { target.getTransform().rotation };
target_rotation.yaw() += ( xpos * 0.006f ) * look_speed;
target_rotation.pitch() -= ( ypos * 0.006f ) * look_speed;
target_rotation.addZ( ( xpos * 0.006f ) * look_speed );
target_rotation.addX( ( ypos * 0.006f ) * look_speed );
target.getTransform().rotation = target_rotation;

View File

@@ -9,8 +9,8 @@
#include "builders/ModelBuilder.hpp"
#include "builders/SceneBuilder.hpp"
#include "engine/memory/buffers/Buffer.hpp"
#include "engine/assets/image/ImageView.hpp"
#include "engine/memory/buffers/Buffer.hpp"
namespace fgl::engine
{
@@ -21,8 +21,13 @@ namespace fgl::engine
std::vector< vk::DrawIndexedIndirectCommand > draw_parameters {};
draw_parameters.reserve( primitives.size() );
//TODO: Perhaps building the parameter list using the model instead of keeping a list already here would be better in order to reduce allocations
for ( const auto& primitive : primitives )
{
// Skip drawing this primitive if draw flag is not set
if ( !primitive.draw ) continue;
vk::DrawIndexedIndirectCommand cmd;
cmd.indexCount = primitive.m_index_buffer.size();
cmd.firstIndex = primitive.m_index_buffer.getOffsetCount();

View File

@@ -67,6 +67,7 @@ namespace fgl::engine
struct Primitive
{
bool draw { true };
VertexBufferSuballocation m_vertex_buffer;
IndexBufferSuballocation m_index_buffer;
OrientedBoundingBox< CoordinateSpace::Model > m_bounding_box;

View File

@@ -12,12 +12,12 @@
#include "objectloaders/tiny_gltf.h"
#pragma GCC diagnostic pop
#include "engine/assets/image/ImageView.hpp"
#include "engine/assets/stores.hpp"
#include "engine/camera/Camera.hpp"
#include "engine/debug/logging/logging.hpp"
#include "engine/descriptors/DescriptorSet.hpp"
#include "engine/gameobjects/GameObject.hpp"
#include "engine/assets/image/ImageView.hpp"
namespace fgl::engine
{
@@ -173,8 +173,9 @@ namespace fgl::engine
const auto mat_idx { prim.material };
if ( mat_idx == -1 )
{
//There is no material for this
throw std::runtime_error( "No material for primitive. One was expected" );
//There is no textures for this material
// throw std::runtime_error( "No material for primitive. One was expected" );
return {};
}
const tinygltf::Material& materials { root.materials[ mat_idx ] };

View File

@@ -19,11 +19,11 @@ namespace fgl::engine
constexpr glm::vec3 BOTTOM_LEFT { -0.5f, -0.5f, 0.0f };
constexpr float dist_mulpt { 2.0f };
verts.emplace_back( TOP_LEFT * dist_mulpt, glm::vec3( 1.0f ), constants::WORLD_UP, glm::vec2( 0.0f, 0.0f ) );
verts.emplace_back( TOP_RIGHT * dist_mulpt, glm::vec3( 1.0f ), constants::WORLD_UP, glm::vec2( 1.0f, 0.0f ) );
verts.emplace_back( TOP_LEFT * dist_mulpt, glm::vec3( 1.0f ), constants::WORLD_Z, glm::vec2( 0.0f, 0.0f ) );
verts.emplace_back( TOP_RIGHT * dist_mulpt, glm::vec3( 1.0f ), constants::WORLD_Z, glm::vec2( 1.0f, 0.0f ) );
verts
.emplace_back( BOTTOM_RIGHT * dist_mulpt, glm::vec3( 1.0f ), constants::WORLD_UP, glm::vec2( 1.0f, 1.0f ) );
verts.emplace_back( BOTTOM_LEFT * dist_mulpt, glm::vec3( 1.0f ), constants::WORLD_UP, glm::vec2( 0.0f, 1.0f ) );
.emplace_back( BOTTOM_RIGHT * dist_mulpt, glm::vec3( 1.0f ), constants::WORLD_Z, glm::vec2( 1.0f, 1.0f ) );
verts.emplace_back( BOTTOM_LEFT * dist_mulpt, glm::vec3( 1.0f ), constants::WORLD_Z, glm::vec2( 0.0f, 1.0f ) );
std::vector< std::uint32_t > indicies { 0, 1, 2, 3 };

View File

@@ -345,16 +345,16 @@ namespace fgl::engine
FrustumBase createFrustum( const float aspect, const float fov_y, const float near, const float far )
{
const Plane< CoordinateSpace::Model > near_plane { ModelCoordinate( constants::WORLD_Y * near ),
NormalVector( constants::WORLD_Y ) };
const Plane< CoordinateSpace::Model > far_plane { ModelCoordinate( constants::WORLD_Y * far ),
NormalVector( constants::WORLD_Y_NEG ) };
const Plane< CoordinateSpace::Model > near_plane { ModelCoordinate( constants::WORLD_FORWARD * near ),
NormalVector( constants::WORLD_FORWARD ) };
const Plane< CoordinateSpace::Model > far_plane { ModelCoordinate( constants::WORLD_FORWARD * far ),
NormalVector( -constants::WORLD_FORWARD ) };
const float half_height { far * glm::tan( fov_y / 2.0f ) };
const float half_width { half_height * aspect };
const ModelCoordinate far_forward { constants::WORLD_Y * far };
const ModelCoordinate right_half { constants::WORLD_X * half_width };
const ModelCoordinate far_forward { constants::WORLD_FORWARD * far };
const ModelCoordinate right_half { constants::WORLD_RIGHT * half_width };
const Vector right_forward { ( far_forward + right_half ).vec() };
const Vector left_forward { ( far_forward - right_half ).vec() };
@@ -375,12 +375,12 @@ namespace fgl::engine
const Plane< CoordinateSpace::Model > top_plane {
ModelCoordinate( constants::WORLD_CENTER ),
NormalVector( glm::cross( top_forward.vec(), constants::WORLD_X ) )
NormalVector( glm::cross( top_forward.vec(), constants::WORLD_RIGHT ) )
};
const Plane< CoordinateSpace::Model > bottom_plane {
ModelCoordinate( constants::WORLD_CENTER ),
NormalVector( glm::cross( bottom_forward.vec(), constants::WORLD_X_NEG ) )
NormalVector( glm::cross( bottom_forward.vec(), -constants::WORLD_RIGHT ) )
};
return { near_plane,

View File

@@ -18,16 +18,16 @@ namespace fgl::engine::constants
constexpr glm::vec3 WORLD_CENTER { 0.0f, 0.0f, 0.0f };
// X RIGHT
constexpr glm::vec3 WORLD_RIGHT { 1.0f, 0.0f, 0.0f };
constexpr glm::vec3 WORLD_LEFT { -WORLD_RIGHT };
constexpr glm::vec3 WORLD_X { 1.0f, 0.0f, 0.0f };
constexpr glm::vec3 WORLD_X_NEG { -WORLD_X };
// Y FORWARD
constexpr glm::vec3 WORLD_FORWARD { 0.0f, 1.0f, 0.0f };
constexpr glm::vec3 WORLD_BACKWARD { -WORLD_FORWARD };
constexpr glm::vec3 WORLD_Y { 0.0f, 1.0f, 0.0f };
constexpr glm::vec3 WORLD_Y_NEG { -WORLD_Y };
// Z UP
constexpr glm::vec3 WORLD_UP { 0.0f, 0.0f, 1.0f };
constexpr glm::vec3 WORLD_DOWN { -WORLD_UP };
constexpr glm::vec3 WORLD_Z { 0.0f, 0.0f, 1.0f };
constexpr glm::vec3 WORLD_Z_NEG { -WORLD_Z };
constexpr float DEFAULT_FLOAT { std::numeric_limits< float >::max() };
@@ -42,4 +42,8 @@ namespace fgl::engine::constants
constexpr glm::mat4 MAT4_IDENTITY { 1.0f };
constexpr glm::mat3 MAT3_IDENTITY { 1.0f };
constexpr glm::vec3 WORLD_FORWARD { WORLD_X };
constexpr glm::vec3 WORLD_RIGHT { WORLD_Y };
constexpr glm::vec3 WORLD_UP { WORLD_Z };
} // namespace fgl::engine::constants

View File

@@ -12,24 +12,39 @@
namespace fgl::engine::debug
{
void drawLine( const LineSegment< CoordinateSpace::World >& line )
void drawLine( const LineSegment< CoordinateSpace::World >& line, const glm::vec3 color )
{
drawLine( line.getStart(), line.getEnd() );
}
void drawBoundingBox( const AxisAlignedBoundingBox< CoordinateSpace::World >& bounding_box )
void drawBoundingBox( const AxisAlignedBoundingBox< CoordinateSpace::World >& bounding_box, const glm::vec3 color )
{
for ( const auto& line : bounding_box.lines() )
{
drawLine( line.getStart(), line.getEnd() );
drawLine( line.getStart(), line.getEnd(), color );
}
}
void drawBoundingBox( const OrientedBoundingBox< CoordinateSpace::World >& bounding_box )
{
constexpr glm::vec3 bounding_box_color { 1.0f, 0.0f, 0.0f };
for ( const auto& line : bounding_box.lines() )
{
drawLine( line.getStart(), line.getEnd() );
drawLine( line.getStart(), line.getEnd(), bounding_box_color );
}
}
void drawAxisHelper()
{
constexpr WorldCoordinate center { constants::WORLD_CENTER };
constexpr WorldCoordinate right { constants::WORLD_X };
constexpr WorldCoordinate up { constants::WORLD_Z };
constexpr WorldCoordinate forward { constants::WORLD_Y };
drawLine( center, right, constants::WORLD_X );
drawLine( center, up, constants::WORLD_Z );
drawLine( center, forward, constants::WORLD_Y );
}
} // namespace fgl::engine::debug

View File

@@ -10,12 +10,14 @@
namespace fgl::engine::debug
{
void drawLine( const WorldCoordinate& p1, const WorldCoordinate& p2 );
void drawLine( const WorldCoordinate& p1, const WorldCoordinate& p2, glm::vec3 color = { 1.0f, 1.0f, 1.0f } );
void drawLine( const LineSegment< CoordinateSpace::World >& line );
void drawLine( const LineSegment< CoordinateSpace::World >& line, glm::vec3 color = { 1.0f, 1.0f, 1.0f } );
void drawBoundingBox( const AxisAlignedBoundingBox< CoordinateSpace::World >& bounding_box );
void drawBoundingBox( const OrientedBoundingBox< CoordinateSpace::World >& bounding_box );
void drawFrustum( const Frustum& frustum );
void drawAxisHelper();
} // namespace fgl::engine::debug

View File

@@ -38,17 +38,17 @@ namespace fgl::engine
if ( changed[ Pitch ] )
{
rot.pitch() = dat[ Pitch ];
rot.setX( dat[ Pitch ] );
}
if ( changed[ Roll ] )
{
rot.roll() = dat[ Roll ];
rot.setZ( dat[ Roll ] );
}
if ( changed[ Yaw ] )
{
rot.yaw() = dat[ Yaw ];
rot.setY( dat[ Yaw ] );
}
}

View File

@@ -18,12 +18,12 @@ namespace fgl::engine
//! Frustum constructed in model space (To be translated to a World space frustum later)
struct FrustumBase
{
ModelPlane near { ModelCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_FORWARD ) };
ModelPlane far { ModelCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_FORWARD ) };
ModelPlane top { ModelCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_FORWARD ) };
ModelPlane bottom { ModelCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_FORWARD ) };
ModelPlane right { ModelCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_FORWARD ) };
ModelPlane left { ModelCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_FORWARD ) };
ModelPlane near { ModelCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_Y ) };
ModelPlane far { ModelCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_Y ) };
ModelPlane top { ModelCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_Y ) };
ModelPlane bottom { ModelCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_Y ) };
ModelPlane right { ModelCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_Y ) };
ModelPlane left { ModelCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_Y ) };
ModelCoordinate m_position {};
@@ -49,12 +49,12 @@ namespace fgl::engine
struct Frustum
{
WorldPlane near { WorldCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_FORWARD ) };
WorldPlane far { WorldCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_FORWARD ) };
WorldPlane top { WorldCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_FORWARD ) };
WorldPlane bottom { WorldCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_FORWARD ) };
WorldPlane right { WorldCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_FORWARD ) };
WorldPlane left { WorldCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_FORWARD ) };
WorldPlane near { WorldCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_Y ) };
WorldPlane far { WorldCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_Y ) };
WorldPlane top { WorldCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_Y ) };
WorldPlane bottom { WorldCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_Y ) };
WorldPlane right { WorldCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_Y ) };
WorldPlane left { WorldCoordinate( constants::WORLD_CENTER ), NormalVector( constants::WORLD_Y ) };
WorldCoordinate m_position {};

View File

@@ -5,237 +5,45 @@
#include "Rotation.hpp"
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtx/quaternion.hpp>
#include <stdexcept>
namespace fgl::engine
{
Rotation::Rotation() : Rotation( 0.0f, 0.0f, 0.0f )
Rotation::Rotation() : Rotation( 0.0f )
{}
inline glm::quat buildQuat( const glm::vec3 euler )
glm::quat toQuat( const float roll, const float pitch, const float yaw )
{
// euler should be in `pitch, roll, yaw` order
const auto pitch { glm::angleAxis( euler.x, constants::WORLD_RIGHT ) };
const auto roll { glm::angleAxis( euler.y, constants::WORLD_FORWARD ) };
const auto yaw { glm::angleAxis( euler.z, constants::WORLD_UP ) };
/*
const glm::vec3 euler { x / 2.0f, y / 2.0f, z / 2.0f };
const glm::vec3 sin { glm::sin( euler ) };
const glm::vec3 cos { glm::cos( euler ) };
return pitch * roll * yaw;
glm::quat q {};
q.w = cos.x * cos.y * cos.z + sin.x * sin.y * sin.z;
q.x = sin.x * cos.y * cos.z - cos.x * sin.y * sin.z;
q.y = cos.x * sin.y * cos.z + sin.x * cos.y * sin.z;
q.z = cos.x * cos.y * sin.z - sin.x * sin.y * cos.z;
*/
const glm::quat identity { 1.0f, 0.0f, 0.0f, 0.0f };
const glm::quat q_x { glm::rotate( identity, roll, constants::WORLD_X ) }; // Roll
const glm::quat q_y { glm::rotate( identity, pitch, constants::WORLD_Y ) }; // Pitch
const glm::quat q_z { glm::rotate( identity, yaw, constants::WORLD_Z ) }; // Yaw
const glm::quat q { q_z * q_y * q_x };
return q;
}
inline float pitch( const glm::quat& q )
{
const float y { 2.0f * ( q.y * q.z + q.w * q.x ) };
const float x { q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z };
Rotation::Rotation( const float x, const float y, const float z ) : glm::quat( toQuat( x, y, z ) )
{}
if ( glm::all( glm::equal( glm::vec2( x, y ), glm::vec2( 0.0f ), glm::epsilon< float >() ) ) ) return 0.0f;
return glm::atan( y, x );
}
inline float roll( const glm::quat& q )
{
return std::asin( glm::clamp( -2.0f * ( q.x * q.z - q.w * q.y ), -1.0f, 1.0f ) );
}
inline float yaw( const glm::quat& q )
{
const float y { 2.0f * ( q.x * q.y + q.w * q.z ) };
const float x { q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z };
if ( glm::all( glm::equal( glm::vec2( x, y ), glm::vec2( 0.0f ), glm::epsilon< float >() ) ) ) return 0.0f;
return glm::atan( y, x );
}
inline glm::vec3 eulerAngles( const glm::quat& quat )
{
return { pitch( quat ), roll( quat ), yaw( quat ) };
}
// Because of how glm does stuff. We need to invert the roll.
Rotation::Rotation( const float pitch, const float roll, const float yaw ) :
glm::quat( buildQuat( { pitch, roll, yaw } ) )
{
FGL_ASSERT(
::fgl::engine::pitch( *this ) - pitch < glm::epsilon< float >(), "Rotation axis does not match input" );
FGL_ASSERT( ::fgl::engine::yaw( *this ) - yaw < glm::epsilon< float >(), "Rotation axis does not match input" );
FGL_ASSERT(
::fgl::engine::roll( *this ) - roll < glm::epsilon< float >(), "Rotation axis does not match input" );
}
RotationModifier< RotationModifierType::Roll > Rotation::roll()
{
return RotationModifier< RotationModifierType::Roll >( *this );
}
ConstRotationModifier< RotationModifierType::Pitch > Rotation::pitch() const
{
return ConstRotationModifier< RotationModifierType::Pitch >( *this );
}
RotationModifier< RotationModifierType::Pitch > Rotation::pitch()
{
return RotationModifier< RotationModifierType::Pitch >( *this );
}
ConstRotationModifier< RotationModifierType::Roll > Rotation::roll() const
{
return ConstRotationModifier< RotationModifierType::Roll >( *this );
}
RotationModifier< RotationModifierType::Yaw > Rotation::yaw()
{
return RotationModifier< RotationModifierType::Yaw >( *this );
}
ConstRotationModifier< RotationModifierType::Yaw > Rotation::yaw() const
{
return ConstRotationModifier< RotationModifierType::Yaw >( *this );
}
template < RotationModifierType ModifierType, bool is_const >
Rotation& RotationModifier< ModifierType, is_const >::operator+=( const float scalar )
{
if constexpr ( is_const )
{
// We should never be in this function if we are attempting to modify a const rotation
FGL_UNREACHABLE();
}
else
{
const glm::quat modifier { glm::angleAxis( scalar, getModifierAxis< ModifierType >() ) };
switch ( ModifierType )
{
case Pitch:
[[fallthrough]];
case Roll:
rot = static_cast< glm::quat >( rot ) * modifier; // local
break;
case Yaw:
rot = modifier * static_cast< glm::quat >( rot ); // global
break;
default:
FGL_UNREACHABLE();
}
return rot;
}
}
template < RotationModifierType ModifierType, bool is_const >
Rotation& RotationModifier< ModifierType, is_const >::operator-=( const float scalar )
{
if constexpr ( is_const )
{
// We should never be in this function if we are attempting to modify a const rotation
FGL_UNREACHABLE();
}
else
{
const auto modifier { glm::angleAxis( -scalar, getModifierAxis< ModifierType >() ) };
switch ( ModifierType )
{
case Pitch:
[[fallthrough]];
case Roll:
rot = static_cast< glm::quat >( rot ) * modifier; // local
break;
case Yaw:
rot = modifier * static_cast< glm::quat >( rot ); // global
break;
default:
FGL_UNREACHABLE();
}
return rot;
}
}
template < RotationModifierType ModifierType, bool is_const >
Rotation& RotationModifier< ModifierType, is_const >::operator=( const float scalar )
{
if constexpr ( is_const )
{
// We should never be in this function if we are attempting to modify a const rotation
FGL_UNREACHABLE();
}
else
{
glm::vec3 euler { ::fgl::engine::eulerAngles( rot ) };
switch ( ModifierType )
{
default:
FGL_UNREACHABLE();
case Pitch:
euler.x = scalar;
break;
case Roll:
euler.y = scalar;
break;
case Yaw:
euler.z = scalar;
break;
}
rot = { euler };
return rot;
}
}
template < RotationModifierType ModifierType, bool is_const >
FGL_FORCE_INLINE_FLATTEN inline RotationModifier< ModifierType, is_const >::operator float() const
{
return value();
}
template < RotationModifierType ModifierType, bool is_const >
float RotationModifier< ModifierType, is_const >::value() const
{
switch ( ModifierType )
{
default:
FGL_UNREACHABLE();
case Pitch:
return glm::pitch( rot );
case Roll:
return glm::roll( rot );
case Yaw:
return glm::yaw( rot );
}
FGL_UNREACHABLE();
}
glm::vec3 Rotation::euler() const
{
return { pitch(), roll(), yaw() };
}
Rotation& Rotation::operator=( const Rotation& rotation )
{
glm::quat::operator=( rotation );
return *this;
}
Rotation& Rotation::operator=( const glm::quat& rotation )
{
glm::quat::operator=( rotation );
return *this;
}
Rotation& Rotation::operator+=( const Rotation& rotation )
{
glm::quat::operator+=( rotation );
*this = glm::normalize( *this );
return *this;
}
Rotation::Rotation( const float value ) : Rotation( value, value, value )
{}
NormalVector Rotation::forward() const
{
@@ -252,21 +60,62 @@ namespace fgl::engine
return mat() * NormalVector( constants::WORLD_UP );
}
RotationMatrix Rotation::mat() const
glm::vec3 Rotation::euler() const
{
return { glm::mat3_cast( *this ) };
return { xAngle(), yAngle(), zAngle() };
}
Rotation Rotation::operator*( const Rotation& other ) const
float Rotation::xAngle() const
{
return Rotation( glm::normalize( static_cast< glm::quat >( *this ) * static_cast< glm::quat >( other ) ) );
//Extract X angle from quaternion
const float sinr_cosp { 2.0f * ( w * x + y * z ) };
const float cosr_cosp { 1.0f - 2.0f * ( x * x + y * y ) };
return std::atan2( sinr_cosp, cosr_cosp );
}
template class RotationModifier< RotationModifierType::Pitch, false >;
template class RotationModifier< RotationModifierType::Roll, false >;
template class RotationModifier< RotationModifierType::Yaw, false >;
template class RotationModifier< RotationModifierType::Pitch, true >;
template class RotationModifier< RotationModifierType::Roll, true >;
template class RotationModifier< RotationModifierType::Yaw, true >;
float Rotation::yAngle() const
{
// Extract Y angle from quaternion
const float sinp { std::sqrt( 1.0f + 2.0f * ( w * y - x * z ) ) };
const float cosp { std::sqrt( 1.0f - 2.0f * ( w * y - x * z ) ) };
return 2.0f * std::atan2( sinp, cosp ) - std::numbers::pi_v< float > / 2.0f;
}
float Rotation::zAngle() const
{
// Extract Z angle from quaternion
const float siny_cosp { 2.0f * ( w * z + x * y ) };
const float cosy_cosp { 1.0f - 2.0f * ( y * y + z * z ) };
return std::atan2( siny_cosp, cosy_cosp );
}
void Rotation::setX( const float value )
{}
void Rotation::setY( const float value )
{}
void Rotation::setZ( const float value )
{}
void Rotation::addX( const float value )
{
const glm::quat q { glm::angleAxis( value, constants::WORLD_X ) };
*this = *this * q;
}
void Rotation::addY( const float value )
{
// Because the camera is flipped. We must also flip the pitch rotation
const glm::quat q { glm::angleAxis( value, -constants::WORLD_Y ) };
*this = *this * q;
}
void Rotation::addZ( const float value )
{
const glm::quat q { glm::angleAxis( value, constants::WORLD_Z ) };
*this = *this * q;
}
} // namespace fgl::engine

View File

@@ -11,6 +11,9 @@
#include <glm/gtc/quaternion.hpp>
#pragma GCC diagnostic pop
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtx/quaternion.hpp>
#include <numbers>
#include <utility>
@@ -25,128 +28,52 @@ namespace fgl::engine
namespace fgl::engine
{
enum class RotationModifierType
struct Rotation : private glm::quat
{
Pitch = 0,
Roll = 1,
Yaw = 2,
};
struct Rotation;
template < RotationModifierType ModifierType, bool is_const = false >
class RotationModifier;
template < RotationModifierType ModifierType >
using ConstRotationModifier = RotationModifier< ModifierType, true >;
struct Rotation : public glm::quat
{
template < RotationModifierType ModifierType, bool is_const >
friend class RotationModifier;
Rotation();
explicit Rotation( float pitch, float roll, float yaw );
Rotation( float x, float y, float z );
Rotation( const Rotation& other ) = default;
Rotation( float value );
explicit Rotation( const glm::quat other ) : glm::quat( glm::normalize( other ) ) {}
Rotation( const glm::quat& quat ) : glm::quat( quat ) {}
explicit Rotation( const float scalar ) : Rotation( scalar, scalar, scalar ) {}
enum RotationReference
{
Local,
Global
};
RotationModifier< RotationModifierType::Pitch > pitch();
ConstRotationModifier< RotationModifierType::Pitch > pitch() const;
RotationModifier< RotationModifierType::Roll > roll();
ConstRotationModifier< RotationModifierType::Roll > roll() const;
RotationModifier< RotationModifierType::Yaw > yaw();
ConstRotationModifier< RotationModifierType::Yaw > yaw() const;
glm::vec3 euler() const;
Rotation& operator=( const Rotation& rotation );
Rotation& operator=( const glm::quat& rotation );
Rotation& operator+=( const Rotation& rotation );
RotationMatrix mat() const { return { glm::toMat3( *this ) }; }
NormalVector forward() const;
NormalVector back() const { return -forward(); }
NormalVector right() const;
NormalVector left() const { return -right(); }
NormalVector up() const;
NormalVector down() const { return -up(); }
glm::vec3 euler() const;
float xAngle() const;
float yAngle() const;
float zAngle() const;
RotationMatrix mat() const;
void setX( float );
void setY( float );
void setZ( float );
Rotation operator*( const Rotation& other ) const;
void addX( float );
void addY( float );
void addZ( float );
bool operator==( const Rotation& other ) const = default;
// internal
inline glm::quat internal_quat() const { return static_cast< glm::quat >( *this ); }
bool operator==( const Rotation& rot ) const
{
return static_cast< glm::quat >( *this ) == static_cast< glm::quat >( rot );
}
friend bool operator==( const Rotation&, const glm::quat& );
};
inline Rotation operator*( const glm::quat quat, const Rotation rotation )
inline bool operator==( const Rotation& rot, const glm::quat& quat )
{
return Rotation( quat * static_cast< glm::quat >( rotation ) );
return static_cast< glm::quat >( rot ) == quat;
}
template < RotationModifierType MT >
glm::vec3 getModifierAxis()
{
switch ( MT )
{
case RotationModifierType::Pitch:
return constants::WORLD_RIGHT;
case RotationModifierType::Roll:
return constants::WORLD_FORWARD;
case RotationModifierType::Yaw:
return -constants::WORLD_UP;
default:
FGL_UNREACHABLE();
}
FGL_UNREACHABLE();
}
template < RotationModifierType ModifierType, bool is_const >
class RotationModifier
{
using enum RotationModifierType;
using RotationType = std::conditional_t< is_const, const Rotation&, Rotation& >;
RotationType rot;
friend struct Rotation;
RotationModifier() = delete;
explicit RotationModifier( RotationType& i_rot ) : rot( i_rot ) {}
public:
Rotation& operator+=( const float scalar );
Rotation& operator-=( const float scalar );
Rotation& operator=( const float scalar );
operator float() const;
float value() const;
};
namespace constants
{
constexpr glm::vec3 DEFAULT_ROTATION { 0.0f, 0.0f, 0.0f };

View File

@@ -12,6 +12,8 @@ namespace fgl::engine
{
const glm::mat3 rotation_mat { rotation.mat() };
// We must flip the z axis in order to match vulkan. Where 0,0 is the top left of the screen and Z+ is down
return glm::mat4 { { scale.x * rotation_mat[ 0 ], 0.0f },
{ scale.y * rotation_mat[ 1 ], 0.0f },
{ scale.z * rotation_mat[ 2 ], 0.0f },

View File

@@ -64,7 +64,8 @@ namespace fgl::engine
{
const auto combined_matrix { matrix * transform.mat() };
[[maybe_unused]] glm::vec3 scale {}, translation {}, skew {};
glm::vec3 scale {}, translation {};
[[maybe_unused]] glm::vec3 skew {};
glm::quat quat {};
[[maybe_unused]] glm::vec4 perspective {};
glm::decompose( combined_matrix, scale, quat, translation, skew, perspective );

View File

@@ -147,6 +147,7 @@ namespace fgl::engine
}
}
/*
template < CoordinateSpace CType >
AxisAlignedBoundingBox< CType >& AxisAlignedBoundingBox< CType >::combine( const OrientedBoundingBox< CType >&
other )
@@ -160,6 +161,7 @@ namespace fgl::engine
return this->combine( aabb );
}
}
*/
template class AxisAlignedBoundingBox< CoordinateSpace::Model >;
template class AxisAlignedBoundingBox< CoordinateSpace::World >;

View File

@@ -46,7 +46,7 @@ namespace fgl::engine
explicit AxisAlignedBoundingBox( const OrientedBoundingBox< CType >& oobb );
AxisAlignedBoundingBox& combine( const AxisAlignedBoundingBox& other );
AxisAlignedBoundingBox& combine( const OrientedBoundingBox< CType >& other );
//AxisAlignedBoundingBox& combine( const OrientedBoundingBox< CType >& other );
bool operator==( const AxisAlignedBoundingBox< CType >& other ) const
{
@@ -67,11 +67,11 @@ namespace fgl::engine
std::array< Coordinate< CType >, POINT_COUNT > points() const;
std::array< LineSegment< CType >, LINE_COUNT > lines() const;
constexpr NormalVector right() const { return NormalVector( constants::WORLD_RIGHT ); }
constexpr NormalVector right() const { return NormalVector( constants::WORLD_X ); }
constexpr NormalVector up() const { return NormalVector( constants::WORLD_UP ); }
constexpr NormalVector up() const { return NormalVector( constants::WORLD_Z ); }
constexpr NormalVector forward() const { return NormalVector( constants::WORLD_FORWARD ); }
constexpr NormalVector forward() const { return NormalVector( constants::WORLD_Y ); }
};
} // namespace fgl::engine

View File

@@ -28,11 +28,11 @@ namespace fgl::engine
float span() const { return this->scale().x; }
constexpr NormalVector right() const { return NormalVector( constants::WORLD_RIGHT ); }
constexpr NormalVector right() const { return NormalVector( constants::WORLD_X ); }
constexpr NormalVector up() const { return NormalVector( constants::WORLD_UP ); }
constexpr NormalVector up() const { return NormalVector( constants::WORLD_Z ); }
constexpr NormalVector forward() const { return NormalVector( constants::WORLD_FORWARD ); }
constexpr NormalVector forward() const { return NormalVector( constants::WORLD_Y ); }
};
} // namespace fgl::engine

View File

@@ -8,6 +8,7 @@
#include <array>
#include "AxisAlignedBoundingBox.hpp"
#include "engine/assets/model/ModelVertex.hpp"
#include "engine/debug/logging/logging.hpp"
#include "engine/primitives/lines/LineSegment.hpp"
@@ -196,6 +197,27 @@ namespace fgl::engine
return generateBoundingFromPoints< CType >( combined_points );
}
template < CoordinateSpace CType >
AxisAlignedBoundingBox< CType > OrientedBoundingBox< CType >::alignToWorld()
{
const auto points { this->points() };
glm::vec3 max { std::numeric_limits< glm::vec3::type >::infinity() };
glm::vec3 min { -std::numeric_limits< glm::vec3::type >::infinity() };
for ( const auto& point : points )
{
max.x = glm::max( max.x, point.x );
max.y = glm::max( max.y, point.y );
max.z = glm::max( max.z, point.z );
min.x = glm::min( min.x, point.x );
min.y = glm::min( min.y, point.y );
min.z = glm::min( min.z, point.z );
}
return AxisAlignedBoundingBox< CType >( Coordinate< CType >( max ), Coordinate< CType >( min ) );
}
template < CoordinateSpace CType >
std::array< LineSegment< CType >, interface::BoundingBox::LINE_COUNT > OrientedBoundingBox< CType >::lines() const
{
@@ -229,25 +251,38 @@ namespace fgl::engine
{
ZoneScoped;
constexpr auto inf_float { std::numeric_limits< float >::infinity() };
// neg (min)
glm::vec3 top_right_forward { points[ 0 ].vec() };
glm::vec3 top_right_forward { -inf_float };
// pos (max)
glm::vec3 bottom_left_back { points[ 0 ].vec() };
glm::vec3 bottom_left_back { inf_float };
assert( points.size() > 0 );
for ( const auto& pos : points )
{
top_right_forward.x = std::max( pos.vec().x, top_right_forward.x );
top_right_forward.y = std::max( pos.vec().y, top_right_forward.y );
top_right_forward.z = std::max( pos.vec().z, top_right_forward.z );
const auto vec { pos.vec() };
top_right_forward.x = std::max( vec.x, top_right_forward.x );
top_right_forward.y = std::max( vec.y, top_right_forward.y );
top_right_forward.z = std::max( vec.z, top_right_forward.z );
bottom_left_back.x = std::min( pos.vec().x, bottom_left_back.x );
bottom_left_back.y = std::min( pos.vec().y, bottom_left_back.y );
bottom_left_back.z = std::min( pos.vec().z, bottom_left_back.z );
bottom_left_back.x = std::min( vec.x, bottom_left_back.x );
bottom_left_back.y = std::min( vec.y, bottom_left_back.y );
bottom_left_back.z = std::min( vec.z, bottom_left_back.z );
}
assert( top_right_forward.x != -inf_float );
assert( top_right_forward.y != -inf_float );
assert( top_right_forward.z != -inf_float );
assert( bottom_left_back.x != inf_float );
assert( bottom_left_back.y != inf_float );
assert( bottom_left_back.z != inf_float );
//Calculate midpoint
const glm::vec3 midpoint { ( top_right_forward + bottom_left_back ) / glm::vec3( 2.0f ) };
const glm::vec3 scale { bottom_left_back - midpoint };
const glm::vec3 scale { glm::abs( bottom_left_back - midpoint ) };
return { Coordinate< CType >( midpoint ), scale };
}
@@ -256,10 +291,12 @@ namespace fgl::engine
{
assert( verts.size() > 0 );
log::debug( "Generating bounding box for {} verts", verts.size() );
constexpr auto inf_float { std::numeric_limits< float >::infinity() };
// neg (min)
glm::vec3 top_right_forward { verts[ 0 ].m_position };
glm::vec3 top_right_forward { -inf_float };
// pos (max)
glm::vec3 bottom_left_back { verts[ 0 ].m_position };
glm::vec3 bottom_left_back { inf_float };
for ( const auto& vert : verts )
{
@@ -273,9 +310,17 @@ namespace fgl::engine
bottom_left_back.z = std::min( pos.z, bottom_left_back.z );
}
assert( top_right_forward.x != -inf_float );
assert( top_right_forward.y != -inf_float );
assert( top_right_forward.z != -inf_float );
assert( bottom_left_back.x != inf_float );
assert( bottom_left_back.y != inf_float );
assert( bottom_left_back.z != inf_float );
//Calculate midpoint
const glm::vec3 midpoint { ( top_right_forward + bottom_left_back ) / glm::vec3( 2.0f ) };
const glm::vec3 scale { bottom_left_back - midpoint };
const glm::vec3 scale { glm::abs( bottom_left_back - midpoint ) };
return OrientedBoundingBox< CoordinateSpace::Model >( Coordinate< CoordinateSpace::Model >( midpoint ), scale );
}

View File

@@ -21,6 +21,9 @@ namespace fgl::engine
template < CoordinateSpace CType >
class LineSegment;
template < CoordinateSpace CType >
class AxisAlignedBoundingBox;
struct ModelVertex;
template < CoordinateSpace CType >
@@ -71,7 +74,11 @@ namespace fgl::engine
NormalVector up() const { return m_transform.up(); }
Coordinate< CType > center() { return m_transform.translation; }
OrientedBoundingBox combine( const OrientedBoundingBox& other ) const;
AxisAlignedBoundingBox< CType > alignToWorld();
};
template < CoordinateSpace CType, MatrixType MType >
@@ -81,9 +88,9 @@ namespace fgl::engine
assert( bounding_box.m_transform.translation.vec() != constants::DEFAULT_VEC3 );
assert( bounding_box.m_transform.scale != glm::vec3( 0.0f ) );
const auto new_transform { matrix * bounding_box.m_transform };
const TransformComponent< EvolvedType< MType >() > new_transform { matrix * bounding_box.m_transform };
return OrientedBoundingBox< EvolvedType< MType >() >( new_transform );
return { new_transform };
}
OrientedBoundingBox< CoordinateSpace::Model > generateBoundingFromVerts( const std::vector< ModelVertex >& verts );

View File

@@ -4,6 +4,7 @@
#pragma once
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/matrix_decompose.hpp>
#include <glm/mat4x4.hpp>
@@ -54,32 +55,31 @@ namespace fgl::engine
//Lines
template < CoordinateSpace CType, MatrixType MType >
requires can_be_evolved< CType, MType >
LineSegment< EvolvedType< MType >() > operator*( const Matrix< MType > mat, const LineSegment< CType > );
LineSegment< EvolvedType< MType >() > operator*( Matrix< MType > mat, LineSegment< CType > );
template < CoordinateSpace CType, MatrixType MType >
InfiniteLine< EvolvedType< MType >() > operator*( const Matrix< MType > mat, const InfiniteLine< CType > );
InfiniteLine< EvolvedType< MType >() > operator*( Matrix< MType > mat, InfiniteLine< CType > );
//Planes
template < CoordinateSpace CType, MatrixType MType >
requires can_be_evolved< CType, MType >
OriginDistancePlane< EvolvedType< MType >() >
operator*( const Matrix< MType > mat, const OriginDistancePlane< CType > );
OriginDistancePlane< EvolvedType< MType >() > operator*( Matrix< MType > mat, OriginDistancePlane< CType > );
template < CoordinateSpace CType, MatrixType MType >
requires can_be_evolved< CType, MType >
PointPlane< EvolvedType< MType >() > operator*( const Matrix< MType > mat, const PointPlane< CType > );
PointPlane< EvolvedType< MType >() > operator*( Matrix< MType > mat, PointPlane< CType > );
//Coordinates
template < CoordinateSpace CType, MatrixType MType >
requires can_be_evolved< CType, MType >
Coordinate< EvolvedType< MType >() > operator*( const Matrix< MType > mat, const Coordinate< CType > );
Coordinate< EvolvedType< MType >() > operator*( Matrix< MType > mat, Coordinate< CType > );
//Vector
template < MatrixType MType >
Vector operator*( const Matrix< MType > mat, const Vector vec );
Vector operator*( Matrix< MType > mat, Vector vec );
template < MatrixType MType >
NormalVector operator*( const Matrix< MType > mat, const NormalVector );
NormalVector operator*( Matrix< MType > mat, NormalVector );
inline Matrix< MatrixType::WorldToScreen >
operator*( const Matrix< MatrixType::CameraToScreen > lhs, const Matrix< MatrixType::WorldToCamera > rhs )

View File

@@ -13,7 +13,7 @@ namespace fgl::engine
template < CoordinateSpace CType >
OriginDistancePlane< CType >::OriginDistancePlane() :
m_distance( std::numeric_limits< float >::infinity() ),
m_direction( constants::WORLD_FORWARD )
m_direction( constants::WORLD_Y )
{}
template < CoordinateSpace CType >

View File

@@ -12,7 +12,7 @@ namespace fgl::engine
template < CoordinateSpace CType >
PointPlane< CType >::PointPlane() :
coordinate( constants::WORLD_CENTER ),
vector( NormalVector( constants::WORLD_FORWARD ) )
vector( NormalVector( constants::WORLD_Y ) )
{}
template < CoordinateSpace CType >

View File

@@ -44,7 +44,7 @@ namespace fgl::engine
constexpr explicit Vector( const float i_x, const float i_y, const float i_z ) : glm::vec3( i_x, i_y, i_z ) {}
glm::vec3 right( const Vector up = Vector( constants::WORLD_UP ) ) const;
glm::vec3 right( const Vector up = Vector( constants::WORLD_Z ) ) const;
glm::vec3 forward() const;
Vector operator*( const float scalar ) const { return Vector( static_cast< glm::vec3 >( *this ) * scalar ); }

View File

@@ -43,7 +43,7 @@ namespace fgl::engine
info.rasterization_info.rasterizerDiscardEnable = VK_FALSE;
info.rasterization_info.polygonMode = vk::PolygonMode::eFill;
info.rasterization_info.cullMode = vk::CullModeFlagBits::eBack;
info.rasterization_info.frontFace = vk::FrontFace::eCounterClockwise;
info.rasterization_info.frontFace = vk::FrontFace::eClockwise;
info.rasterization_info.depthBiasEnable = VK_FALSE;
info.rasterization_info.depthBiasConstantFactor = 0.0f;
info.rasterization_info.depthBiasClamp = 0.0f;

View File

@@ -5,10 +5,11 @@
#include "LineDrawer.hpp"
#include "engine/FrameInfo.hpp"
#include "engine/memory/buffers/vector/HostVector.hpp"
#include "engine/camera/CameraDescriptor.hpp"
#include "engine/assets/model/ModelVertex.hpp"
#include "engine/assets/model/SimpleVertex.hpp"
#include "engine/camera/CameraDescriptor.hpp"
#include "engine/debug/drawers.hpp"
#include "engine/memory/buffers/vector/HostVector.hpp"
#include "engine/primitives/points/Coordinate.hpp"
namespace fgl::engine
@@ -48,6 +49,8 @@ namespace fgl::engine
void LineDrawer::pass( FrameInfo& info )
{
debug::drawAxisHelper();
ZoneScopedN( "Debug line drawing" );
auto& command_buffer { setupSystem( info ) };
TracyVkZone( info.tracy_ctx, *command_buffer, "Draw debug lines" );
@@ -69,13 +72,15 @@ namespace fgl::engine
namespace debug
{
void drawLine( const WorldCoordinate& p1, const WorldCoordinate& p2 )
void drawLine( const WorldCoordinate& p1, const WorldCoordinate& p2, const glm::vec3 color )
{
VertexLine line {};
auto& [ p1v, p2v ] = line;
p1v.m_position = p1.vec();
p1v.m_color = color;
p2v.m_position = p2.vec();
p2v.m_color = color;
m_lines.emplace_back( std::move( line ) );
}

View File

@@ -1,8 +1,10 @@
#version 450
layout(location = 0) in vec3 in_color;
#include "include/gbuffer_out.glsl"
void main() {
out_albedo = vec4(1.0, (20.0 / 255.0), (147.0 / 255.0f), 1.0f);
out_albedo = vec4(in_color, 1.0f);
out_normal = vec4(1.0f);
}

View File

@@ -1,10 +1,14 @@
#version 450
layout(location = 0) in vec3 in_pos;
layout(location = 1) in vec3 in_color;
#include "include/camera.glsl"
layout(location = 0) out vec3 out_color;
void main()
{
gl_Position = ubo.projection * ubo.view * vec4(in_pos, 1.0);
out_color = in_color;
}

View File

@@ -12,8 +12,9 @@ if (FGL_ENABLE_TESTS)
set(CMAKE_CXX_STANDARD_REQUIRED 23)
add_executable(FGLTests ${FGL_TEST_SOURCES})
target_link_libraries(FGLTests PUBLIC FGLEngine Catch2::Catch2WithMain)
target_compile_definitions(FGLTests PUBLIC GLM_FORCE_RADIANS GLM_FORCE_DEPTH_ZERO_TO_ONE GLM_FORCE_LEFT_HANDED)
target_link_libraries(FGLTests PUBLIC FGLEngine)
target_link_libraries(FGLTests PRIVATE Catch2::Catch2WithMain)
target_compile_definitions(FGLTests PUBLIC GLM_FORCE_RADIANS GLM_FORCE_DEPTH_ZERO_TO_ONE)
target_compile_features(FGLTests PRIVATE cxx_std_23)
include(CTest)

View File

@@ -2,43 +2,58 @@
// Created by kj16609 on 2/14/24.
//
#include <catch2/catch_all.hpp>
#include "engine/assets/model/ModelVertex.hpp"
#include "engine/primitives/boxes/OrientedBoundingBox.hpp"
#include "gtest_printers.hpp"
using namespace fgl::engine;
#include <catch2/catch_all.hpp>
ModelVertex createTestVert( const float x, const float y, const float z )
{
ModelVertex vert {};
vert.m_position = { x, y, z };
#include "gtest_printers.hpp"
return vert;
}
TEST_CASE( "BoundingBox", "[boundingbox]" )
{
SECTION( "Combine test" )
{
std::vector< Coordinate< CoordinateSpace::Model > > model_points {};
std::vector< ModelVertex > model_points {};
// Top left
model_points.push_back( Coordinate< CoordinateSpace::Model >( -1.0f, 1.0f, 1.0f ) );
// Bottom right
model_points.push_back( Coordinate< CoordinateSpace::Model >( 1.0f, -1.0f, -1.0f ) );
model_points.push_back( createTestVert( 1.0f, 1.0f, 1.0f ) );
OrientedBoundingBox< CoordinateSpace::Model > model_box( generateBoundingFromPoints( model_points ) );
// Bottom right
model_points.push_back( createTestVert( -1.0f, -1.0f, -1.0f ) );
OrientedBoundingBox< CoordinateSpace::Model > model_box( generateBoundingFromVerts( model_points ) );
THEN( "The bounding box center must be at 0,0,0" )
{
REQUIRE( model_box.center().vec() == glm::vec3( 0.0f, 0.0f, 0.0f ) );
}
model_points.clear();
// Top left
model_points.push_back( Coordinate< CoordinateSpace::Model >( -2.0f, 1.0f, 2.0f ) );
// Bottom right
model_points.push_back( Coordinate< CoordinateSpace::Model >( 2.0f, -1.0f, -2.0f ) );
model_points.push_back( createTestVert( 2.0f, 1.0f, 2.0f ) );
OrientedBoundingBox< CoordinateSpace::Model > model_box2( generateBoundingFromPoints( model_points ) );
// Bottom right
model_points.push_back( createTestVert( -2.0f, -1.0f, -2.0f ) );
OrientedBoundingBox< CoordinateSpace::Model > model_box2( generateBoundingFromVerts( model_points ) );
auto combined_box = model_box.combine( model_box2 );
//Check that the points are correct
//The middle point should not change
REQUIRE( combined_box.middle == model_box.middle );
REQUIRE( combined_box.center() == model_box.center() );
//The scale should be the max of the two boxes
REQUIRE( combined_box.scale == glm::vec3( 2.0f, 1.0f, 2.0f ) );
REQUIRE( combined_box.m_transform.scale == glm::vec3( 2.0f, 1.0f, 2.0f ) );
//Check that the points are correct

View File

@@ -0,0 +1,175 @@
//
// Created by kj16609 on 9/28/24.
//
#include "catch2/catch_approx.hpp"
#include "catch2/catch_test_macros.hpp"
#include "catch2/matchers/catch_matchers.hpp"
#include "engine/primitives/Rotation.hpp"
#include "gtest_printers.hpp"
#include "operators/vector.hpp"
TEST_CASE( "Rotations", "[transform][rotation]" )
{
using namespace fgl::engine;
GIVEN( "A Default Rotation" )
{
Rotation rot {};
SECTION( "Check quat" )
{
glm::quat quat { rot.internal_quat() };
THEN( "Quat: w should be 1.0" )
{
REQUIRE( quat.w == Catch::Approx( 1.0 ) );
}
auto is_zero { Catch::Approx( 0.0 ) };
THEN( "Quat: x should be zero" )
{
REQUIRE( quat.x == is_zero );
}
THEN( "Quat: y should be zero" )
{
REQUIRE( quat.y == is_zero );
}
THEN( "Quat: z should be zero" )
{
REQUIRE( quat.z == is_zero );
}
}
THEN( "Forward should be WORLD_FORWARD" )
{
REQUIRE( rot.forward() == NormalVector( constants::WORLD_FORWARD ) );
}
THEN( "Right should be WORLD_RIGHT" )
{
REQUIRE( rot.right() == NormalVector( constants::WORLD_RIGHT ) );
}
THEN( "Up should be WORLD_UP" )
{
REQUIRE( rot.up() == NormalVector( constants::WORLD_UP ) );
}
THEN( "Euler X should be 0.0" )
{
REQUIRE( rot.xAngle() == Catch::Approx( 0.0 ) );
}
THEN( "Euler Y should be 0.0" )
{
REQUIRE( rot.yAngle() == Catch::Approx( 0.0 ) );
}
THEN( "Euler Z should be 0.0" )
{
REQUIRE( rot.zAngle() == Catch::Approx( 0.0 ) );
}
}
GIVEN( "A rotation with euler angles (X, 0.0f, 0.0f)" )
{
for ( float i = 0; i < 180.0f; i += 1.0f )
{
Rotation rot { glm::radians( i ), 0.0f, 0.0f };
INFO( "Euler Value: " << i );
INFO( "Euler X: " << rot.xAngle() );
INFO( "Euler Y: " << rot.yAngle() );
INFO( "Euler Z: " << rot.zAngle() );
INFO(
"Quat: (" << rot.internal_quat().w << ", " << rot.internal_quat().x << ", " << rot.internal_quat().y
<< ", " << rot.internal_quat().z << ")" );
THEN( "Euler X should be " << i )
{
REQUIRE( rot.xAngle() == Catch::Approx( glm::radians( i ) ) );
REQUIRE( rot.yAngle() == Catch::Approx( 0.0 ) );
REQUIRE( rot.zAngle() == Catch::Approx( 0.0 ) );
}
}
}
GIVEN( "A rotation with euler angles (0.0f, Y, 0.0f)" )
{
for ( float i = 0; i < 180.0f; i += 1.0f )
{
Rotation rot { 0.0f, glm::radians( i ), 0.0f };
INFO( "Euler Value: " << i );
INFO( "Euler X: " << rot.xAngle() );
INFO( "Euler Y: " << rot.yAngle() );
INFO( "Euler Z: " << rot.zAngle() );
INFO(
"Quat: (" << rot.internal_quat().w << ", " << rot.internal_quat().x << ", " << rot.internal_quat().y
<< ", " << rot.internal_quat().z << ")" );
THEN( "Euler Y should be " << i )
{
REQUIRE( rot.xAngle() == Catch::Approx( 0.0 ).epsilon( 0.1 ) );
REQUIRE( rot.yAngle() == Catch::Approx( glm::radians( i ) ).epsilon( 0.01 ) );
REQUIRE( rot.zAngle() == Catch::Approx( glm::radians( 0.0 ) ).epsilon( 0.01 ) );
}
}
}
GIVEN( "A rotation with euler angles (0.0f, 0.0f, Z)" )
{
for ( float i = 0; i < 180.0f; i += 1.0f )
{
Rotation rot { 0.0f, 0.0f, glm::radians( i ) };
INFO( "Euler Value: " << i );
INFO( "Euler X: " << rot.xAngle() );
INFO( "Euler Y: " << rot.yAngle() );
INFO( "Euler Z: " << rot.zAngle() );
INFO(
"Quat: (" << rot.internal_quat().w << ", " << rot.internal_quat().x << ", " << rot.internal_quat().y
<< ", " << rot.internal_quat().z << ")" );
THEN( "Euler Z should be " << i )
{
REQUIRE( rot.xAngle() == Catch::Approx( 0.0 ) );
REQUIRE( rot.yAngle() == Catch::Approx( 0.0 ) );
REQUIRE( rot.zAngle() == Catch::Approx( glm::radians( i ) ) );
}
}
}
GIVEN( "A rotation with euler angles (0.0f, Y, Z)" )
{
for ( float i = 0; i < 180.0f; i += 1.0f )
{
Rotation rot { 0.0f, glm::radians( i ), glm::radians( i ) };
INFO( "Euler Value: " << i );
INFO( "Euler X: " << rot.xAngle() );
INFO( "Euler Y: " << rot.yAngle() );
INFO( "Euler Z: " << rot.zAngle() );
INFO(
"Quat: (" << rot.internal_quat().w << ", " << rot.internal_quat().x << ", " << rot.internal_quat().y
<< ", " << rot.internal_quat().z << ")" );
THEN( "Euler Y should be " << i )
{
REQUIRE( rot.xAngle() == Catch::Approx( 0.0 ).epsilon( 0.1 ) );
REQUIRE( rot.yAngle() == Catch::Approx( glm::radians( i ) ).epsilon( 0.01 ) );
REQUIRE( rot.zAngle() == Catch::Approx( glm::radians( i ) ).epsilon( 0.01 ) );
}
}
}
}

View File

@@ -37,6 +37,63 @@ TEST_CASE( "Matrix", "[transform][rotation][translation][matrix]" )
}
*/
/*
TEST_CASE( "Quaternion Rotations", "[rotation]" )
{
SECTION( "Quaternion build from euler" )
{
// euler should be in `pitch, roll, yaw` order
const auto q_pitch { glm::angleAxis( 0.0f, constants::WORLD_RIGHT ) };
const auto q_roll { glm::angleAxis( 0.0f, constants::WORLD_FORWARD ) };
const auto q_yaw { glm::angleAxis( 0.0f, constants::WORLD_UP ) };
REQUIRE( q_pitch == glm::quat( 1.0f, 0.0f, 0.0f, 0.0f ) );
REQUIRE( q_pitch * q_roll == glm::quat( 1.0f, 0.0f, 0.0f, 0.0f ) );
REQUIRE( q_pitch * q_roll * q_yaw == glm::quat( 1.0f, 0.0f, 0.0f, 0.0f ) );
const Rotation rot { 0.0f, 0.0f, 0.0f };
REQUIRE( glm::quat( 1.0f, 0.0f, 0.0f, 0.0f ) == rot );
}
WHEN( "Building a quat with a 90.0f deg pitch" )
{
const glm::quat quat { fgl::engine::buildQuat( glm::radians( 90.0f ), 0.0f, 0.0f ) };
THEN( "The output of glm::yaw should be 90.0f deg" )
{
REQUIRE( glm::pitch( quat ) == Catch::Approx( glm::radians( 90.0f ) ) );
REQUIRE( glm::roll( quat ) == 0.0f );
REQUIRE( glm::yaw( quat ) == 0.0f );
}
}
WHEN( "Building a quat with a 90.0f deg roll" )
{
const glm::quat quat { fgl::engine::buildQuat( 0.0f, glm::radians( 90.0f ), 0.0f ) };
THEN( "The output of glm::roll should be 90.0f deg" )
{
REQUIRE( glm::pitch( quat ) == 0.0f );
REQUIRE( glm::roll( quat ) == Catch::Approx( glm::radians( 90.0f ) ) );
REQUIRE( glm::yaw( quat ) == 0.0f );
}
}
WHEN( "Building a quat with a 90.0f deg yaw" )
{
const glm::quat quat { fgl::engine::buildQuat( 0.0f, 0.0f, glm::radians( 90.0f ) ) };
THEN( "The output of glm::pitch should be 90.0f deg" )
{
REQUIRE( glm::pitch( quat ) == 0.0f );
REQUIRE( glm::roll( quat ) == 0.0f );
REQUIRE( glm::yaw( quat ) == Catch::Approx( glm::radians( 90.0f ) ).epsilon( 0.01f ) );
}
}
}
*/
TEST_CASE( "Transform", "[transform][rotation][translation]" )
{
TransformComponent component;
@@ -45,112 +102,7 @@ TEST_CASE( "Transform", "[transform][rotation][translation]" )
component.scale = glm::vec3( 1.0f );
component.rotation = Rotation( 0.0f );
constexpr auto TEST_POINT { constants::WORLD_FORWARD };
GIVEN( "A default rotation" )
{
THEN( "The rotation is (0,0,0)" )
{
REQUIRE( component.rotation.pitch() == 0.0f );
REQUIRE( component.rotation.yaw() == 0.0f );
REQUIRE( component.rotation.roll() == 0.0f );
}
THEN( "The rotation matrix is the identity matrix" )
{
REQUIRE( constants::MAT4_IDENTITY == component.mat4() );
}
// Tests behaviour that a point from WORLD_FORWARD should end up WORLD_UP when pitched 90 degrees
WHEN( "Rotated +90 Pitch" )
{
//Rotate by pitch
component.rotation.pitch() = glm::radians( 90.0f );
THEN( "Forward should be WORLD_UP" )
{
REQUIRE( component.forward() == NormalVector( constants::WORLD_UP ) );
}
THEN( "WORLD_FORWARD should be rotated to WORLD_UP" )
{
REQUIRE(
component.rotation.mat() * NormalVector( constants::WORLD_FORWARD )
== NormalVector( constants::WORLD_UP ) );
}
THEN( "Pitch should be 90.0f" )
{
REQUIRE( component.rotation.pitch() == glm::radians( 90.0f ) );
}
}
// Tests behaviour that a point from WORLD_FORWARD should end up WORLD_DOWN when pitched -90 degrees
WHEN( "Rotated -90 Pitch" )
{
component.rotation.pitch() = -glm::radians( 90.0f );
const glm::vec3 rotated_point { component.mat4() * glm::vec4( TEST_POINT, 1.0f ) };
THEN( "Forward should be WORLD_DOWN" )
{
REQUIRE( rotated_point == constants::WORLD_DOWN );
}
}
// Tests behaviour that a point from WORLD_FORWARD should end up WORLD_RIGHT when yawed 90 degrees
WHEN( "Rotated +90 Yaw" )
{
component.rotation.yaw() = glm::radians( 90.0f );
const glm::vec3 rotated_point { component.mat4() * glm::vec4( TEST_POINT, 1.0f ) };
THEN( "Forward should be WORLD_RIGHT" )
{
REQUIRE( rotated_point == constants::WORLD_RIGHT );
}
}
// Tests behaviour that a point from WORLD_FORWARD should end up WORLD_LEFT when yawed -90 degrees
WHEN( "Rotated -90 Yaw" )
{
component.rotation.yaw() = -glm::radians( 90.0f );
const glm::vec3 rotated_point { component.mat4() * glm::vec4( TEST_POINT, 1.0f ) };
THEN( "Forward should be WORLD_LEFT" )
{
REQUIRE( rotated_point == constants::WORLD_LEFT );
}
}
//Tests behaviour that a point from WORLD_RIGHT should end up WORLD_DOWN when rolled 90 degrees
//This behaviour assumes that WORLD_RIGHT is 90 deg YAW+ from WORLD_FORWARD
WHEN( "Rotated +90 Roll" )
{
component.rotation.roll() = glm::radians( 90.0f );
const glm::vec3 rotated_point { component.mat4() * glm::vec4( constants::WORLD_RIGHT, 1.0f ) };
THEN( "Forward should be WORLD_DOWN" )
{
REQUIRE( rotated_point == constants::WORLD_DOWN );
}
}
//Tests behaviour that a point from WORLD_RIGHT should end up WORLD_UP when rolled -90 degrees
WHEN( "Rotated -90 Roll" )
{
component.rotation.roll() = -glm::radians( 90.0f );
const glm::vec3 rotated_point { component.mat4() * glm::vec4( constants::WORLD_RIGHT, 1.0f ) };
THEN( "Forward should be WORLD_UP" )
{
REQUIRE( rotated_point == constants::WORLD_UP );
}
}
}
constexpr auto TEST_POINT { constants::WORLD_Y };
SECTION( "Translation" )
{
@@ -162,7 +114,7 @@ TEST_CASE( "Transform", "[transform][rotation][translation]" )
THEN( "Forward should be WORLD_FORWARD + WORLD_UP" )
{
REQUIRE( translated_point == constants::WORLD_FORWARD + constants::WORLD_UP );
REQUIRE( translated_point == constants::WORLD_Y + constants::WORLD_Z );
}
}
@@ -174,7 +126,7 @@ TEST_CASE( "Transform", "[transform][rotation][translation]" )
THEN( "Forward should be WORLD_FORWARD + WORLD_FORWARD" )
{
REQUIRE( translated_point == constants::WORLD_FORWARD + constants::WORLD_FORWARD );
REQUIRE( translated_point == constants::WORLD_Y + constants::WORLD_Y );
}
}
@@ -186,29 +138,30 @@ TEST_CASE( "Transform", "[transform][rotation][translation]" )
THEN( "Forward should be WORLD_FORWARD + WORLD_RIGHT" )
{
REQUIRE( translated_point == constants::WORLD_FORWARD + constants::WORLD_RIGHT );
REQUIRE( translated_point == constants::WORLD_Y + constants::WORLD_X );
}
}
}
/*
SECTION( "Mix" )
{
WHEN( "Translated X+1 and Rotated Y+90" )
{
component.rotation.yaw() = glm::radians( glm::radians( 90.0f ) );
component.rotation.yAngle() = glm::radians( glm::radians( 90.0f ) );
component.translation.right() += 1.0f;
const glm::vec3 translated_point { component.mat4() * glm::vec4( constants::WORLD_FORWARD, 1.0f ) };
const glm::vec3 translated_point { component.mat4() * glm::vec4( constants::WORLD_Y, 1.0f ) };
THEN( "WORLD_FORWARD should be transformed into (WORLD_RIGHT * 2)" )
{
REQUIRE( translated_point == ( constants::WORLD_RIGHT * 2.0f ) );
REQUIRE( translated_point == ( constants::WORLD_X * 2.0f ) );
}
}
SECTION( "Translated X+1 Yaw-90" )
{
component.rotation.yaw() = glm::radians( -glm::radians( 90.0f ) );
component.rotation.yAngle() = glm::radians( -glm::radians( 90.0f ) );
component.translation.right() += 1.0f;
const glm::vec3 translated_point { component.mat4() * glm::vec4( TEST_POINT, 1.0f ) };
@@ -219,4 +172,5 @@ TEST_CASE( "Transform", "[transform][rotation][translation]" )
}
}
}
*/
}

View File

@@ -1,218 +0,0 @@
//
// Created by kj16609 on 2/16/24.
//
#include <glm/gtc/epsilon.hpp>
#include <utility>
#include "engine/primitives/TransformComponent.hpp"
#include "engine/primitives/vectors/Vector.hpp"
#include "gtest_printers.hpp"
#include "operators/vector.hpp"
using namespace fgl::engine;
TEST_CASE( "Vector", "[vector][transforms]" )
{
WHEN( "Vector is default constructed" )
{
constexpr Vector vec {};
THEN( "X should be max floatf" )
{
REQUIRE( vec.x == constants::DEFAULT_FLOAT );
}
THEN( "Y should be max float" )
{
REQUIRE( vec.y == constants::DEFAULT_FLOAT );
}
THEN( "Z should be max float" )
{
REQUIRE( vec.z == constants::DEFAULT_FLOAT );
}
}
WHEN( "Rotated +90 yaw" )
{
Vector rotation_vec { NormalVector( constants::WORLD_FORWARD ) };
//Rotate by 90 degrees on yaw
TransformComponent transform;
transform.rotation.yaw() += glm::radians( 90.0f );
const Vector value { transform.mat() * rotation_vec };
THEN( "Forward should be WORLD_RIGHT" )
{
REQUIRE( value == Vector( constants::WORLD_RIGHT ) );
}
}
WHEN( "Rotated -90 yaw" )
{
Vector rotation_vec { NormalVector( constants::WORLD_FORWARD ) };
//Rotate by 90 degrees on yaw
TransformComponent transform;
transform.rotation.yaw() += glm::radians( -90.0f );
const Vector value { transform.mat() * rotation_vec };
THEN( "Forward should be WORLD_LEFT" )
{
REQUIRE( value == Vector( constants::WORLD_LEFT ) );
}
}
}
TEST_CASE( "Rotation", "[vector][transforms]" )
{
WHEN( "Rotation is default constructed" )
{
Rotation rot {};
THEN( "Should match a default quaternion" )
{
REQUIRE( static_cast< glm::quat >( rot ) == glm::quat( 1.0f, 0.0f, 0.0f, 0.0f ) );
}
THEN( "Yaw should be 0.0f" )
{
REQUIRE( rot.yaw() == 0.0f );
}
THEN( "Pitch should be 0.0f" )
{
REQUIRE( rot.pitch() == 0.0f );
}
THEN( "Roll should be 0.0f" )
{
REQUIRE( rot.roll() == 0.0f );
}
THEN( "Forward should be WORLD_FORWARD" )
{
REQUIRE( rot.forward() == NormalVector( constants::WORLD_FORWARD ) );
}
THEN( "Backwards should be WORLD_BACKWARD" )
{
REQUIRE( -rot.forward() == NormalVector( constants::WORLD_BACKWARD ) );
}
THEN( "Right should be WORLD_RIGHT" )
{
REQUIRE( rot.right() == NormalVector( constants::WORLD_RIGHT ) );
}
THEN( "Left should be WORLD_LEFT" )
{
REQUIRE( -rot.right() == NormalVector( constants::WORLD_LEFT ) );
}
}
GIVEN( "A rotation constructed" )
{
constexpr auto rad_90 { glm::radians( 90.0f ) };
AND_WHEN( "Given 90.0f pitch" )
{
Rotation rotation { rad_90, 0.0f, 0.0f };
THEN( "Pitch should return 90" )
{
REQUIRE( rotation.pitch() == Catch::Approx( rad_90 ).epsilon( 0.01 ) );
}
/*
THEN( "Quaternion should be valid" )
{
REQUIRE( static_cast< glm::quat >( rotation ) == glm::quat( 0.7071068, 0.7071068, 0, 0 ) );
}
*/
}
AND_WHEN( "Given 90.0f yaw" )
{
Rotation rotation { 0.0f, rad_90, 0.0f };
REQUIRE( rotation.yaw() == Catch::Approx( rad_90 ).epsilon( 0.01 ) );
}
AND_WHEN( "Given 90.0f roll" )
{
Rotation rotation { 0.0f, 0.0f, rad_90 };
REQUIRE( rotation.roll() == Catch::Approx( rad_90 ).epsilon( 0.01 ) );
}
}
GIVEN( "A default identity matrix" )
{
const Matrix< MatrixType::ModelToWorld > matrix { 1.0f };
THEN( "The matrix rot() function should match a default rotation" )
{
const Rotation default_rot {};
REQUIRE( default_rot.mat() == matrix.rotmat() );
}
WHEN( "Multiplied with a default rotation" )
{
THEN( "Nothing should happen" )
{}
}
}
SECTION( "Rotation transforms" )
{
WHEN( "Rotated +90 yaw from default" )
{
Rotation rot { 0.0f, 0.0f, glm::radians( 90.0f ) };
THEN( "Forward should be WORLD_RIGHT" )
{
REQUIRE( rot.forward() == NormalVector( constants::WORLD_RIGHT ) );
}
THEN( "Backwards should be WORLD_LEFT" )
{
REQUIRE( rot.back() == NormalVector( constants::WORLD_LEFT ) );
}
THEN( "Right should be WORLD_BACKWARD" )
{
REQUIRE( rot.right() == NormalVector( constants::WORLD_BACKWARD ) );
}
THEN( "Left should be WORLD_FORWARD" )
{
REQUIRE( rot.left() == NormalVector( constants::WORLD_FORWARD ) );
}
}
WHEN( "Rotated -90 yaw from default" )
{
Rotation rot { 0.0f, 0.0f, glm::radians( -90.0f ) };
THEN( "Forward should be WORLD_LEFT" )
{
REQUIRE( rot.forward() == NormalVector( constants::WORLD_LEFT ) );
}
THEN( "Backwards should be WORLD_RIGHT" )
{
REQUIRE( rot.back() == NormalVector( constants::WORLD_RIGHT ) );
}
THEN( "Right should be WORLD_FORWARD" )
{
REQUIRE( rot.right() == NormalVector( constants::WORLD_FORWARD ) );
}
THEN( "Left should be WORLD_BACKWARD" )
{
REQUIRE( rot.left() == NormalVector( constants::WORLD_BACKWARD ) );
}
}
}
}

View File

@@ -10,7 +10,9 @@
#include <glm/gtx/string_cast.hpp>
#include "engine/primitives/Rotation.hpp"
#include "engine/primitives/Scale.hpp"
#include "engine/primitives/matricies/Matrix.hpp"
#include "engine/primitives/points/Coordinate.hpp"
#include "engine/primitives/vectors/Vector.hpp"
namespace Catch
@@ -35,7 +37,7 @@ namespace Catch
{
static std::string convert( const fgl::engine::Rotation& rot )
{
return StringMaker< glm::vec3 >::convert( { rot.pitch(), rot.roll(), rot.yaw() } );
return StringMaker< glm::vec3 >::convert( { rot.xAngle(), rot.yAngle(), rot.zAngle() } );
}
};
@@ -68,7 +70,7 @@ namespace Catch
};
template <>
struct StringMaker< fgl::engine::NormalVector >
struct StringMaker< ::fgl::engine::NormalVector >
{
static std::string convert( const fgl::engine::NormalVector vec )
{
@@ -76,6 +78,24 @@ namespace Catch
}
};
template <>
struct StringMaker< ::fgl::engine::Scale >
{
static std::string convert( const fgl::engine::Scale scale )
{
return StringMaker< glm::vec3 >::convert( static_cast< glm::vec3 >( scale ) );
}
};
template <>
struct StringMaker< ::fgl::engine::ModelCoordinate >
{
static std::string convert( const fgl::engine::ModelCoordinate coord )
{
return StringMaker< glm::vec3 >::convert( coord.vec() );
}
};
} // namespace Catch
#ifndef NDEBUG