Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,17 @@ jobs:
run: cmake -E make_directory ${{runner.workspace}}/build

- name: Configure CMake
if: matrix.os != 'windows-latest'
shell: bash
working-directory: ${{runner.workspace}}/build
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE

- name: Configure Windows CMake
if: matrix.os == 'windows-latest'
working-directory: ${{runner.workspace}}/build
shell: bash
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -T ClangCL -A x64

- name: Build project
working-directory: ${{runner.workspace}}/build
shell: bash
Expand Down
10 changes: 8 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,20 @@ set(MATH_SOURCES source/aabb.cpp source/bvh.cpp)

add_library(math-static STATIC ${MATH_SOURCES})
target_include_directories(math-static PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_compile_definitions(math-static PUBLIC _USE_MATH_DEFINES NOMINMAX)
target_compile_definitions(math-static PUBLIC __STDC_WANT_IEC_60559_TYPES_EXT__)
if(WIN32)
target_compile_definitions(math-static PUBLIC _USE_MATH_DEFINES NOMINMAX)
endif()

if(MATH_BUILD_SHARED)
add_library(math-shared SHARED ${MATH_SOURCES})
set_target_properties(math-shared PROPERTIES
OUTPUT_NAME "math" WINDOWS_EXPORT_ALL_SYMBOLS ON)
target_include_directories(math-shared PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_compile_definitions(math-shared PUBLIC _USE_MATH_DEFINES NOMINMAX)
target_compile_definitions(math-shared PUBLIC __STDC_WANT_IEC_60559_TYPES_EXT__)
if(WIN32)
target_compile_definitions(math-shared PUBLIC _USE_MATH_DEFINES NOMINMAX)
endif()
endif()

if(MATH_BUILD_TESTS)
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ See the [documentation](https://cfnptr.github.io/math).

## Features

* Vector (float2/3/4, int2/3/4, half)
* Vector (float2/3/4, int2/3/4, half2/3/4)
* Types (byte, sbyte, short, ushort, int, uint, long, ulong)
* Matrix (float2x2/3x3/4x4)
* Quaternion (float4)
* SIMD optimized (f32x4, f32x4x4, f16x4)
* Quaternion rotations (float4)
* SIMD optimized (i32x4, f32x4, f32x4x4, f16x4)
* Euler angles/radians conversion
* Matrix translate, scale, rotate
* Perspective, orthographic projection
Expand Down
2 changes: 1 addition & 1 deletion include/math/color-space.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ static uint32 encodeB10G11R11(float value, uint32 bits, uint32 mask) noexcept
*/
static uint32 encodeB10G11R11(f32x4 rgb) noexcept
{
rgb = clamp(rgb, f32x4::zero, f32x4(FLOAT_BIG_16));
rgb = clamp(rgb, f32x4::zero, f32x4(FLT16_MAX));
auto r = encodeB10G11R11(rgb.getX(), 6, 0b111111);
auto g = encodeB10G11R11(rgb.getY(), 6, 0b111111);
auto b = encodeB10G11R11(rgb.getZ(), 5, 0b11111);
Expand Down
74 changes: 58 additions & 16 deletions include/math/color.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,23 @@ struct [[nodiscard]] Color
/**
* @brief Creates a new sRGB color structure.
*
* @param rgb red green and blue channel color value
* @param rgb red, green and blue channel color value
* @param a alpha channel color value (transparency)
*/
constexpr Color(Color rgb, uint8 a) noexcept : r(rgb.r), g(rgb.g), b(rgb.b), a(a) { }
/**
* @brief Creates a new sRGB color structure.
*
* @param rgb red green and blue channel color value
* @param rgb red, green and blue channel color value
* @param a alpha channel color value (transparency)
*/
constexpr Color(Color rgb, float a) noexcept : r(rgb.r), g(rgb.g), b(rgb.b),
a(uint8(saturate(a) * 255.0f + 0.5f)) { }
/**
* @brief Creates a new sRGB color structure.
* @param rgba red, green, blue and alpha channel color value
*/
constexpr Color(byte4 rgba) noexcept : r(rgba.x), g(rgba.y), b(rgba.z), a(rgba.w) { }

/**
* @brief Creates a new sRGB color structure from the binary data.
Expand Down Expand Up @@ -165,25 +170,37 @@ struct [[nodiscard]] Color
}

/*******************************************************************************************************************
* @brief Converts sRGB color to the normalized RG vector. (Red, Green)
* @brief Converts sRGB color to the normalized RGBA SIMD vector. (Red, Green, Blue, Alpha)
*/
constexpr explicit operator float2() const noexcept { return float2(r, g) * (1.0f / 255.0f); }
explicit operator f32x4() const noexcept { return f32x4(r, g, b, a) * (1.0f / 255.0f); }
/**
* @brief Converts sRGB color to the normalized RGB vector. (Red, Green, Blue)
* @brief Converts sRGB color to the normalized RGBA SIMD vector. (Red, Green, Blue, Alpha)
*/
constexpr explicit operator float3() const noexcept { return float3(r, g, b) * (1.0f / 255.0f); }
explicit operator f16x4() const noexcept { return (f16x4)(f32x4(r, g, b, a) * (1.0f / 255.0f)); }
/**
* @brief Converts sRGB color to the normalized RGBA vector. (Red, Green, Blue, Alpha)
*/
constexpr explicit operator float4() const noexcept { return float4(r, g, b, a) * (1.0f / 255.0f); }
/**
* @brief Converts sRGB color to the normalized RGBA SIMD vector. (Red, Green, Blue, Alpha)
* @brief Converts sRGB color to the normalized RGBA vector. (Red, Green, Blue, Alpha)
*/
explicit operator f32x4() const noexcept { return f32x4(r, g, b, a) * (1.0f / 255.0f); }
constexpr explicit operator half4() const noexcept { return (half4)(float4(r, g, b, a) * (1.0f / 255.0f)); }
/**
* @brief Returns color binary data.
* @brief Returns color as binary vector.
*/
explicit operator uint32() const noexcept { return *(const uint32*)this; }
explicit operator byte4() const noexcept { return *((const byte4*)this); }
/**
* @brief Converts sRGB color to the normalized RGB vector. (Red, Green, Blue)
*/
constexpr explicit operator float3() const noexcept { return float3(r, g, b) * (1.0f / 255.0f); }
/**
* @brief Converts sRGB color to the normalized RGB vector. (Red, Green, Blue)
*/
constexpr explicit operator half3() const noexcept { return (half3)(float3(r, g, b) * (1.0f / 255.0f)); }
/**
* @brief Returns color as unsigned integer value
*/
explicit operator uint32() const noexcept { return *((const uint32*)this); }

/*******************************************************************************************************************
* @brief Returns sRGB color normalizer R channel. (Red)
Expand Down Expand Up @@ -293,6 +310,16 @@ static constexpr bool operator>(uint8 n, Color c) noexcept { return Color(n) > c
static constexpr bool operator<=(uint8 n, Color c) noexcept { return Color(n) <= c; }
static constexpr bool operator>=(uint8 n, Color c) noexcept { return Color(n) >= c; }

/**
* @brief Creates a new sRGB color. (CSS style declaration)
*
* @param r red channel color value
* @param g green channel color value
* @param b blue channel color value
* @param a alpha channel color value (transparency)
*/
static constexpr Color rgba(uint8 r, uint8 g, uint8 b, float a) noexcept { return Color(Color(r, g, b), a); }

/**
* @brief Returns true if first color binary representation is less than the second.
*
Expand All @@ -301,15 +328,30 @@ static constexpr bool operator>=(uint8 n, Color c) noexcept { return Color(n) >=
*/
static bool isBinaryLess(Color a, Color b) noexcept { return *((const uint32*)&a) < *((const uint32*)&b); }

/***********************************************************************************************************************
* @brief Linearly interpolates each component of the color between a and b using t.
*
* @param a minimum color (t == 0.0)
* @param b maximum color (t == 1.0)
* @param t target interpolation value (0.0 - 1.0)
*/
static Color lerp(Color a, Color b, float t) noexcept
{
return Color::fromLinear(lerp(a.toLinear(), b.toLinear(), t));
}
/**
* @brief Creates a new sRGB color. (CSS style declaration)
* @brief Linearly interpolates each component of the color between a and b taking into account delta time.
* @note Always use this function instead of basic lerp() when you have variable delta time!
*
* @param r red channel color value
* @param g green channel color value
* @param b blue channel color value
* @param a alpha channel color value (transparency)
* @param a minimum color (t == 0.0)
* @param b maximum color (t == 1.0)
* @param dr target decay rate value
* @param dt current delta time value
*/
static constexpr Color rgba(uint8 r, uint8 g, uint8 b, float a) noexcept { return Color(Color(r, g, b), a); }
static Color lerpDelta(Color a, Color b, float dr, float dt) noexcept
{
return Color::fromLinear(lerpDelta(a.toLinear(), b.toLinear(), dr, dt));
}

// TODO: color conversion functions.

Expand Down
124 changes: 89 additions & 35 deletions include/math/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
*/

#pragma once
#include "math/types.hpp"
#include <algorithm>
#include <cmath>
#include <cassert>
Expand All @@ -28,53 +27,54 @@ namespace math

using namespace std;

#define M_LN100 4.60517018598809136803598290936872842 // loge(100)

/**
* @brief Returns the minimum of three floating point values.
*
* @param a first value to find minimum
* @param b second value to find minimum
* @param c third value to find minimum
*/
static constexpr float min(float a, float b, float c) { return std::min(std::min(a, b), c); }
/**
* @brief Returns the maximum of three floating point values.
*
* @param a first value to find maximum
* @param b second value to find maximum
* @param c third value to find maximum
*/
static constexpr float max(float a, float b, float c) { return std::max(std::max(a, b), c); }
/**
* @brief Returns the minimum of signed integer values.
* @brief Returns the minimum of three values.
*
* @tparam T target value type
* @param a first value to find minimum
* @param b second value to find minimum
* @param c third value to find minimum
*/
static constexpr int32 min(int32 a, int32 b, int32 c) { return std::min(std::min(a, b), c); }
template<typename T>
static constexpr const T& min(const T& a, const T& b, const T& c) { return std::min(std::min(a, b), c); }
/**
* @brief Returns the maximum of signed integer values.
* @brief Returns the maximum of three values.
*
* @tparam T target value type
* @param a first value to find maximum
* @param b second value to find maximum
* @param c third value to find maximum
*/
static constexpr int32 max(int32 a, int32 b, int32 c) { return std::max(std::max(a, b), c); }
template<typename T>
static constexpr const T& max(const T& a, const T& b, const T& c) { return std::max(std::max(a, b), c); }

/**
* @brief Clamps float value between the 0.0f and 1.0f. (Inclusive range)
* @param v target float value to saturate
* @brief Clamps float value between the 0.0 and 1.0. (Inclusive range)
* @param v target floating-point value to saturate
*/
static constexpr float saturate(float v) { return std::clamp(v, 0.0f, 1.0f); }
/**
* @brief Clamps float value between the 0.0 and 1.0. (Inclusive range)
* @param v target floating-point value to saturate
*/
static constexpr double saturate(double v) { return std::clamp(v, 0.0, 1.0); }

/**
* @brief Returns specified floating point value sign.
* @param v target value
* @brief Returns specified float value sign.
* @param v target floating-point value
*/
static float sign(float v) noexcept { return std::signbit(v) ? -1.0f : 1.0f; }
/**
* @brief Returns specified float value sign.
* @param v target floating-point value
*/
static double sign(double v) noexcept { return std::signbit(v) ? -1.0 : 1.0; }

/***********************************************************************************************************************
* @brief Remaps specified value to the 0.0 - 1.0 range.
* @param v target value to repeat
* @param v target floating-point value to repeat
*/
static float repeat(float v) noexcept
{
Expand All @@ -84,6 +84,18 @@ static float repeat(float v) noexcept
return std::fmod(v, 1.0f);
return v;
}
/**
* @brief Remaps specified value to the 0.0 - 1.0 range.
* @param v target floating-point value to repeat
*/
static double repeat(double v) noexcept
{
if (v < 0.0)
return 1.0 - std::fmod(-v, 1.0);
if (v >= 1.0)
return std::fmod(v, 1.0);
return v;
}

/**
* @brief Linearly interpolates between a and b values using t.
Expand All @@ -92,21 +104,51 @@ static float repeat(float v) noexcept
* @param b maximum value (t == 1.0)
* @param t target interpolation value (0.0 - 1.0)
*/
static float lerp(float a, float b, float t) noexcept { return a + t * (b - a); }
static float lerp(float a, float b, float t) noexcept { return std::fma(t, b, std::fma(-t, a, a)); }
/**
* @brief Linearly interpolates between a and b values using t, taking into account delta time.
* @note Always use this function instead of basic lerp() when you have variable delta time!
* @brief Linearly interpolates between a and b values using t.
*
* @param a minimum value (t == 0.0)
* @param b maximum value (t == 1.0)
* @param t target interpolation value (0.0 - 1.0)
*/
static double lerp(double a, double b, double t) noexcept { return std::fma(t, b, std::fma(-t, a, a)); }

/**
* @brief Linearly interpolates between a and b values taking into account delta time.
* @note Always use this function instead of basic lerp() when you have variable delta time!
*
* @param a minimum value (t == 0.0)
* @param b maximum value (t == 1.0)
* @param dr target decay rate value
* @param dt current delta time
*/
static float lerpDelta(float a, float b, float f, float dt) noexcept
{
return a + (1.0f - std::pow(f, dt)) * (b - a);
}
static float lerpDelta(float a, float b, float dr, float dt) noexcept { return lerp(b, a, std::exp(-dr * dt)); }
/**
* @brief Linearly interpolates between a and b values taking into account delta time.
* @note Always use this function instead of basic lerp() when you have variable delta time!
*
* @param a minimum value (t == 0.0)
* @param b maximum value (t == 1.0)
* @param dr target decay rate value
* @param dt current delta time
*/
static double lerpDelta(double a, double b, double dr, double dt) noexcept { return lerp(b, a, std::exp(-dr * dt)); }

/**
* @brief Converts seconds needed to reach 99% of the distance to the decay rate.
* @details Use this function to calculate dt parameter for the lerpDelta().
* @param time target time to convert in seconds
*/
static constexpr float secToDecRate(float time) noexcept { return (float)M_LN100 / time; }
/**
* @brief Converts seconds needed to reach 99% of the distance to the decay rate.
* @details Use this function to calculate dt parameter for the lerpDelta().
* @param time target time to convert in seconds
*/
static constexpr double secToDecRate(double time) noexcept { return M_LN100 / time; }

/***********************************************************************************************************************
* @brief Applies gain function to the x value.
* @note The function is symmetric when x == 0.5.
*
Expand All @@ -118,12 +160,24 @@ static float gain(float x, float k) noexcept
auto a = 0.5f * std::pow(2.0f * ((x < 0.5f) ? x : 1.0f - x), k);
return (x < 0.5f) ? a : 1.0f - a;
}
/**
* @brief Applies gain function to the x value.
* @note The function is symmetric when x == 0.5.
*
* @param x target value to gain (0.0 - 1.0)
* @param k gain factor
*/
static double gain(double x, double k) noexcept
{
auto a = 0.5 * std::pow(2.0 * ((x < 0.5) ? x : 1.0 - x), k);
return (x < 0.5) ? a : 1.0 - a;
}

/**
* @brief Returns true if specified value is a power of 2.
*
* @tparam T type of the value
* @param v target value to check
* @tparam T integer type of the value
* @param v target integer value to check
*/
template <typename T>
static constexpr bool isPowerOf2(T v) noexcept
Expand Down
2 changes: 1 addition & 1 deletion include/math/hex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ static string toHex8(const uint8* data, psize size) noexcept
}

/***********************************************************************************************************************
* @brief Converts hexadecimal string to the 32bit integer value.
* @brief Converts hexadecimal string to the 32-bit integer value.
* @param[in] hex target hexadecimal string
*/
static uint32 toInt32(const string& hex) noexcept { return (uint32)std::stoul(hex, nullptr, 16); }
Expand Down
Loading
Loading