diff --git a/CMakeLists.txt b/CMakeLists.txt index 54cdb9d..9f13f29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.13.4) -project(ClassicOS VERSION 0.0.1 LANGUAGES C ASM_NASM) +project(ClassicOS VERSION 0.0.1 LANGUAGES C CXX ASM_NASM) set(IS_OS_WINDOWS FALSE) set(IS_OS_LINUX FALSE) @@ -7,13 +7,13 @@ set(IS_OS_MAC FALSE) if (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows") set(IS_OS_WINDOWS TRUE) - message("Building for the Windows operating system.") + message("Building on the Windows operating system.") elseif (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux") set(IS_OS_LINUX TRUE) - message("Building for the Linux operating system.") + message("Building on the Linux operating system.") elseif (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Darwin") set(IS_OS_MAC TRUE) - message("Building for the Mac operating system.") + message("Building on the Mac operating system.") endif () # Source files @@ -38,7 +38,7 @@ set(DRIVERS_SOURCE_FILES src/drivers/bus/isa.h src/drivers/bus/mca.c src/drivers/bus/mca.h - src/drivers/bus/pci.asm + #src/drivers/bus/pci.asm src/drivers/bus/pci.c src/drivers/bus/pci.h src/drivers/bus/vesa.c @@ -71,10 +71,37 @@ set(KERNEL_SOURCE_FILES src/kernel/print.c ) +set(UTIL_SOURCE_FILES + src/EHS.h + src/sys/CPU.h src/sys/CPU.cpp src/sys/CPU_GCC_AMD64.asm + src/Util.h src/Util.cpp + src/Version.h src/Version.cpp + src/Serializer.h + src/Array.h + src/Vector.h + src/SArray.h + src/Str.h + src/PRNG.h + src/HRNG.h src/HRNG_GCC.s + src/Math.h src/Math.cpp src/Math_GCC_AMD64.s + src/Rect.h + src/Range.h src/Range.cpp + src/Color4.h src/Color4.cpp + src/Color3.h src/Color3.cpp + src/Quat.h + src/Vec4.h + src/Vec3.h + src/Vec2.h + src/Mat4.h + src/Mat3.h + src/Mat2.h +) + add_executable(ClassicOS ${GRUB_SOURCE_FILES} ${DRIVERS_SOURCE_FILES} ${KERNEL_SOURCE_FILES} + ${UTIL_SOURCE_FILES} ) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -88,6 +115,7 @@ target_link_libraries(ClassicOS PRIVATE) set(CMAKE_SYSTEM_PROCESSOR i386) set(CMAKE_SYSTEM_NAME None) set(CMAKE_C_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_BUILD_TYPE Debug) set(CMAKE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) set(CMAKE_BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/build) diff --git a/src/Array.h b/src/Array.h new file mode 100644 index 0000000..a50152d --- /dev/null +++ b/src/Array.h @@ -0,0 +1,375 @@ +#pragma once + +#include "EHS.h" + +#include +#include + +/// A helper class for C-style arrays. +/// @tparam T Array data type to use. +/// @tparam N Number data type to use. +template +class Array +{ +protected: + T* data; + N size; + +public: + /// Frees any data created on the heap. + ~Array() + { + delete[] data; + } + + /// Default members initialization. + Array() + : data(nullptr), size(0) + { + } + + /// Initializes an empty array with the given size. + /// @note Data must be assigned manually using an index. + explicit Array(const N size) + : data(new T[size]), size(size) + { + } + + /// Initializes this array with an initializer list object. + /// @param [in] list The given initializer list. + Array(std::initializer_list list) + : data(new T[list.size()]), size(list.size()) + { + N i = 0; + for (auto v = list.begin(); v != list.end(); ++v) + data[i++] = std::move(*v); + } + + /// Initializes members with given C-style array. + /// @param [in] data The C-style array. + /// @param [in] size The size of the given C-style array. + Array(const T* const data, const N size) + : data(new T[size]), size(size) + { + for (N i = 0; i < size; ++i) + this->data[i] = data[i]; + } + + /// Copies all members from the given array object. + /// @param [in] array The array object to copy from. + Array(const Array& array) + : data(new T[array.size]), size(array.size) + { + for (N i = 0; i < size; ++i) + data[i] = array.data[i]; + } + + Array(Array&& array) noexcept + : data(array.data), size(array.size) + { + array.data = nullptr; + array.size = 0; + } + + /// Copies all members from the given array object. + /// @param [in] array The array object to copy from. + /// @returns The array that has been assigned to. + Array& operator=(const Array& array) + { + if (this == &array) + return *this; + + delete[] data; + data = new T[array.size]; + for (N i = 0; i < array.size; ++i) + data[i] = array.data[i]; + + size = array.size; + + return *this; + } + + Array& operator=(Array&& array) noexcept + { + if (this == &array) + return *this; + + delete[] data; + data = array.data; + size = array.size; + + array.data = nullptr; + array.size = 0; + + return *this; + } + + /// Copies all members from the given initializer list object. + /// @param [in] list The initializer list object to copy from. + /// @returns The array that has been assigned to. + Array& operator=(std::initializer_list list) + { + delete[] data; + data = new T[list.size]; + + N i = 0; + for (auto v = list.begin(); v != list.end(); ++v) + data[i++] = std::move(*v); + + size = list.size(); + + return *this; + } + + /// Adds a given array object at the end of the array. + /// @param [in] value The given array object to push to the end of the array. + Array& operator+=(Array value) + { + T* result = new T[size + value.size]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + for (N i = 0; i < value.size; ++i) + result[size + i] = std::move(value[i]); + + delete[] data; + + data = result; + size += value.size; + + return *this; + } + + bool operator==(const Array& array) const + { + if (size != array.size) + return false; + + for (N i = 0; i < size; ++i) + if (data[i] != array[i]) + return false; + + return true; + } + + bool operator!=(const Array& array) const + { + if (size == array.size) + return false; + + for (N i = 0; i < size; ++i) + if (data[i] != array[i]) + return true; + + return false; + } + + /// Adds a given array object at the end of the array. + /// @param [in] value The given initializer list to push to the end of the array. + Array& operator+=(std::initializer_list value) + { + T* result = new T[size + value.size()]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + N i = 0; + for (auto v = value.begin(); v != value.end(); ++v) + result[size + i++] = std::move(*v); + + delete[] data; + + data = result; + size += value.size(); + + return *this; + } + + /// Adds a given value at the end of the array. + /// @param [in] value The given value to push to the end of the array. + Array& operator+=(const T value) + { + T* result = new T[size + 1]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + result[size] = std::move(value); + + delete[] data; + + data = result; + ++size; + + return *this; + } + + /// Retrieves the raw C-style array from casting an array object. + operator T* () const + { + return data; + } + + /// Swaps two values in the array. + /// @param a The first index to swap with. + /// @param b The second index to swap with. + void Swap(N a, N b) const + { + T tmp = std::move(data[a]); + + data[a] = std::move(data[b]); + data[b] = std::move(tmp); + } + + /// Adds a given C-style array at the end of the array. + /// @param [in] value The given C-style array to push to the end of the array. + /// @param [in] size The size of the given C-style array. + void Push(const T* const value, const N size) + { + T* result = new T[this->size + size]; + + for (N i = 0; i < this->size; ++i) + result[i] = std::move(this->data[i]); + + for (N i = 0; i < size; ++i) + result[this->size + i] = value[i]; + + delete[] data; + + this->data = result; + this->size += size; + } + + /// Adds a given array object at the end of the array. + /// @param [in] value The given array object to push to the end of the array. + void Push(Array value) + { + T* result = new T[size + value.size]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + for (N i = 0; i < value.size; ++i) + result[size + i] = std::move(value[i]); + + delete[] data; + + data = result; + size += value.size; + } + + /// Adds a given array object at the end of the array. + /// @param [in] value The given initializer list to push to the end of the array. + void Push(std::initializer_list value) + { + T* result = new T[size + value.size()]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + N i = 0; + for (auto v = value.begin(); v != value.end(); ++v) + result[size + i++] = std::move(*v); + + delete[] data; + + data = result; + size += value.size(); + } + + /// Adds a given value at the end of the array. + /// @param [in] value The given value to push to the end of the array. + void Push(T value) + { + T* result = new T[size + 1]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + result[size] = std::move(value); + + delete[] data; + + data = result; + ++size; + } + + /// Removes a value at the end of the array. + /// @returns The value that was popped. + T Pop() + { + T* result = new T[--size]; + + T value = std::move(data[size]); + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + delete[] data; + + data = result; + + return value; + } + + /// Removes a value at a provided index. + /// @param [in] index The index of the value to remove. + /// @returns The value that was removed. + T Remove(const N index) + { + T* result = new T[--size]; + + T value = std::move(data[index]); + + for (N i = 0, c = 0; i < size; ++i) + if (i != index) + result[c++] = std::move(data[i]); + + delete[] data; + + data = result; + + return value; + } + + void Clear() + { + if (!data) + return; + + delete[] data; + data = nullptr; + size = 0; + } + + /// Resizes the array. + /// @param [in] newSize The size to change to. + void Resize(const N newSize) + { + if (size == newSize) + return; + + T* result = new T[newSize]; + + for (N i = 0; i < newSize && i < size; ++i) + result[i] = std::move(data[i]); + + delete[] data; + + data = result; + size = newSize; + } + + /// Retrieves the size of the array. + /// @returns The resulting size. + N Size() const + { + return size; + } + + N End() const + { + return size - 1; + } +}; \ No newline at end of file diff --git a/src/Color3.cpp b/src/Color3.cpp new file mode 100644 index 0000000..7d53dfa --- /dev/null +++ b/src/Color3.cpp @@ -0,0 +1,89 @@ +#include "Color3.h" + +#include "Math.h" + +Color3::Color3() + : r(0.0f), g(0.0f), b(0.0f) +{ +} + +Color3::Color3(const float scalar) + : r(Math::Clamp(scalar, 0.0f, 1.0f)), g(Math::Clamp(scalar, 0.0f, 1.0f)), b(Math::Clamp(scalar, 0.0f, 1.0f)) +{ +} + +Color3::Color3(const float r, const float g, const float b) + : r(Math::Clamp(r, 0.0f, 1.0f)), g(Math::Clamp(g, 0.0f, 1.0f)), b(Math::Clamp(b, 0.0f, 1.0f)) +{ +} + +Color3::Color3(const Color3& color) + : r(color.r), g(color.g), b(color.b) +{ +} + +Color3& Color3::operator=(const Color3& color) +{ + if (this == &color) + return *this; + + r = color.r; + g = color.g; + b = color.b; + + return *this; +} + +bool Color3::operator==(const Color3& color) const +{ + return r == color.r && g == color.g && b == color.b; +} + +bool Color3::operator!=(const Color3& color) const +{ + return r != color.r || g != color.g || b != color.b; +} + +float Color3::operator[](const UInt_64 i) const +{ + switch (i) + { + case 0: + return r; + case 1: + return g; + case 2: + return b; + default: + return r; + } +} + +float& Color3::operator[](const UInt_64 i) +{ + switch (i) + { + case 0: + return r; + case 1: + return g; + case 2: + return b; + default: + return r; + } +} + +Color3& Color3::operator*=(const Color3& color) +{ + r *= color.r; + g *= color.g; + b *= color.b; + + return *this; +} + +Color3 Color3::operator*(const Color3& color) const +{ + return {r * color.r, g * color.g, b * color.b}; +} \ No newline at end of file diff --git a/src/Color3.h b/src/Color3.h new file mode 100644 index 0000000..a52ac59 --- /dev/null +++ b/src/Color3.h @@ -0,0 +1,33 @@ +#pragma once + +#include "EHS.h" + +class Color3 +{ +public: + float r; + float g; + float b; + + Color3(); + + Color3(const float scalar); + + Color3(const float r, const float g, const float b); + + Color3(const Color3& color); + + Color3& operator=(const Color3& color); + + bool operator==(const Color3& color) const; + + bool operator!=(const Color3& color) const; + + float operator[](const UInt_64 i) const; + + float& operator[](const UInt_64 i); + + Color3& operator*=(const Color3& color); + + Color3 operator*(const Color3& color) const; +}; \ No newline at end of file diff --git a/src/Color4.cpp b/src/Color4.cpp new file mode 100644 index 0000000..8707eeb --- /dev/null +++ b/src/Color4.cpp @@ -0,0 +1,94 @@ +#include "Color4.h" + +#include "Math.h" + +Color4::Color4() + : r(0.0f), g(0.0f), b(0.0f), a(1.0f) +{ +} + +Color4::Color4(const float scalar, const float a) + : r(Math::Clamp(scalar, 0.0f, 1.0f)), g(Math::Clamp(scalar, 0.0f, 1.0f)), b(Math::Clamp(scalar, 0.0f, 1.0f)), a(a) +{ +} + +Color4::Color4(const float r, const float g, const float b, const float a) + : r(Math::Clamp(r, 0.0f, 1.0f)), g(Math::Clamp(g, 0.0f, 1.0f)), b(Math::Clamp(b, 0.0f, 1.0f)), a(Math::Clamp(a, 0.0f, 1.0f)) +{ +} + +Color4::Color4(const Color4& color) + : r(color.r), g(color.g), b(color.b), a(color.a) +{ +} + +Color4& Color4::operator=(const Color4& color) +{ + if (this == &color) + return *this; + + r = color.r; + g = color.g; + b = color.b; + a = color.a; + + return *this; +} + +bool Color4::operator==(const Color4& color) const +{ + return r == color.r && g == color.g && b == color.b && a == color.a; +} + +bool Color4::operator!=(const Color4& color) const +{ + return r != color.r || g != color.g || b != color.b || a != color.a; +} + +float Color4::operator[](const UInt_64 i) const +{ + switch (i) + { + case 0: + return r; + case 1: + return g; + case 2: + return b; + case 3: + return a; + default: + return r; + } +} + +float& Color4::operator[](const UInt_64 i) +{ + switch (i) + { + case 0: + return r; + case 1: + return g; + case 2: + return b; + case 3: + return a; + default: + return r; + } +} + +Color4& Color4::operator*=(const Color4& color) +{ + r *= color.r; + g *= color.g; + b *= color.b; + + return *this; +} + +Color4 Color4::operator*(const Color4& color) const +{ + return {r * color.r, g * color.g, b * color.b, a}; +} \ No newline at end of file diff --git a/src/Color4.h b/src/Color4.h new file mode 100644 index 0000000..aefd19a --- /dev/null +++ b/src/Color4.h @@ -0,0 +1,34 @@ +#pragma once + +#include "EHS.h" + +class Color4 +{ +public: + float r; + float g; + float b; + float a; + + Color4(); + + Color4(const float scalar, const float a = 1.0f); + + Color4(const float r, const float g, const float b, const float a = 1.0f); + + Color4(const Color4& color); + + Color4& operator=(const Color4& color); + + bool operator==(const Color4& color) const; + + bool operator!=(const Color4& color) const; + + float operator[](const UInt_64 i) const; + + float& operator[](const UInt_64 i); + + Color4& operator*=(const Color4& color); + + Color4 operator*(const Color4& color) const; +}; \ No newline at end of file diff --git a/src/EHS.h b/src/EHS.h new file mode 100644 index 0000000..3d6a34d --- /dev/null +++ b/src/EHS.h @@ -0,0 +1,72 @@ +#if defined(_M_AMD64) || defined(_M_X64) || defined(__x86_64__) + #define LITTLE_ENDIAN + #define ARCH_X64 +#elif defined(__i386__) + #define LITTLE_ENDIAN + #define ARCH_X86 +#elif defined(_M_ARM64) || defined(__aarch64__) + #define LITTLE_ENDIAN + #define ARCH_ARM64 +#else + #error Unsupported architecture. +#endif + +typedef unsigned char UInt_8; +typedef signed char SInt_8; +typedef char Int_8; +typedef unsigned short UInt_16; +typedef signed short SInt_16; +typedef short Int_16; +typedef unsigned int UInt_32; +typedef signed int SInt_32; +typedef int Int_32; + +typedef UInt_8 Byte; +typedef Int_8 Char_8; +typedef Int_16 Char_16; +typedef Int_32 Char_32; + +#if defined(__GNUC__) + typedef unsigned long long UInt_64; + typedef signed long long SInt_64; + typedef long long Int_64; +#elif defined(_WIN32) + typedef unsigned long UInt_64; + typedef signed long SInt_64; + typedef long Int_64; +#endif + +#if defined(ARCH_X64) + typedef UInt_64 USize; + typedef SInt_64 SSize; + typedef Int_64 Size; +#elif defined(ARCH_X86) + typedef UInt_32 USize; + typedef SInt_32 SSize; + typedef Int_32 Size; +#endif + +#define MAX_PATH 0x104 +#define UINT_8_MAX 0xFF +#define SINT_8_MAX 0x7F +#define SINT_8_MIN 0x80 +#define UINT_16_MAX 0xFFFF +#define SINT_16_MAX 0x7FFF +#define SINT_16_MIN 0x8000 +#define UINT_24_MAX 0xFFFFFF +#define SINT_24_MAX 0x7FFFFF +#define SINT_24_MIN 0x800000 +#define UINT_32_MAX 0xFFFFFFFF +#define SINT_32_MAX 0x7FFFFFFF +#define SINT_32_MIN 0x80000000 +#define UINT_64_MAX 0xFFFFFFFFFFFFFFFF +#define SINT_64_MAX 0x7FFFFFFFFFFFFFFF +#define SINT_64_MIN 0x8000000000000000 +#define FLOAT_MAX 3.40282e+038f +#define FLOAT_MIN 1.17549e-038f +#define DOUBLE_MAX 1.79769e+308 +#define DOUBLE_MIN 2.22507e-308 +#define LDOUBLE_MAX 1.79769e+308 +#define LDOUBLE_MIN 2.22507e-308 + +#define INFINITE UINT_32_MAX \ No newline at end of file diff --git a/src/HRNG.h b/src/HRNG.h new file mode 100644 index 0000000..0b263f1 --- /dev/null +++ b/src/HRNG.h @@ -0,0 +1,55 @@ +#pragma once + +#include "EHS.h" + +class HRNG +{ +public: + static UInt_64 GenerateSeed_u64(); + + static UInt_64 Generate_u64(const UInt_64 min, const UInt_64 max); + + static UInt_64 Generate_u64(); + + static SInt_64 GenerateSeed_s64(); + + static SInt_64 Generate_s64(const SInt_64 min, const SInt_64 max); + + static SInt_64 Generate_s64(); + + static UInt_32 GenerateSeed_u32(); + + static UInt_32 Generate_u32(const UInt_32 min, const UInt_32 max); + + static UInt_32 Generate_u32(); + + static SInt_32 GenerateSeed_s32(); + + static SInt_32 Generate_s32(const SInt_32 min, const SInt_32 max); + + static SInt_32 Generate_s32(); + + static UInt_32 GenerateSeed_u16(); + + static UInt_16 Generate_u16(const UInt_16 min, const UInt_16 max); + + static UInt_16 Generate_u16(); + + static SInt_16 GenerateSeed_s16(); + + static SInt_16 Generate_s16(const SInt_16 min, const SInt_16 max); + + static SInt_16 Generate_s16(); + + static UInt_8 GenerateSeed_u8(); + + static UInt_8 Generate_u8(const UInt_8 min, const UInt_8 max); + + static UInt_8 Generate_u8(); + + static SInt_8 GenerateSeed_s8(); + + static SInt_8 Generate_s8(const SInt_8 min, const SInt_8 max); + + static SInt_8 Generate_s8(); +}; \ No newline at end of file diff --git a/src/HRNG_GCC.s b/src/HRNG_GCC.s new file mode 100644 index 0000000..a468505 --- /dev/null +++ b/src/HRNG_GCC.s @@ -0,0 +1,161 @@ +global _ZN3lwe4HRNG16GenerateSeed_u64Ev +global _ZN3lwe4HRNG12Generate_u64Emm +global _ZN3lwe4HRNG12Generate_u64Ev +global _ZN3lwe4HRNG16GenerateSeed_s64Ev +global _ZN3lwe4HRNG12Generate_s64Ell +global _ZN3lwe4HRNG12Generate_s64Ev +global _ZN3lwe4HRNG16GenerateSeed_u32Ev +global _ZN3lwe4HRNG12Generate_u32Ejj +global _ZN3lwe4HRNG12Generate_u32Ev +global _ZN3lwe4HRNG16GenerateSeed_s32Ev +global _ZN3lwe4HRNG12Generate_s32Eii +global _ZN3lwe4HRNG12Generate_s32Ev +global _ZN3lwe4HRNG16GenerateSeed_u16Ev +global _ZN3lwe4HRNG12Generate_u16Ett +global _ZN3lwe4HRNG12Generate_u16Ev +global _ZN3lwe4HRNG16GenerateSeed_s16Ev +global _ZN3lwe4HRNG12Generate_s16Ess +global _ZN3lwe4HRNG12Generate_s16Ev +global _ZN3lwe4HRNG15GenerateSeed_u8Ev +global _ZN3lwe4HRNG11Generate_u8Ehh +global _ZN3lwe4HRNG11Generate_u8Ev +global _ZN3lwe4HRNG15GenerateSeed_s8Ev +global _ZN3lwe4HRNG11Generate_s8Eaa +global _ZN3lwe4HRNG11Generate_s8Ev + +section .text + _ZN3lwe4HRNG16GenerateSeed_u64Ev: + RDSEED RAX + RET + + _ZN3lwe4HRNG12Generate_u64Emm: + RDRAND RAX + SUB RDI, RCX + XOR RDX, RDX + DIV RDI + MOV RAX, RDX + ADD RAX, RCX + RET + + _ZN3lwe4HRNG12Generate_u64Ev: + RDRAND RAX + RET + + _ZN3lwe4HRNG16GenerateSeed_s64Ev: + RDSEED RAX + RET + + _ZN3lwe4HRNG12Generate_s64Ell: + RDRAND RAX + SUB RDI, RCX + XOR RDX, RDX + DIV RDI + MOV RAX, RDX + ADD RAX, RCX + RET + + _ZN3lwe4HRNG12Generate_s64Ev: + RDRAND RAX + RET + + _ZN3lwe4HRNG16GenerateSeed_u32Ev: + RDSEED EAX + RET + + _ZN3lwe4HRNG12Generate_u32Ejj: + RDRAND EAX + SUB EDI, ECX + XOR EDX, EDX + DIV EDI + MOV EAX, EDX + ADD EAX, ECX + RET + + _ZN3lwe4HRNG12Generate_u32Ev: + RDRAND EAX + RET + + _ZN3lwe4HRNG16GenerateSeed_s32Ev: + RDSEED EAX + RET + + _ZN3lwe4HRNG12Generate_s32Eii: + RDRAND EAX + SUB EDI, ECX + XOR EDX, EDX + DIV EDI + MOV EAX, EDX + ADD EAX, ECX + RET + + _ZN3lwe4HRNG12Generate_s32Ev: + RDRAND EAX + RET + + _ZN3lwe4HRNG16GenerateSeed_u16Ev: + RDSEED AX + RET + + _ZN3lwe4HRNG12Generate_u16Ett: + RDRAND AX + SUB DI, CX + XOR DX, DX + DIV DI + MOV AX, DX + ADD AX, CX + RET + + _ZN3lwe4HRNG12Generate_u16Ev: + RDRAND AX + RET + + _ZN3lwe4HRNG16GenerateSeed_s16Ev: + RDSEED AX + RET + + _ZN3lwe4HRNG12Generate_s16Ess: + RDRAND AX + SUB DI, CX + XOR DX, DX + DIV DI + MOV AX, DX + ADD AX, CX + RET + + _ZN3lwe4HRNG12Generate_s16Ev: + RDRAND AX + RET + + _ZN3lwe4HRNG15GenerateSeed_u8Ev: + RDSEED AX + RET + + _ZN3lwe4HRNG11Generate_u8Ehh: + RDRAND AX + SUB DI, CX + XOR DX, DX + DIV DI + MOV AX, DX + ADD AX, CX + RET + + _ZN3lwe4HRNG11Generate_u8Ev: + RDRAND AX + RET + + _ZN3lwe4HRNG15GenerateSeed_s8Ev: + RDSEED AX + RET + + _ZN3lwe4HRNG11Generate_s8Eaa: + RDRAND AX + SUB DI, CX + XOR DX, DX + DIV DI + MOV AX, DX + ADD AX, CX + RET + + _ZN3lwe4HRNG11Generate_s8Ev: + RDRAND AX + RET \ No newline at end of file diff --git a/src/HRNG_MSVC.s b/src/HRNG_MSVC.s new file mode 100644 index 0000000..10bbcc9 --- /dev/null +++ b/src/HRNG_MSVC.s @@ -0,0 +1,169 @@ +global ?GenerateSeed_u64@HRNG@lwe@@SA_KXZ +global ?Generate_u64@HRNG@lwe@@SA_K_K0@Z +global ?Generate_u64@HRNG@lwe@@SA_KXZ +global ?GenerateSeed_s64@HRNG@lwe@@SA_JXZ +global ?Generate_s64@HRNG@lwe@@SA_J_J0@Z +global ?Generate_s64@HRNG@lwe@@SA_JXZ +global ?GenerateSeed_u32@HRNG@lwe@@SAIXZ +global ?Generate_u32@HRNG@lwe@@SAIII@Z +global ?Generate_u32@HRNG@lwe@@SAIXZ +global ?GenerateSeed_s32@HRNG@lwe@@SAHXZ +global ?Generate_s32@HRNG@lwe@@SAHHH@Z +global ?Generate_s32@HRNG@lwe@@SAHXZ +global ?GenerateSeed_u16@HRNG@lwe@@SAIXZ +global ?Generate_u16@HRNG@lwe@@SAGGG@Z +global ?Generate_u16@HRNG@lwe@@SAGXZ +global ?GenerateSeed_s16@HRNG@lwe@@SAFXZ +global ?Generate_s16@HRNG@lwe@@SAFFF@Z +global ?Generate_s16@HRNG@lwe@@SAFXZ +global ?GenerateSeed_u8@HRNG@lwe@@SAEXZ +global ?Generate_u8@HRNG@lwe@@SAEEE@Z +global ?Generate_u8@HRNG@lwe@@SAEXZ +global ?GenerateSeed_s8@HRNG@lwe@@SACXZ +global ?Generate_s8@HRNG@lwe@@SACCC@Z +global ?Generate_s8@HRNG@lwe@@SACXZ + +section .text + ?GenerateSeed_u64@HRNG@lwe@@SA_KXZ: + RDSEED RAX + RET + + ?Generate_u64@HRNG@lwe@@SA_K_K0@Z: + RDRAND RAX + MOV R8, RDX + SUB R8, RCX + XOR RDX, RDX + DIV R8 + MOV RAX, RDX + ADD RAX, RCX + RET + + ?Generate_u64@HRNG@lwe@@SA_KXZ: + RDRAND RAX + RET + + ?GenerateSeed_s64@HRNG@lwe@@SA_JXZ: + RDSEED RAX + RET + + ?Generate_s64@HRNG@lwe@@SA_J_J0@Z: + RDRAND RAX + MOV R8, RDX + SUB R8, RCX + XOR RDX, RDX + DIV R8 + MOV RAX, RDX + ADD RAX, RCX + RET + + ?Generate_s64@HRNG@lwe@@SA_JXZ: + RDRAND RAX + RET + + ?GenerateSeed_u32@HRNG@lwe@@SAIXZ: + RDSEED EAX + RET + + ?Generate_u32@HRNG@lwe@@SAIII@Z: + RDRAND EAX + MOV R8D, EDX + SUB R8D, ECX + XOR EDX, EDX + DIV R8D + MOV EAX, EDX + ADD EAX, ECX + RET + + ?Generate_u32@HRNG@lwe@@SAIXZ: + RDRAND EAX + RET + + ?GenerateSeed_s32@HRNG@lwe@@SAHXZ: + RDSEED EAX + RET + + ?Generate_s32@HRNG@lwe@@SAHHH@Z: + RDRAND EAX + MOV R8D, EDX + SUB R8D, ECX + XOR EDX, EDX + DIV R8D + MOV EAX, EDX + ADD EAX, ECX + RET + + ?Generate_s32@HRNG@lwe@@SAHXZ: + RDRAND EAX + RET + + ?GenerateSeed_u16@HRNG@lwe@@SAIXZ: + RDSEED AX + RET + + ?Generate_u16@HRNG@lwe@@SAGGG@Z: + RDRAND AX + MOV R8W, DX + SUB R8W, CX + XOR DX, DX + DIV R8W + MOV AX, DX + ADD AX, CX + RET + + ?Generate_u16@HRNG@lwe@@SAGXZ: + RDRAND AX + RET + + ?GenerateSeed_s16@HRNG@lwe@@SAFXZ: + RDSEED AX + RET + + ?Generate_s16@HRNG@lwe@@SAFFF@Z: + RDRAND AX + MOV R8W, DX + SUB R8W, CX + XOR DX, DX + DIV R8W + MOV AX, DX + ADD AX, CX + RET + + ?Generate_s16@HRNG@lwe@@SAFXZ: + RDRAND AX + RET + + ?GenerateSeed_u8@HRNG@lwe@@SAEXZ: + RDSEED AX + RET + + ?Generate_u8@HRNG@lwe@@SAEEE@Z: + RDRAND AX + MOV R8W, DX + SUB R8W, CX + XOR DX, DX + DIV R8W + MOV AX, DX + ADD AX, CX + RET + + ?Generate_u8@HRNG@lwe@@SAEXZ: + RDRAND AX + RET + + ?GenerateSeed_s8@HRNG@lwe@@SACXZ: + RDSEED AX + RET + + ?Generate_s8@HRNG@lwe@@SACCC@Z: + RDRAND AX + MOV R8W, DX + SUB R8W, CX + XOR DX, DX + DIV R8W + MOV AX, DX + ADD AX, CX + RET + + ?Generate_s8@HRNG@lwe@@SACXZ: + RDRAND AX + RET \ No newline at end of file diff --git a/src/Link.h b/src/Link.h new file mode 100644 index 0000000..9d823f3 --- /dev/null +++ b/src/Link.h @@ -0,0 +1,66 @@ +#pragma once + +template +class Link +{ +public: + T value; + Link *child; + + ~Link() + { + delete child; + } + + Link() + : value(), child(nullptr) + { + } + + Link(const T value, Link* child) + : value(value), child(child) + { + } + + Link(const T value) + : value(value), child(nullptr) + { + } + + Link(const Link& link) + : value(link.value), child(nullptr) + { + } + + Link(Link&& link) noexcept + : value(link.value), child(link.child) + { + link.value = 0; + link.child = nullptr; + } + + Link& operator=(const Link& link) + { + if (this == &link) + return *this; + + value = link.value; + child = nullptr; + + return *this; + } + + Link& operator=(Link&& link) noexcept + { + if (this == &link) + return *this; + + value = link.value; + child = link.child; + + link.value = 0; + link.child = nullptr; + + return *this; + } +}; \ No newline at end of file diff --git a/src/LinkedList.h b/src/LinkedList.h new file mode 100644 index 0000000..6c3b25a --- /dev/null +++ b/src/LinkedList.h @@ -0,0 +1,236 @@ +#pragma once + +#include "EHS.h" +#include "Link.h" + +template +class LinkedList +{ +private: + Link* start; + Link* end; + N size; + +public: + ~LinkedList() + { + delete start; + } + + LinkedList() + : size(0), start(nullptr), end(nullptr) + { + } + + LinkedList(const LinkedList& list) + : start(nullptr), end(nullptr), size(list.size) + { + const Link* rLast = list.start; + Link* last = new Link(rLast->value); + start = last; + + while (rLast->child) + { + last->child = new Link(rLast->child->value); + last = last->child; + rLast = rLast->child; + } + + end = last; + } + + LinkedList(LinkedList&& list) noexcept + : start(list.start), end(list.end), size(list.size) + { + list.start = nullptr; + list.end = nullptr; + list.size = {}; + } + + LinkedList& operator=(const LinkedList& list) + { + if (this == &list) + return *this; + + const Link* rLast = list.start; + Link* last = new Link(rLast->value); + start = last; + + while (rLast->child) + { + last->child = new Link(rLast->child->value); + last = last->child; + rLast = rLast->child; + } + + end = last; + size = list.size; + + return *this; + } + + LinkedList& operator=(LinkedList&& list) noexcept + { + if (this == &list) + return *this; + + start = list.start; + end = list.end; + size = list.size; + + list.start = nullptr; + list.end = nullptr; + list.size = {}; + + return *this; + } + + const Link* operator[](const N index) const + { + const Link* result = start; + + for (N i = 0; i != index; ++i) + result = result->child; + + return result; + } + + Link* operator[](const N index) + { + Link* result = start; + + for (N i = 0; i != index; ++i) + result = result->child; + + return result; + } + + T& Insert(const N index, const T value) + { + if (index && index == size - 1) + { + end->child = new Link(value); + end = end->child; + ++size; + return end->value; + } + else if (index) + { + Link* hierarchy = start; + for (N i = 0; i != index - 1; ++i) + hierarchy = hierarchy->child; + + hierarchy->child = new Link(value, hierarchy->child); + ++size; + return hierarchy->child->value; + } + else + { + start = new Link(value, start); + ++size; + return start->value; + } + } + + T Remove(const N index) + { + if (index && index == size - 1) + { + Link* hierarchy = start; + while (hierarchy->child->child) + hierarchy = hierarchy->child; + + T result = end->value; + delete end; + end = hierarchy; + --size; + return result; + } + else if (index) + { + Link* hierarchy = start; + for (N i = 0; i != index - 1; ++i) + hierarchy = hierarchy->child; + + Link* tmp = hierarchy->child; + T result = tmp->value; + hierarchy->child = hierarchy->child->child; + tmp->child = nullptr; + delete tmp; + return result; + } + else + { + Link* tmp = start; + T result = tmp->value; + start = start->child; + + if (--size) + tmp->child = nullptr; + else + end = nullptr; + + delete tmp; + + return result; + } + } + + T& Push(const T value) + { + if (size) + { + end->child = new Link(value); + end = end->child; + ++size; + return end->value; + } + else + { + start = new Link(value); + end = start; + size = 1; + return start->value; + } + } + + T Pop() + { + if (size == 1) + { + T result = start->value; + delete start; + start = nullptr; + end = nullptr; + size = 0; + return result; + } + if (size > 1) + { + Link* hierarchy = start; + while (hierarchy->child->child) + hierarchy = hierarchy->child; + + T result = hierarchy->child->value; + delete hierarchy->child; + hierarchy->child = nullptr; + end = hierarchy; + return result; + } + else + return {}; + } + + void Clear() + { + delete start; + start = nullptr; + end = nullptr; + size = 0; + } + + N Size() const + { + return size; + } +}; \ No newline at end of file diff --git a/src/Mat2.h b/src/Mat2.h new file mode 100644 index 0000000..70de62b --- /dev/null +++ b/src/Mat2.h @@ -0,0 +1,214 @@ +#pragma once + +#include "EHS.h" +#include "Vec2.h" + +template +class Mat2 +{ +private: + T data[4]; + +public: + Mat2() + { + for (UInt_8 i = 0; i < 4; ++i) + data[i] = 0; + } + + template + Mat2(const Mat2& mat) + { + for (UInt_8 i = 0; i < 4; ++i) + data[i] = mat.data[i]; + } + + template + Mat2& operator=(const Mat2& mat) + { + if (this == &mat) + return *this; + + for (UInt_8 i = 0; i < 4; ++i) + data[i] = mat.data[i]; + + return *this; + } + + operator const T*() const + { + return data; + } + + operator T*() + { + return data; + } + + Vec2 operator*(Vec2 vec) const + { + Vec2 result; + result.x = vec.x * data[0] + vec.y * data[2]; + result.y = vec.x * data[1] + vec.y * data[3]; + + return result; + } + + Mat2& operator*=(const T scalar) + { + for (UInt_8 i = 0; i < 4; ++i) + data[i] *= scalar; + + return *this; + } + + Mat2 operator*(const T scalar) const + { + Mat2 result; + for (UInt_8 i = 0; i < 4; ++i) + result.data[i] = data[i] * scalar; + + return result; + } + + Mat2& operator*=(const Mat2& mat) + { + Mat2 old = *this; + for (UInt_8 i = 0; i < 4; ++i) + { + UInt_8 row = i / 2; + UInt_8 column = i % 2; + data[i] = 0; + data[i] += old.data[0 * 2 + column] * mat.data[row * 2 + 0]; + data[i] += old.data[1 * 2 + column] * mat.data[row * 2 + 1]; + } + + return *this; + } + + Mat2 operator*(const Mat2& mat) const + { + Mat2 result; + for (UInt_8 i = 0; i < 4; ++i) + { + UInt_8 row = i / 2; + UInt_8 column = i % 2; + result.data[i] += data[0 * 2 + column] * mat.data[row * 2 + 0]; + result.data[i] += data[1 * 2 + column] * mat.data[row * 2 + 1]; + } + + return result; + } + + Mat2 GetTranspose() const + { + Mat2 result; + for (UInt_8 i = 0; i < 4; ++i) + result.data[i] = data[2 * (i % 2) + i / 2]; + + return result; + } + + void Transpose() + { + Mat2 old = *this; + for (UInt_8 i = 0; i < 4; ++i) + data[i] = old.data[2 * (i % 2) + i / 2]; + } + + Mat2 GetMinor() const + { + Mat2 result(0); + result.data[0] = data[3]; + result.data[1] = data[2]; + result.data[2] = data[1]; + result.data[3] = data[0]; + return result; + } + + void Minor() + { + Mat2 old = *this; + data[0] = old.data[3]; + data[1] = old.data[2]; + data[2] = old.data[1]; + data[3] = old.data[0]; + } + + T GetDeterminant() const + { + return data[0] * data[3] - data[1] * data[2]; + } + + Mat2 GetCofactor() const + { + Mat2 minor = GetMinor(); + Mat2 result; + + for (UInt_8 r = 0; r < 2; ++r) + { + for (UInt_8 c = 0; c < 2; ++c) + { + UInt_8 i = 2 * c + r; + result.data[i] = minor.data[i] * Math::Pow(-1, r + c); + } + } + + return result; + } + + void Cofactor() + { + Mat2 minor = GetMinor(); + + for (UInt_8 r = 0; r < 2; ++r) + { + for (UInt_8 c = 0; c < 2; ++c) + { + UInt_8 i = 2 * c + r; + data[i] = minor.data[i] * Math::Pow(-1, r + c); + } + } + } + + Mat2 GetAdjugate() const + { + return GetCofactor().GetTranspose(); + } + + void Adjugate() + { + Cofactor(); + Transpose(); + } + + Mat2 GetInverse() const + { + T det = GetDeterminant(); + if (Math::ComCmp(det, 0.0f)) + return {}; + + return GetAdjugate() * (1 / det); + } + + void Inverse() + { + T det = GetDeterminant(); + if (Math::ComCmp(det, 0.0f)) + return; + + Adjugate(); + operator*=(1 / det); + } + + static Mat2 Identity() + { + Mat2 result; + result[0] = 1; + result[3] = 1; + return result; + } +}; + +typedef Mat2 Mat2_f; +typedef Mat2 Mat2_d; \ No newline at end of file diff --git a/src/Mat3.h b/src/Mat3.h new file mode 100644 index 0000000..2963b71 --- /dev/null +++ b/src/Mat3.h @@ -0,0 +1,319 @@ +#pragma once + +#include "EHS.h" +#include "Vec3.h" +#include "Mat2.h" + +template +class Mat3 +{ +private: + T data[9]; + +public: + Mat3() + { + for (UInt_8 i = 0; i < 9; ++i) + data[i] = 0; + } + + template + Mat3(const Mat2& mat) + { + for (UInt_8 i = 0; i < 4; ++i) + data[i / 2 * 4 + i % 2] = mat.data[i]; + } + + template + Mat3(const Mat3& mat) + { + for (UInt_8 i = 0; i < 9; ++i) + data[i] = mat.data[i]; + } + + template + Mat3& operator=(const Mat3& mat) + { + if (this == &mat) + return *this; + + for (UInt_8 i = 0; i < 9; ++i) + data[i] = mat.data[i]; + + return *this; + } + + operator Mat2() const + { + Mat2 result; + + for (UInt_8 i = 0; i < 4; ++i) + result.data[i] = data[i / 2 * 4 + i % 2]; + + return result; + } + + operator const T*() const + { + return data; + } + + operator T*() + { + return data; + } + + Vec3 operator*(Vec3 vec) const + { + Vec3 result; + result.x = vec.x * data[0] + vec.y * data[3] + vec.z * data[6]; + result.y = vec.x * data[1] + vec.y * data[4] + vec.z * data[7]; + result.z = vec.x * data[2] + vec.y * data[5] + vec.z * data[8]; + + return result; + } + + Mat3& operator*=(const T scalar) + { + for (UInt_8 i = 0; i < 9; ++i) + data[i] *= scalar; + + return *this; + } + + Mat3 operator*(const T scalar) const + { + Mat3 result; + for (UInt_8 i = 0; i < 9; ++i) + result.data[i] = data[i] * scalar; + + return result; + } + + Mat3& operator*=(const Mat3& mat) + { + Mat3 old = *this; + for (UInt_8 i = 0; i < 9; ++i) + { + UInt_8 row = i / 3; + UInt_8 column = i % 3; + data[i] = 0; + data[i] += old.data[0 * 3 + column] * mat.data[row * 3 + 0]; + data[i] += old.data[1 * 3 + column] * mat.data[row * 3 + 1]; + data[i] += old.data[2 * 3 + column] * mat.data[row * 3 + 2]; + } + + return *this; + } + + Mat3 operator*(const Mat3& mat) const + { + Mat3 result; + for (UInt_8 i = 0; i < 9; ++i) + { + UInt_8 row = i / 3; + UInt_8 column = i % 3; + result.data[i] += data[0 * 3 + column] * mat.data[row * 3 + 0]; + result.data[i] += data[1 * 3 + column] * mat.data[row * 3 + 1]; + result.data[i] += data[2 * 3 + column] * mat.data[row * 3 + 2]; + } + + return result; + } + + Mat3 GetTranspose() const + { + Mat3 result; + for (UInt_8 i = 0; i < 9; ++i) + result.data[i] = data[3 * (i % 3) + i / 3]; + + return result; + } + + void Transpose() + { + Mat3 old = *this; + for (UInt_8 i = 0; i < 9; ++i) + data[i] = old.data[3 * (i % 3) + i / 3]; + } + + Mat3 GetMinor() const + { + Mat3 result; + + for (UInt_8 r = 0; r < 3; ++r) + for (UInt_8 c = 0; c < 3; ++c) + result[3 * r + c] = Cut(r, c).GetDeterminant(); + + return result; + } + + void Minor() + { + Mat3 old = *this; + + for (UInt_8 r = 0; r < 3; ++r) + for (UInt_8 c = 0; c < 3; ++c) + data[3 * r + c] = old.Cut(r, c).GetDeterminant(); + } + + Mat2 Cut(const UInt_8 row, const UInt_8 column) const + { + Mat2 result; + UInt_8 index = 0; + + for (UInt_8 r = 0; r < 3; ++r) + { + for (UInt_8 c = 0; c < 3; ++c) + { + if (r == row || c == column) + continue; + + result[index++] = data[3 * r + c]; + } + } + + return result; + } + + T GetDeterminant() const + { + Mat3 cofactor = GetCofactor(); + T result = 0; + + for (UInt_8 c = 0; c < 3; ++c) + result += data[c] * cofactor[c]; + + return result; + } + + Mat3 GetCofactor() const + { + Mat3 minor = GetMinor(); + Mat3 result; + + for (UInt_8 r = 0; r < 3; ++r) + { + for (UInt_8 c = 0; c < 3; ++c) + { + UInt_8 i = 3 * c + r; + result.data[i] = minor.data[i] * Math::Pow(-1, r + c); + } + } + + return result; + } + + void Cofactor() + { + Mat3 minor = GetMinor(); + + for (UInt_8 r = 0; r < 3; ++r) + { + for (UInt_8 c = 0; c < 3; ++c) + { + UInt_8 i = 3 * c + r; + data[i] = minor.data[i] * Math::Pow(-1, r + c); + } + } + } + + Mat3 GetAdjugate() const + { + return GetCofactor().GetTranspose(); + } + + void Adjugate() + { + Cofactor(); + Transpose(); + } + + Mat3 GetInverse() const + { + T det = GetDeterminant(); + if (Math::ComCmp(det, 0.0f)) + return {}; + + return GetAdjugate() * (1 / det); + } + + void Inverse() + { + T det = GetDeterminant(); + if (Math::ComCmp(det, 0.0f)) + return; + + Adjugate(); + operator*=(1 / det); + } + + static Mat3 Identity() + { + Mat3 result; + result.data[0] = 1; + result.data[4] = 1; + result.data[8] = 1; + return result; + } + + static Mat3 Scale(const Vec3& scale) + { + Mat3 result; + result.data[0] = scale.x; + result.data[4] = scale.y; + result.data[8] = scale.z; + + return result; + } + + static Mat3 PitchRotate(const T angle) + { + T radians = Math::Rads(angle); + + Mat3 result; + result.data[0] = 1; + result.data[4] = Math::Cos(radians); + result.data[5] = Math::Sin(radians); + result.data[7] = -Math::Sin(radians); + result.data[8] = Math::Cos(radians); + + return result; + } + + static Mat3 YawRotate(const T angle) + { + T radians = Math::Rads(angle); + + Mat3 result; + result.data[0] = Math::Cos(radians); + result.data[2] = -Math::Sin(radians); + result.data[4] = 1; + result.data[6] = Math::Sin(radians); + result.data[8] = Math::Cos(radians); + + return result; + } + + static Mat3 RollRotate(const T angle) + { + T radians = Math::Rads(angle); + + Mat3 result; + result.data[0] = Math::Cos(radians); + result.data[1] = Math::Sin(radians); + result.data[3] = -Math::Sin(radians); + result.data[4] = Math::Cos(radians); + result.data[8] = 1; + + return result; + } + + static Mat3 Rotate(const Vec3& vec) + { + return YawRotate(vec.y) * RollRotate(vec.z) * PitchRotate(vec.x); + } +}; + +typedef Mat3 Mat3_f; +typedef Mat3 Mat3_d; \ No newline at end of file diff --git a/src/Mat4.h b/src/Mat4.h new file mode 100644 index 0000000..0d34080 --- /dev/null +++ b/src/Mat4.h @@ -0,0 +1,420 @@ +#pragma once + +#include "EHS.h" +#include "Math.h" +#include "Mat3.h" +#include "Vec4.h" +#include "Vec3.h" + +template +class Mat4 +{ +private: + friend class Uniform; + + T data[16]; + +public: + Mat4() + { + for (UInt_8 i = 0; i < 16; ++i) + data[i] = 0; + } + + explicit Mat4(const T* data) + { + for (UInt_8 i = 0; i < 16; ++i) + this->data[i] = data[i]; + } + + template + Mat4(const Mat3& mat) + { + for (UInt_8 i = 0; i < 9; ++i) + { + UInt_8 row = i / 3; + UInt_8 column = i % 3; + UInt_8 dst = row * 4 + column; + + data[dst] = (T)mat[i]; + } + + data[3] = 0; + data[7] = 0; + data[11] = 0; + data[12] = 0; + data[13] = 0; + data[14] = 0; + data[15] = 1; + } + + template + Mat4(const Mat4& mat) + { + for (UInt_8 i = 0; i < 16; ++i) + data[i] = (T)mat.data[i]; + } + + template + Mat4& operator=(const Mat4& mat) + { + if (this == &mat) + return *this; + + for (UInt_8 i = 0; i < 16; ++i) + data[i] = (T)mat.data[i]; + + return *this; + } + + Vec4 operator*(Vec4 vec) const + { + Vec4 result; + result.x = vec.x * data[0] + vec.y * data[4] + vec.z * data[8] + vec.w * data[12]; + result.y = vec.x * data[1] + vec.y * data[5] + vec.z * data[9] + vec.w * data[13]; + result.z = vec.x * data[2] + vec.y * data[6] + vec.z * data[10] + vec.w * data[14]; + result.w = vec.x * data[3] + vec.y * data[7] + vec.z * data[11] + vec.w * data[15]; + + return result; + } + + Mat4& operator*=(const T scalar) + { + for (UInt_8 i = 0; i < 16; ++i) + data[i] *= scalar; + + return *this; + } + + Mat4 operator*(const T scalar) const + { + Mat4 result; + for (UInt_8 i = 0; i < 16; ++i) + result.data[i] = data[i] * scalar; + + return result; + } + + Mat4& operator*=(const Mat4& mat) + { + Mat4 old = *this; + for (UInt_8 i = 0; i < 16; ++i) + { + UInt_8 row = i / 4; + UInt_8 column = i % 4; + data[i] += old.data[0 * 4 + column] * mat.data[row * 4 + 0]; + data[i] += old.data[1 * 4 + column] * mat.data[row * 4 + 1]; + data[i] += old.data[2 * 4 + column] * mat.data[row * 4 + 2]; + data[i] += old.data[3 * 4 + column] * mat.data[row * 4 + 3]; + } + + return *this; + } + + Mat4 operator*(const Mat4& mat) const + { + Mat4 result; + for (UInt_8 i = 0; i < 16; ++i) + { + UInt_8 row = i / 4; + UInt_8 column = i % 4; + result.data[i] += data[0 * 4 + column] * mat.data[row * 4 + 0]; + result.data[i] += data[1 * 4 + column] * mat.data[row * 4 + 1]; + result.data[i] += data[2 * 4 + column] * mat.data[row * 4 + 2]; + result.data[i] += data[3 * 4 + column] * mat.data[row * 4 + 3]; + } + + return result; + } + + operator const T*() const + { + return data; + } + + operator T*() + { + return data; + } + + Vec3 GetRight() const + { + return Vec3(data[0], data[4], data[8]); + } + + Vec3 GetUp() const + { + return Vec3(data[1], data[5], data[9]); + } + + Vec3 GetForward() const + { + return Vec3(data[2], data[6], data[10]); + } + + Mat4 GetTranspose() const + { + Mat4 result; + for (UInt_8 i = 0; i < 16; ++i) + result.data[i] = data[4 * (i % 4) + i / 4]; + + return result; + } + + void Transpose() + { + Mat4 old = *this; + for (UInt_8 i = 0; i < 16; ++i) + data[i] = old.data[4 * (i % 4) + i / 4]; + } + + Mat3 Cut(const UInt_8 row, const UInt_8 column) const + { + Mat3 result; + UInt_8 index = 0; + + for (UInt_8 r = 0; r < 4; ++r) + { + for (UInt_8 c = 0; c < 4; ++c) + { + if (r == row || c == column) + continue; + + result[index++] = data[4 * r + c]; + } + } + + return result; + } + + Mat4 GetMinor() const + { + Mat4 result; + + for (UInt_8 r = 0; r < 4; ++r) + for (UInt_8 c = 0; c < 4; ++c) + result.data[4 * r + c] = Cut(r, c).GetDeterminant(); + + return result; + } + + void Minor() + { + Mat4 old = *this; + + for (UInt_8 r = 0; r < 4; ++r) + for (UInt_8 c = 0; c < 4; ++c) + data[4 * r + c] = old.Cut(r, c).GetDeterminant(); + } + + Mat4 GetCofactor() const + { + Mat4 minor = GetMinor(); + Mat4 result; + + for (UInt_8 r = 0; r < 4; ++r) + { + for (UInt_8 c = 0; c < 4; ++c) + { + UInt_8 i = 4 * c + r; + result.data[i] = minor.data[i] * Math::Pow(-1, r + c); + } + } + + return result; + } + + void Cofactor() + { + Mat4 minor = GetMinor(); + + for (UInt_8 r = 0; r < 4; ++r) + { + for (UInt_8 c = 0; c < 4; ++c) + { + UInt_8 i = 4 * c + r; + data[i] = minor.data[i] * Math::Pow(-1, r + c); + } + } + } + + T GetDeterminant() const + { + Mat4 cofactor = GetCofactor(); + T result = 0; + + for (UInt_8 c = 0; c < 4; ++c) + result += data[c] * cofactor[c]; + + return result; + } + + Mat4 GetAdjugate() const + { + return GetCofactor().GetTranspose(); + } + + void Adjugate() + { + Cofactor(); + Transpose(); + } + + Mat4 GetInverse() const + { + T det = GetDeterminant(); + if (Math::ComCmp(det, 0.0f)) + return {}; + + return GetAdjugate() * (1 / det); + } + + void Inverse() + { + T det = GetDeterminant(); + if (Math::ComCmp(det, 0.0f)) + return; + + Adjugate(); + operator*=(1 / det); + } + + static Mat4 Identity() + { + Mat4 result; + result.data[0] = 1; + result.data[5] = 1; + result.data[10] = 1; + result.data[15] = 1; + return result; + } + + static Mat4 Scale(const Vec3& scale) + { + Mat4 result; + result.data[0] = scale.x; + result.data[5] = scale.y; + result.data[10] = scale.z; + result.data[15] = 1; + + return result; + } + + static Mat4 Translate(const Vec3& pos) + { + Mat4 result = Identity(); + result.data[12] = pos.x; + result.data[13] = pos.y; + result.data[14] = pos.z; + + return result; + } + + static Mat4 PitchRotate(const T angle) + { + T radians = Math::Rads(angle); + + Mat4 result; + result.data[0] = 1; + result.data[5] = Math::Cos(radians); + result.data[6] = Math::Sin(radians); + result.data[9] = -Math::Sin(radians); + result.data[10] = Math::Cos(radians); + result.data[15] = 1; + + return result; + } + + static Mat4 YawRotate(const T angle) + { + T radians = Math::Rads(angle); + + Mat4 result; + result.data[0] = Math::Cos(radians); + result.data[2] = -Math::Sin(radians); + result.data[5] = 1; + result.data[8] = Math::Sin(radians); + result.data[10] = Math::Cos(radians); + result.data[15] = 1; + + return result; + } + + static Mat4 RollRotate(const T angle) + { + T radians = Math::Rads(angle); + + Mat4 result; + result.data[0] = Math::Cos(radians); + result.data[1] = Math::Sin(radians); + result.data[4] = -Math::Sin(radians); + result.data[5] = Math::Cos(radians); + result.data[10] = 1; + result.data[15] = 1; + + return result; + } + + static Mat4 Rotate(const Vec3& vec) + { + return YawRotate(vec.y) * RollRotate(vec.z) * PitchRotate(vec.x); + } + + static Mat4 RH_Perspective(const T fov, const T aspect, const T zNear, const T zFar) + { + const float tanHalfFovy = tan(Math::Rads(fov) / 2.0f); + + Mat4 result; + result[0] = 1.0f / (aspect * tanHalfFovy); + result[5] = -1.0f / tanHalfFovy; + result[10] = zFar / (zFar - zNear); + result[14] = -(zFar * zNear) / (zFar - zNear); + + return result; + } + + static Mat4 LH_Perspective(const T fov, const T aspect, const T zNear, const T zFar) + { + const float tanHalfFovy = Math::Tan(Math::Rads(fov) / 2.0f); + + Mat4 result; + result[0] = 1.0f / (aspect * tanHalfFovy); + result[5] = -1.0f / tanHalfFovy; + result[10] = zFar / (zFar - zNear); + result[11] = 1.0f; + result[14] = -(zFar * zNear) / (zFar - zNear); + result[15] = 0.0f; + + return result; + } + + static Mat4 LH_Orthographic(const T left, const T right, const T top, const T bottom, const T zNear, const T zFar) + { + Mat4 result; + result[0] = 2.0f / (right - left); // 0,0 entry + result[5] = 2.0f / (bottom - top); // 1,1 entry + result[10] = 1.0f / (zFar - zNear); // 2,2 entry + result[12] = -(right + left) / (right - left); // 3,0 entry + result[13] = -(bottom + top) / (bottom - top); // 3,1 entry + result[14] = -zNear / (zFar - zNear); // 3,2 entry + result[15] = 1.0f; // 3,3 entry + + return result; + + /* + Mat4 result; + result.data[0] = 2 / (right - left); + result.data[5] = 2 / (top - bottom); + result.data[10] = 1 / (zFar - zNear); + result.data[12] = (left + right) / (left - right); + result.data[13] = (top + bottom) / (bottom - top); + result.data[14] = zNear / (zNear - zFar); + result.data[15] = 1; + + return result; + */ + } +}; + +typedef Mat4 Mat4_f; +typedef Mat4 Mat4_d; \ No newline at end of file diff --git a/src/Math.cpp b/src/Math.cpp new file mode 100644 index 0000000..bc46d12 --- /dev/null +++ b/src/Math.cpp @@ -0,0 +1,87 @@ +#include "Math.h" + +bool Math::AbsCmp(const float a, const float b) +{ + return Abs(a - b) <= fltEpsilon; +} + +bool Math::AbsCmp(const double a, const double b) +{ + return Abs(a - b) <= fltEpsilon; +} + +bool Math::RelCmp(const float a, const float b) +{ + return Abs(a - b) <= fltEpsilon * Max(Abs(a), Abs(b)); +} + +bool Math::RelCmp(const double a, const double b) +{ + return Abs(a - b) <= fltEpsilon * Max(Abs(a), Abs(b)); +} + +bool Math::ComCmp(const float a, const float b) +{ + return Abs(a - b) <= fltEpsilon * Max(1.0f, Max(Abs(a), Abs(b))); +} + +bool Math::ComCmp(const double a, const double b) +{ + return Abs(a - b) <= dblEpsilon * Max(1.0, Max(Abs(a), Abs(b))); +} + +double Math::Sqrt(const double from) +{ + #if defined(ARCH_X64) + if (CPU::HasAVX()) + return Sqrt_AVX(from); + else if (CPU::HasSSE()) + return Sqrt_SSE2(from); + + double temp = 0.0; + double result = from / 2.0; + + while (result != temp) + { + temp = result; + result = (from / temp + temp) / 2.0; + } + + return result; + #elif defined(ARCH_ARM64) + return Sqrt_VFP4(from); + #endif +} + +float Math::Sqrt(const float from) +{ + #if defined(ARCH_X64) + if (CPU::HasAVX()) + return Sqrt_AVX(from); + else if (CPU::HasSSE()) + return Sqrt_SSE(from); + + float temp = 0.0f; + float result = from / 2.0f; + + while (result != temp) + { + temp = result; + result = (from / temp + temp) / 2.0f; + } + + return result; + #elif defined(ARCH_ARM64) + return Sqrt_VFP4(from); + #endif +} + +float Math::Mod(const float from, const float divisor) +{ + return from - Trunc(from / divisor) * divisor; +} + +double Math::Mod(const double from, const double divisor) +{ + return from - Trunc(from / divisor) * divisor; +} \ No newline at end of file diff --git a/src/Math.h b/src/Math.h new file mode 100644 index 0000000..d294ee3 --- /dev/null +++ b/src/Math.h @@ -0,0 +1,313 @@ +#pragma once + +#include "sys/cpu.h" + +#define LOW_WORD(x) *((int*)&x) + 1 + +class Math +{ +private: + static float Sqrt_AVX(const float from); + + static double Sqrt_AVX(const double from); + + static float Sqrt_SSE(const float from); + + static double Sqrt_SSE2(const double from); + + static float Sqrt_VFP4(const float from); + + static double Sqrt_VFP4(const double from); + +public: + constexpr static float fltEpsilon = 1e-7f; + constexpr static double dblEpsilon = 1e-16; + + /// Absolute tolerance comparison for single precision floats. + static bool AbsCmp(const float a, const float b); + + /// Absolute tolerance comparison for double precision floats. + static bool AbsCmp(const double a, const double b); + + /// Relative tolerance comparison for single precision floats. + static bool RelCmp(const float a, const float b); + + /// Relative tolerance comparison for double precision floats. + static bool RelCmp(const double a, const double b); + + /// Combined absolute and relative tolerance comparison for single precision floats. + static bool ComCmp(const float a, const float b); + + /// Combined absolute and relative tolerance comparison for double precision floats. + static bool ComCmp(const double a, const double b); + + template + static T Max(const T a, const T b) + { + return a > b ? a : b; + } + + template + static T Min(const T a, const T b) + { + return a < b ? a : b; + } + + template + static T Clamp(const T value, const T min, const T max) + { + if (value < min) + return min; + else if (value > max) + return max; + + return value; + } + + template + static T Abs(const T from) + { + return from < 0 ? -from : from; + } + + /// Retrieves a very accurate version of Pi as a long double and converts it. + /// @tparam T The data type to return Pi as. + /// @returns The result. + template + static constexpr T Pi() + { + return (T)3.141592653589793238462643383279502884L; + } + + /// Converts degrees into radians. + /// @tparam T The data type to return; + /// @param [in] from The value to convert to radians. + /// @returns The value in radians. + template + static T Rads(const T from) + { + return from * 0.01745329251994329576923690768489; + } + + /// Converts radians into degrees. + /// @tparam T The data type to return; + /// @param [in] from The value to convert to degrees. + /// @returns The value in degrees. + template + static T Degr(const T from) + { + return from * 57.295779513082320876798154814105; + } + + /// A method for use of exponents. + /// @tparam T The data type to return; + /// @tparam I The data type to use as the exponent. + /// @param [in] from The value to use the exponent on. + /// @param [in] of The exponent. + /// @returns The result. + template + static T Pow(const T from, const I of) + { + if (of < 0) + { + if (from == 0) + return -0; + + return 1 / (from * Pow(from, (-of) - 1)); + } + + if (of == 0) + return 1; + else if (of == 1) + return from; + + return from * Pow(from, of - 1); + } + + static float Near(const float from); + + static double Near(const double from); + + static float Floor(const float from); + + static double Floor(const double from); + + static float Ceil(const float from); + + static double Ceil(const double from); + + static float Trunc(const float from); + + static double Trunc(const double from); + + static float Mod(const float from, const float divisor); + + static double Mod(const double from, const double divisor); + + /// A method for retrieving the square root of a value. + /// @tparam T The data type to use. + /// @param [in] from The value to retrieve to square root of. + /// @returns The result. + template + static T Sqrt(const T from) + { + T temp = 0; + T result = from / 2; + + while (result != temp) + { + temp = result; + result = (from / temp + temp) / 2; + } + + return result; + } + + static double Sqrt(const double from); + + static float Sqrt(const float from); + + template + static R Sin(const R angle, const R precision = 0.001) + { + R sum = angle; + R term = angle; + + for (UInt_64 i = 1; Abs(term) >= precision; ++i) + { + term *= -angle * angle / (R)((2 * i + 1) * (2 * i)); + sum += term; + } + + return sum; + + /* + R sum = 0; + + for (USize n = 0; n < precision; ++n) + sum += Pow(-1, n) / (R)Fact(2 * n + 1) * Pow(angle, 2 * n + 1); + + return sum; + */ + } + + template + static R ASin(const R yPos, const T precision = 10) + { + R sum = 0; + + for (T n = 0; n < precision; ++n) + sum += (R)Fact(2 * n) / (Pow(4, n) * Pow((R)Fact(n), 2) * (2 * n + 1)) * Pow(yPos, 2 * n + 1); + + return sum; + } + + /// A trigonometry Cosine function for finding the X-Axis position from the Z-Axis angle. + /// @tparam R Input and result data type. + /// @tparam T Precision data type. + /// @param[in] angle The angle in radians from the Z-Axis. + /// @param [in] precision Sigma max. + /// @returns The X-Axis position. + template + static R Cos(const R angle, const R precision = 0.001) + { + R sum = 1.0; + R term = 1.0; + + for (UInt_64 i = 2; Abs(term) >= precision; i += 2) + { + term *= -angle * angle / (R)(i * (i - 1)); + sum += term; + } + + return sum; + + /* + R sum = 0; + + for (T n = 0; n < precision; ++n) + sum += Pow(-1, n) / (R)Fact(2 * n) * Pow(angle, 2 * n); + + return sum; + */ + } + + /// A trigonometry Arc Cosine function for finding the Z-Axis angle form the X-Axis position. + /// @tparam R Input and result data type. + /// @tparam T Precision data type. + /// @param [in] xPos The position from the X-Axis. + /// @param [in] precision Sigma max. + /// @returns The Z-Axis angle. + template + static R ACos(const R xPos, const T precision = 10) + { + return Pi() / 2 - ASin(xPos, precision); + } + + template + static R Tan(const R angle, const R precision = 0.001) + { + /* + R sum = 0; + + for (T n = 1; n < precision + 1; ++n) + sum += B(2 * n) * Pow(-4, n) * (1 - Pow(4, n)) / (R)Fact(2 * n) * Pow(angle, 2 * n - 1); + + return sum; + */ + return Sin(angle) / Cos(angle); + } + + template + static R ATan(const R x, const T precision = 1) + { + R sum = 0; + + for (T n = 0; n < precision; ++n) + sum += Pow(-1, n) / (2 * n + 1) * Pow(x, 2 * n + 1); + + return sum; + } + + template + static R Cot(const R x, const R precision = 0.001) + { + return 1 / Tan(x, precision); + } + + template + static T Fact(const T n) + { + if (n <= 1) + return 1; + + return n * Fact(n - 1); + } + + template + static R Combination(const T n, const T k) + { + if (k <= n) + return (R)Fact(n) / (R)(Fact(n - k) * Fact(k)); + + return 0; + } + + template + static R B(const T n) + { + R innerSum = 0; + R outerSum = 0; + + for (T k = 0; k <= n; ++k) + { + for (T r = 0; r <= k; ++r) + innerSum += Pow(-1, r) * Combination(k, r) * Pow(r, n); + + outerSum += 1 / ((R)k + 1) * innerSum; + innerSum = 0; + } + + return outerSum; + } +}; \ No newline at end of file diff --git a/src/Math_GCC_AMD64.s b/src/Math_GCC_AMD64.s new file mode 100644 index 0000000..b08777f --- /dev/null +++ b/src/Math_GCC_AMD64.s @@ -0,0 +1,61 @@ +global _ZN3lwe4Math8Sqrt_AVXEf +global _ZN3lwe4Math8Sqrt_AVXEd +global _ZN3lwe4Math8Sqrt_SSEEf +global _ZN3lwe4Math9Sqrt_SSE2Ed +global _ZN3lwe4Math4NearEf +global _ZN3lwe4Math4NearEd +global _ZN3lwe4Math5FloorEf +global _ZN3lwe4Math5FloorEd +global _ZN3lwe4Math4CeilEf +global _ZN3lwe4Math4CeilEd +global _ZN3lwe4Math5TruncEf +global _ZN3lwe4Math5TruncEd + +section .text + _ZN3lwe4Math8Sqrt_AVXEf: + VSQRTPS XMM0, XMM0 + RET + + _ZN3lwe4Math8Sqrt_AVXEd: + VSQRTPD XMM0, XMM0 + RET + + _ZN3lwe4Math8Sqrt_SSEEf: + SQRTPS XMM0, XMM0 + RET + + _ZN3lwe4Math9Sqrt_SSE2Ed: + SQRTPD XMM0, XMM0 + RET + + _ZN3lwe4Math4NearEf: + ROUNDPS XMM0, XMM0, 0 + RET + + _ZN3lwe4Math4NearEd: + ROUNDPD XMM0, XMM0, 0 + RET + + _ZN3lwe4Math5FloorEf: + ROUNDPS XMM0, XMM0, 1 + RET + + _ZN3lwe4Math5FloorEd: + ROUNDPD XMM0, XMM0, 1 + RET + + _ZN3lwe4Math4CeilEf: + ROUNDPS XMM0, XMM0, 2 + RET + + _ZN3lwe4Math4CeilEd: + ROUNDPD XMM0, XMM0, 2 + RET + + _ZN3lwe4Math5TruncEf: + ROUNDPS XMM0, XMM0, 3 + RET + + _ZN3lwe4Math5TruncEd: + ROUNDPD XMM0, XMM0, 3 + RET \ No newline at end of file diff --git a/src/Math_MSVC_AMD64.s b/src/Math_MSVC_AMD64.s new file mode 100644 index 0000000..19059af --- /dev/null +++ b/src/Math_MSVC_AMD64.s @@ -0,0 +1,61 @@ +global ?Sqrt_AVX@Math@lwe@@CAMM@Z +global ?Sqrt_AVX@Math@lwe@@CANN@Z +global ?Sqrt_SSE@Math@lwe@@CAMM@Z +global ?Sqrt_SSE2@Math@lwe@@CANN@Z +global ?Near@Math@lwe@@SAMM@Z +global ?Near@Math@lwe@@SANN@Z +global ?Floor@Math@lwe@@SAMM@Z +global ?Floor@Math@lwe@@SANN@Z +global ?Ceil@Math@lwe@@SAMM@Z +global ?Ceil@Math@lwe@@SANN@Z +global ?Trunc@Math@lwe@@SAMM@Z +global ?Trunc@Math@lwe@@SANN@Z + +section .text + ?Sqrt_AVX@Math@lwe@@CAMM@Z: + VSQRTPS XMM0, XMM0 + RET + + ?Sqrt_AVX@Math@lwe@@CANN@Z: + VSQRTPD XMM0, XMM0 + RET + + ?Sqrt_SSE@Math@lwe@@CAMM@Z: + SQRTPS XMM0, XMM0 + RET + + ?Sqrt_SSE2@Math@lwe@@CANN@Z: + SQRTPD XMM0, XMM0 + RET + + ?Near@Math@lwe@@SAMM@Z: + ROUNDPS XMM0, XMM0, 0 + RET + + ?Near@Math@lwe@@SANN@Z: + ROUNDPD XMM0, XMM0, 0 + RET + + ?Floor@Math@lwe@@SAMM@Z: + ROUNDPS XMM0, XMM0, 1 + RET + + ?Floor@Math@lwe@@SANN@Z: + ROUNDPD XMM0, XMM0, 1 + RET + + ?Ceil@Math@lwe@@SAMM@Z: + ROUNDPS XMM0, XMM0, 2 + RET + + ?Ceil@Math@lwe@@SANN@Z: + ROUNDPD XMM0, XMM0, 2 + RET + + ?Trunc@Math@lwe@@SAMM@Z: + ROUNDPS XMM0, XMM0, 3 + RET + + ?Trunc@Math@lwe@@SANN@Z: + ROUNDPD XMM0, XMM0, 3 + RET \ No newline at end of file diff --git a/src/PRNG.h b/src/PRNG.h new file mode 100644 index 0000000..d082c0b --- /dev/null +++ b/src/PRNG.h @@ -0,0 +1,55 @@ +#pragma once + +#include "EHS.h" + +template +class PRNG +{ +private: + T seed; + T last; + +public: + PRNG() + : seed(0), last(0) + { + } + + PRNG(const T seed) + : seed(seed), last(seed) + { + } + + PRNG(const PRNG& prng) + : seed(prng.seed), last(prng.last) + { + } + + PRNG& operator=(const PRNG& prng) + { + if (this == &prng) + return *this; + + seed = prng.seec; + last = prng.last; + } + + T Generate(const T min, const T max) + { + return Generate() % (max - min) + min; + } + + T Generate() + { + return ((last = last * 214013 + 2531011) >> 16) & 0x7fff; + } +}; + +typedef PRNG PRNG_s64; +typedef PRNG PRNG_u64; +typedef PRNG PRNG_s32; +typedef PRNG PRNG_u32; +typedef PRNG PRNG_s16; +typedef PRNG PRNG_u16; +typedef PRNG PRNG_s8; +typedef PRNG PRNG_u8; \ No newline at end of file diff --git a/src/Quat.h b/src/Quat.h new file mode 100644 index 0000000..15fc707 --- /dev/null +++ b/src/Quat.h @@ -0,0 +1,393 @@ +#pragma once + +#include "EHS.h" +#include "Math.h" +#include "Mat4.h" +#include "Vec3.h" + +template +class Quat +{ +public: + T w; + T x; + T y; + T z; + + Quat() + : w(0), x(0), y(0), z(0) + { + } + + Quat(const T w, const T x, const T y, const T z) + : w(w), x(x), y(y), z(z) + { + } + + Quat(const T yaw, const T pitch, const T roll) + : w(0), x(0), y(0), z(0) + { + T c1 = cos(yaw / 2); + T c2 = cos(pitch / 2); + T c3 = cos(roll / 2); + T s1 = sin(yaw / 2); + T s2 = sin(pitch / 2); + T s3 = sin(roll / 2); + + w = c1 * c2 * c3 - s1 * s2 * s3; + x = s1 * s2 * c3 + c1 * c2 * s3; + y = s1 * c2 * c3 + c1 * s2 * s3; + z = c1 * s2 * c3 - s1 * c2 * s3; + } + + explicit Quat(const Vec3& euler) + : w(0), x(0), y(0), z(0) + { + T c1 = cos(euler.x / 2); + T c2 = cos(euler.y / 2); + T c3 = cos(euler.z / 2); + T s1 = sin(euler.x / 2); + T s2 = sin(euler.y / 2); + T s3 = sin(euler.z / 2); + + w = c1 * c2 * c3 - s1 * s2 * s3; + x = s1 * s2 * c3 + c1 * c2 * s3; + y = s1 * c2 * c3 + c1 * s2 * s3; + z = c1 * s2 * c3 - s1 * c2 * s3; + } + + Quat(const Vec3& n, const T a) + : w(cosf(a / 2)), x(n.x * sinf(a / 2)), y(n.y * sinf(a / 2)), z(n.z * sinf(a / 2)) + { + } + + explicit Quat(const Mat4& rotMatrix) + : w(0), x(0), y(0), z(0) + { + ToQuaternion(rotMatrix); + } + + Quat(const Quat& quat) + : w(quat.w), x(quat.x), y(quat.y), z(quat.z) + { + } + + explicit Quat(const T scalar) + : w(scalar), x(scalar), y(scalar), z(scalar) + { + } + + Quat& operator=(const Quat& quat) + { + if (this == &quat) + return *this; + + w = quat.w; + x = quat.x; + y = quat.y; + z = quat.z; + + return *this; + } + + Quat& operator=(const Mat4& rotMatrix) + { + ToQuaternion(rotMatrix); + + return *this; + } + + Quat operator+(const Quat& other) const + { + return {w + other.w, x + other.x, y + other.y, z + other.z}; + } + + Quat operator-() const + { + return {-w, -x, -y, -z}; + } + + Quat operator-(const Quat& other) const + { + return {w - other.w, x - other.x, y - other.y, z - other.z}; + } + + Quat operator*(const T scalar) + { + return {w * scalar, x * scalar, x * scalar, x * scalar}; + } + + Quat operator*(const Quat& other) + { + return Quat + ( + w * other.w - x * other.x - y * other.y - z * other.z, + w * other.x + x * other.w + y * other.z - z * other.y, + w * other.y - x * other.z + y * other.w + z * other.x, + w * other.z + x * other.y - y * other.x + z * other.w + ); + } + + Vec3 operator*(const Vec3& vect) + { + Quat tmp(0, vect[0], vect[1], vect[2]); + Vec3 tmpVect(x, y, z); + + Vec3 vcV = tmpVect.CrossProduct(vect); + return vect + vcV * (2 * w) + tmpVect.CrossProduct(vcV) * 2; + } + + Quat operator^(const T t) + { + Vec3 n; + T a; + + ToAxisAngle(&n, &a); + + float at = a * t; + + return Quat(n, at); + } + + bool operator==(const Quat& quat) const + { + return w == quat.w && x == quat.x && y == quat.y && z == quat.z; + } + + bool operator!=(const Quat& quat) const + { + return w != quat.w || x != quat.x || y != quat.y || z == quat.z; + } + + T operator[](const UInt_64 index) const + { + switch (index) + { + case 0: + return w; + case 1: + return x; + case 2: + return y; + case 3: + return z; + default: + return w; + } + } + + T& operator[](const UInt_64 index) + { + switch (index) + { + case 0: + return w; + case 1: + return x; + case 2: + return y; + case 3: + return z; + default: + return w; + } + } + + void ToAxisAngle(Vec3* vectAxis, T* flAngle) + { + Vec3 tmp(x, y, z); + + if (tmp.GetDis2() < 0.0001f) + *vectAxis = Vec3(1, 0, 0); + else + *vectAxis = tmp.GetNorm(); + + *flAngle = acosf(w) * 2; + *flAngle = Math::Degr(*flAngle); + } + + void ToQuaternion(const Mat4& rotMatrix) + { + T trace = rotMatrix[0][0] + rotMatrix[1][1] + rotMatrix[2][2]; + + if (trace > 0) + { + T s = 0.5f / Math::Sqrt(trace + 1.0f); + w = 0.25f / s; + + x = (rotMatrix[2][1] - rotMatrix[1][2]) * s; + y = (rotMatrix[0][2] - rotMatrix[2][0]) * s; + z = (rotMatrix[1][0] - rotMatrix[0][1]) * s; + } else + { + if ((rotMatrix[0][0] > rotMatrix[1][1]) && (rotMatrix[0][0] > rotMatrix[2][2])) + { + T s = 2.0f * Math::Sqrt(1.0f + rotMatrix[0][0] - rotMatrix[1][1] - rotMatrix[2][2]); + w = (rotMatrix[2][1] - rotMatrix[1][2]) / s; + x = 0.25f * s; + y = (rotMatrix[0][1] + rotMatrix[1][0]) / s; + z = (rotMatrix[0][2] + rotMatrix[2][0]) / s; + } else if (rotMatrix[1][1] > rotMatrix[2][2]) + { + T s = 2.0f * sqrtf(1.0f + rotMatrix[1][1] - rotMatrix[0][0] - rotMatrix[2][2]); + w = (rotMatrix[0][2] - rotMatrix[2][0]) / s; + x = (rotMatrix[0][1] + rotMatrix[1][0]) / s; + y = 0.25f * s; + z = (rotMatrix[1][2] + rotMatrix[2][1]) / s; + } else + { + T s = 2.0f * sqrtf(1.0f + rotMatrix[2][2] - rotMatrix[0][0] - rotMatrix[1][1]); + w = (rotMatrix[1][0] - rotMatrix[0][1]) / s; + x = (rotMatrix[0][2] + rotMatrix[2][0]) / s; + y = (rotMatrix[1][2] + rotMatrix[2][1]) / s; + z = 0.25f * s; + } + } + } + + /* + Vec3 ToEulerAngle() const + { + Vec3 euler; + + float ysqr = y * y; + + float t0 = 2 * (w * x + y * z); + float t1 = 1 - 2 * (x * x + ysqr); + euler.z = std::atan2(t0, t1); + + float t2 = 2 * (w * y - z * x); + t2 = t2 > 1 ? 1 : t2; + t2 = t2 < -1 ? -1 : t2; + euler.y = std::asin(t2); + + float t3 = 2 * (w * z + x * y); + float t4 = 1 - 2 * (ysqr + z * z); + euler.x = std::atan2(t3, t4); + + return euler; + } + */ + + Mat4 ToMatrix() const + { + Mat4 result; + + T x2 = x + x; + T y2 = y + y; + T z2 = z + z; + T x2w = x2 * w; + T y2w = y2 * w; + T z2w = z2 * w; + T x2x = x2 * x; + T y2x = y2 * x; + T z2x = z2 * x; + T y2y = y2 * y; + T z2y = z2 * y; + T z2z = z2 * y; + + result[0] = T(1) - (y2y + z2z); + result[1] = y2x - z2w; + result[2] = z2x + y2w; + result[3] = T(0); + + result[4] = y2x + z2w; + result[5] = T(1) - (x2x + z2z); + result[6] = z2y - x2w; + result[7] = T(0); + + result[8] = z2x - y2w; + result[9] = z2y + x2w; + result[10] = T(1) - (x2x + y2y); + result[11] = T(0); + + result[12] = T(0); + result[13] = T(0); + result[14] = T(0); + result[15] = T(1); + + return result; + } + + float GetMagnitude() + { + return Math::Sqrt(Math::Pow(w, 2) + Math::Pow(x, 2) + Math::Pow(y, 2) + Math::Pow(z, 2)); + } + + Quat GetNormalized() + { + T mag = GetMagnitude(); + + return Quat(w / mag, x / mag, y / mag, z / mag); + } + + void Normalize() + { + T mag = GetMagnitude(); + + w = w / mag; + x = x / mag; + y = y / mag; + z = z / mag; + } + + T Dot(const Quat& other) const + { + return w * other.w + x * other.x + y * other.y + z * other.z; + } + + Quat GetConjugate() + { + return Quat(w, -x, -y, -z); + } + + void Conjugate() + { + x = -x; + y = -y; + z = -z; + } + + Quat GetInverse() + { + return Quat(w, -x, -y, -z); + } + + void Inverse() + { + x = -x; + y = -y; + z = -z; + } + + static Quat Slerp(Quat start, Quat finish, const T t) + { + T cosHalfTheta = start.Dot(finish); + if (Math::Abs(cosHalfTheta) >= 1.0f) + return start; + + float halfTheta = Math::ACos(cosHalfTheta); + float sinHalfTheta = Math::Sqrt(1.0f - cosHalfTheta * cosHalfTheta); + if (Math::Abs(sinHalfTheta) < 0.001f) + { + return { + start.w * 0.5f + finish.w * 0.5f, + start.x * 0.5f + finish.x * 0.5f, + start.y * 0.5f + finish.y * 0.5f, + start.z * 0.5f + finish.z * 0.5f + }; + } + + float ratioA = Math::Sin((1 - t) * halfTheta) / sinHalfTheta; + float ratioB = Math::Sin(t * halfTheta) / sinHalfTheta; + + return { + start.w * ratioA + finish.w * ratioB, + start.x * ratioA + finish.x * ratioB, + start.y * ratioA + finish.y * ratioB, + start.z * ratioA + finish.z * ratioB + }; + } +}; + +typedef Quat Quat_f; \ No newline at end of file diff --git a/src/Range.cpp b/src/Range.cpp new file mode 100644 index 0000000..1bae7a6 --- /dev/null +++ b/src/Range.cpp @@ -0,0 +1,5 @@ +// +// Created by Nelso on 3/29/2022. +// + +#include "Range.h" diff --git a/src/Range.h b/src/Range.h new file mode 100644 index 0000000..4e9842d --- /dev/null +++ b/src/Range.h @@ -0,0 +1,25 @@ +#pragma once + + +template +class Range +{ +public: + N min; + N max; + + Range() + : min(0), max(0) + { + } + + Range(const N min, const N max) + : min(min), max(max) + { + } + + Range(const Range& range) + : min(range.min), max(range.max) + { + } +}; \ No newline at end of file diff --git a/src/Rect.h b/src/Rect.h new file mode 100644 index 0000000..8d75561 --- /dev/null +++ b/src/Rect.h @@ -0,0 +1,181 @@ +#pragma once + +#include "EHS.h" +#include "Vec2.h" +#include "Vec3.h" +#include "Vec4.h" + +template +class Rect +{ +public: + T x; + T y; + T w; + T h; + + Rect(const T scalar = 0) + : x(scalar), y(scalar), w(scalar), h(scalar) + { + } + + Rect(const T x, const T y, const T w, const T h) + : x(x), y(y), w(w), h(h) + { + } + + template + Rect(const Vec2& vec, const T w = 0, const T h = 0) + : x((T)vec.x), y((T)vec.y), w(w), h(h) + { + } + + template + Rect(const Vec3& vec, const T h = 0) + : x((T)vec.x), y((T)vec.y), w((T)vec.z), h(h) + { + } + + template + Rect(const Vec4& vec) + : x((T)vec.x), y((T)vec.y), w((T)vec.z), h((T)vec.w) + { + } + + template + Rect(const Rect& rect) + : x((T)rect.x), y((T)rect.y), w((T)rect.w), h((T)rect.h) + { + } + + template + Rect& operator=(const Vec2& vec) + { + x = (T)vec.x; + y = (T)vec.y; + w = 0; + h = 0; + + return *this; + } + + template + Rect& operator=(const Vec3& vec) + { + x = (T)vec.x; + y = (T)vec.y; + w = (T)vec.z; + h = 0; + + return *this; + } + + template + Rect& operator=(const Vec4& vec) + { + x = (T)vec.x; + y = (T)vec.y; + w = (T)vec.z; + h = (T)vec.w; + + return *this; + } + + template + Rect& operator=(const Rect& rect) + { + if (this == &rect) + return *this; + + x = (T)rect.x; + y = (T)rect.y; + w = (T)rect.w; + h = (T)rect.h; + + return *this; + } + + bool operator==(const Vec4& vec) + { + return x == vec.x && y == vec.y && w == vec.z && h == vec.w; + } + + bool operator!=(const Vec4& vec) + { + return x != vec.x || y != vec.y || w != vec.z || h != vec.w; + } + + bool operator==(const Rect& rect) + { + return x == rect.x && y == rect.y && w == rect.w && h == rect.h; + } + + bool operator!=(const Rect& rect) + { + return x != rect.x || y != rect.y || w != rect.w || h != rect.h; + } + + T operator[](const UInt_64 index) const + { + switch (index) + { + case 0: + return x; + case 1: + return y; + case 2: + return w; + case 3: + return h; + default: + return x; + } + } + + T& operator[](const UInt_64 index) + { + switch (index) + { + case 0: + return x; + case 1: + return y; + case 2: + return w; + case 3: + return h; + default: + return x; + } + } + + operator Vec4() + { + return Vec4(x, y, w, h); + } + + Vec2 GetPos() const + { + return {x, y}; + } + + Vec2 GetScale() const + { + return {w, h}; + } +}; + +typedef Rect Rect_u64; +typedef Rect Rect_s64; +typedef Rect Rect_64; +typedef Rect Rect_u32; +typedef Rect Rect_s32; +typedef Rect Rect_32; +typedef Rect Rect_u16; +typedef Rect Rect_s16; +typedef Rect Rect_16; +typedef Rect Rect_u8; +typedef Rect Rect_s8; +typedef Rect Rect_8; +typedef Rect Rect_f; +typedef Rect Rect_d; \ No newline at end of file diff --git a/src/SArray.h b/src/SArray.h new file mode 100644 index 0000000..bba5070 --- /dev/null +++ b/src/SArray.h @@ -0,0 +1,105 @@ +#pragma once + +#include "EHS.h" + +/// This container is useful for sorting arrays efficiently. +template +class SArray +{ +private: + T* data; + N size; + +public: + ~SArray() + { + delete[] data; + } + + SArray() + : data(nullptr), size(0) + { + } + + SArray(const N size) + : data(new T[size]), size(size) + { + } + + SArray(const SArray& sArray) + : data(new T[sArray.size]), size(sArray.size) + { + for (N i = 0; i < size; ++i) + data[i] = sArray.data[i]; + } + + SArray(SArray&& sArray) noexcept + : data(sArray.data), size(sArray.size) + { + sArray.data = nullptr; + sArray.size = 0; + } + + SArray& operator=(const SArray& pArray) + { + if (this == &pArray) + return *this; + + delete[] data; + data = new T[pArray.size]; + for (N i = 0; i < pArray.size; ++i) + data[i] = pArray.data[i]; + + size = pArray.size; + + return *this; + } + + SArray& operator=(SArray&& pArray) noexcept + { + if (this == &pArray) + return *this; + + delete[] data; + data = pArray.data; + size = pArray.size; + + pArray.data = nullptr; + pArray.size = 0; + + return *this; + } + + operator const T* () const + { + return data; + } + + operator T* () + { + return data; + } + + void Insert(const N index, T value) + { + if (index >= size) + { + return; + } + + for (N i = size; i > index + 1; --i) + data[i - 1] = std::move(data[i - 2]); + + data[index] = std::move(value); + } + + void SetSize(const N newSize) + { + size = newSize; + } + + N Size() const + { + return size; + } +}; \ No newline at end of file diff --git a/src/Serializer.h b/src/Serializer.h new file mode 100644 index 0000000..67863a2 --- /dev/null +++ b/src/Serializer.h @@ -0,0 +1,1122 @@ +#pragma once + +#include "EHS.h" +#include "Util.h" +#include "Array.h" +#include "Vector.h" +#include "Str.h" +#include "Version.h" +#include "Vec2.h" +#include "Vec3.h" +#include "Color3.h" +#include "Vec4.h" +#include "Rect.h" +#include "Color4.h" +#include "Quat.h" +#include "Mat2.h" +#include "Mat3.h" +#include "Mat4.h" + +template +class Serializer +{ +private: + Endianness endianness; + Byte* data; + N size; + N offset; + +public: + ~Serializer() + { + delete[] data; + } + + Serializer() + : endianness(Endianness::BE), data(nullptr), size(0), offset(0) + { + } + + Serializer(const Endianness endianness) + : endianness(endianness), data(nullptr), size(0), offset(0) + { + } + + Serializer(const Endianness endianness, const N size) + : endianness(endianness), data(new Byte[size]), size(size), offset(0) + { + } + + Serializer(const Endianness endianness, const Byte* const data, const N size, const N offset = 0) + : endianness(endianness), data(new Byte[size]), size(size), offset(offset) + { + for (N i = 0; i < size; ++i) + this->data[i] = data[i]; + } + + Serializer(const Serializer& serializer) + : endianness(serializer.endianness), data(new Byte[serializer.size]), size(serializer.size), offset(serializer.offset) + { + for (N i = 0; i < serializer.size; ++i) + data[i] = serializer.data[i]; + } + + Serializer(Serializer&& serializer) noexcept + : endianness(serializer.endianness), data(serializer.data), size(serializer.size), offset(serializer.offset) + { + serializer.data = nullptr; + serializer.size = 0; + serializer.offset = 0; + } + + Serializer& operator=(const Serializer& serializer) + { + if (this == &serializer) + return *this; + + endianness = serializer.endianness; + + delete[] data; + data = new Byte[serializer.size]; + for (N i = 0; i < serializer.size; ++i) + data[i] = serializer.data[i]; + + size = serializer.size; + offset = serializer.offset; + + return *this; + } + + Serializer& operator=(Serializer&& serializer) noexcept + { + if (this == &serializer) + return *this; + + endianness = serializer.endianness; + delete[] data; + data = serializer.data; + size = serializer.size; + offset = serializer.offset; + + serializer.data = nullptr; + serializer.size = 0; + serializer.offset = 0; + + return *this; + } + + Serializer& operator+=(const N size) + { + offset += size; + return *this; + } + + Serializer& operator-=(const N size) + { + offset -= size; + return *this; + } + + Serializer& operator*=(const N size) + { + offset *= size; + return *this; + } + + Serializer& operator/=(const N size) + { + offset /= size; + return *this; + } + + Serializer& operator%=(const N size) + { + offset %= size; + return *this; + } + + operator const Byte* () const + { + return data; + } + + operator Byte* () + { + return data; + } + + void SetEndianness(const Endianness newEndianness) + { + endianness = newEndianness; + } + + Endianness GetEndianness() const + { + return endianness; + } + + template + void WriteArray(const T* const value, const O size) + { + if (sizeof(N) + size * sizeof(T) > this->size - offset) + { + N remainder = sizeof(N) + size * sizeof(T) - (this->size - offset); + + Byte* r = new Byte[this->size + remainder]; + + for (N i = 0; i < this->size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + this->size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + { + *(N*)&data[offset] = (N)size; + + offset += sizeof(N); + + for (N i = 0; i < size; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + } + else + { + N tmp = (N)size; + + for (N i = 0; i < sizeof(N); ++i) + data[offset + i] = ((Byte*)&tmp)[sizeof(N) - i - 1]; + + offset += sizeof(N); + + for (N i = 0; i < size; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = ((Byte*)&value[i])[sizeof(T) - i - 1]; + } + } + else + { + if (endianness == Endianness::LE) + { + N tmp = (N)size; + + for (N i = 0; i < sizeof(N); ++i) + data[offset + i] = ((Byte*)&tmp)[sizeof(N) - i - 1]; + + offset += sizeof(N); + + for (N i = 0; i < size; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = ((Byte*)&value[i])[sizeof(T) - i - 1]; + } + else + { + *(N*)&data[offset] = (N)size; + + offset += sizeof(N); + + for (N i = 0; i < size; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + } + } + + offset += sizeof(T) * size; + } + + template + void WriteArray(const Array& value) + { + if (sizeof(N) + value.Size() * sizeof(T) > size - offset) + { + N remainder = sizeof(N) + value.Size() * sizeof(T) - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + { + *(N*)&data[offset] = (N)value.Size(); + + offset += sizeof(N); + + for (N i = 0; i < value.Size(); ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + } + else + { + N tmpSize = (N)value.Size(); + + for (N i = 0; i < sizeof(N); ++i) + data[offset + i] = ((Byte*)&tmpSize)[sizeof(N) - i - 1]; + + offset += sizeof(N); + + for (N i = 0; i < value.Size(); ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = ((Byte*)&value[i])[sizeof(T) - i - 1]; + } + } + else + { + if (endianness == Endianness::LE) + { + N tmpSize = (N)value.Size(); + + for (N i = 0; i < sizeof(N); ++i) + data[offset + i] = ((Byte*)&tmpSize)[sizeof(N) - i - 1]; + + offset += sizeof(N); + + for (N i = 0; i < value.Size(); ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = ((Byte*)&value[i])[sizeof(T) - i - 1]; + } + else + { + *(N*)&data[offset] = (N)value.Size(); + + offset += sizeof(N); + + for (N i = 0; i < value.Size(); ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + } + } + + offset += sizeof(T) * value.Size(); + } + + template + void WriteVector(const Vector& value) + { + if (sizeof(N) + value.Size() * sizeof(T) > size - offset) + { + N remainder = sizeof(N) + value.Size() * sizeof(T) - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + { + *(N*)&data[offset] = (N)value.Size(); + + offset += sizeof(N); + + for (N i = 0; i < value.Size(); ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + } + else + { + N tmpSize = (N)value.Size(); + + for (N i = 0; i < sizeof(N); ++i) + data[offset + i] = ((Byte*)&tmpSize)[sizeof(N) - i - 1]; + + offset += sizeof(N); + + for (N i = 0; i < value.Size(); ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = ((Byte*)&value[i])[sizeof(T) - i - 1]; + } + } + else + { + if (endianness == Endianness::LE) + { + N tmpSize = (N)value.Size(); + + for (N i = 0; i < sizeof(N); ++i) + data[offset + i] = ((Byte*)&tmpSize)[sizeof(N) - i - 1]; + + offset += sizeof(N); + + for (N i = 0; i < value.Size(); ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = ((Byte*)&value[i])[sizeof(T) - i - 1]; + } + else + { + *(N*)&data[offset] = (N)value.Size(); + + offset += sizeof(N); + + for (N i = 0; i < value.Size(); ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + } + } + + offset += sizeof(T) * value.Size(); + } + + template + void WriteStr(const Str& str) + { + if (sizeof(N) + sizeof(T) * str.Size() > size - offset) + { + N remainder = sizeof(N) + sizeof(T) * str.Size() - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + { + *(N*)&data[offset] = (N)str.Size(); + + offset += sizeof(N); + + for (N i = 0; i < str.Size(); ++i) + *(T*)&data[offset + i * sizeof(T)] = str[i]; + } + else + { + N tmpSize = (N)str.Size(); + + for (N i = 0; i < sizeof(N); ++i) + data[offset + i] = ((Byte*)&tmpSize)[sizeof(N) - i - 1]; + + offset += sizeof(N); + + for (N i = 0; i < str.Size(); ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = ((Byte*)&str[i])[sizeof(T) - i - 1]; + } + } + else + { + if (endianness == Endianness::LE) + { + N tmpSize = (N)str.Size(); + + for (N i = 0; i < sizeof(N); ++i) + data[offset + i] = ((Byte*)&tmpSize)[sizeof(N) - i - 1]; + + offset += sizeof(N); + + for (N i = 0; i < str.Size(); ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = ((Byte*)&str[i])[sizeof(T) - i - 1]; + } + else + { + *(N*)&data[offset] = (N)str.Size(); + + offset += sizeof(N); + + for (N i = 0; i < str.Size(); ++i) + *(T*)&data[offset + i * sizeof(T)] = str[i]; + } + } + + offset += str.Size() * sizeof(T); + } + + void WriteVersion(const Version& value) + { + if (sizeof(unsigned int) * 3 > size - offset) + { + N remainder = sizeof(unsigned int) * 3 - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + for (N i = 0; i < 3; ++i) + *(unsigned int*)&data[offset + i * sizeof(unsigned int)] = value[i]; + else + for (N i = 0; i < 3; ++i) + for (N b = 0; b < sizeof(unsigned int); ++b) + data[offset + i * sizeof(unsigned int) + b] = value[sizeof(unsigned int) - i - 1]; + } + else + { + if (endianness == Endianness::LE) + for (N i = 0; i < 3; ++i) + for (N b = 0; b < sizeof(unsigned int); ++b) + data[offset + i * sizeof(unsigned int) + b] = value[sizeof(unsigned int) - i - 1]; + else + for (N i = 0; i < 3; ++i) + *(unsigned int*)&data[offset + i * sizeof(unsigned int)] = value[i]; + } + + offset += sizeof(unsigned int) * 3; + } + + template + void WriteVec2(const Vec2& value) + { + if (sizeof(T) * 2 > size - offset) + { + N remainder = sizeof(T) * 2 - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + for (N i = 0; i < 2; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + else + for (N i = 0; i < 2; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = value[sizeof(T) - i - 1]; + } + else + { + if (endianness == Endianness::LE) + for (N i = 0; i < 2; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = value[sizeof(T) - i - 1]; + else + for (N i = 0; i < 2; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + } + + offset += sizeof(T) * 2; + } + + template + void WriteVec3(const Vec3& value) + { + if (sizeof(T) * 3 > size - offset) + { + N remainder = sizeof(T) * 3 - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + for (N i = 0; i < 3; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + else + for (N i = 0; i < 3; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = value[sizeof(T) - i - 1]; + } + else + { + if (endianness == Endianness::LE) + for (N i = 0; i < 3; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = value[sizeof(T) - i - 1]; + else + for (N i = 0; i < 3; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + } + + offset += sizeof(T) * 3; + } + + void WriteColor3(const Color3& value) + { + if (sizeof(float) * 3 > size - offset) + { + N remainder = sizeof(float) * 3 - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + for (N i = 0; i < 3; ++i) + *(float*)&data[offset + i * sizeof(float)] = value[i]; + else + for (N i = 0; i < 3; ++i) + for (N b = 0; b < sizeof(float); ++b) + data[offset + i * sizeof(float) + b] = value[sizeof(float) - i - 1]; + } + else + { + if (endianness == Endianness::LE) + for (N i = 0; i < 3; ++i) + for (N b = 0; b < sizeof(float); ++b) + data[offset + i * sizeof(float) + b] = value[sizeof(float) - i - 1]; + else + for (N i = 0; i < 3; ++i) + *(float*)&data[offset + i * sizeof(float)] = value[i]; + } + + offset += sizeof(float) * 3; + } + + template + void WriteVec4(const Vec4& value) + { + if (sizeof(T) * 4 > size - offset) + { + N remainder = sizeof(T) * 4 - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + for (N i = 0; i < 4; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + else + for (N i = 0; i < 4; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = value[sizeof(T) - i - 1]; + } + else + { + if (endianness == Endianness::LE) + for (N i = 0; i < 4; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = value[sizeof(T) - i - 1]; + else + for (N i = 0; i < 4; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + } + + offset += sizeof(T) * 4; + } + + template + void WriteRect(const Rect& value) + { + if (sizeof(T) * 4 > size - offset) + { + N remainder = sizeof(T) * 4 - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + for (N i = 0; i < 4; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + else + for (N i = 0; i < 4; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = value[sizeof(T) - i - 1]; + } + else + { + if (endianness == Endianness::LE) + for (N i = 0; i < 4; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = value[sizeof(T) - i - 1]; + else + for (N i = 0; i < 4; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + } + + offset += sizeof(T) * 4; + } + + void WriteColor4(const Color4& value) + { + if (sizeof(float) * 4 > size - offset) + { + N remainder = sizeof(float) * 4 - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + for (N i = 0; i < 4; ++i) + *(float*)&data[offset + i * sizeof(float)] = value[i]; + else + for (N i = 0; i < 4; ++i) + for (N b = 0; b < sizeof(float); ++b) + data[offset + i * sizeof(float) + b] = value[sizeof(float) - i - 1]; + } + else + { + if (endianness == Endianness::LE) + for (N i = 0; i < 4; ++i) + for (N b = 0; b < sizeof(float); ++b) + data[offset + i * sizeof(float) + b] = value[sizeof(float) - i - 1]; + else + for (N i = 0; i < 4; ++i) + *(float*)&data[offset + i * sizeof(float)] = value[i]; + } + + offset += sizeof(float) * 4; + } + + template + void WriteQuat(const Quat& value) + { + if (sizeof(T) * 4 > size - offset) + { + N remainder = sizeof(T) * 4 - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + for (N i = 0; i < 4; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + else + for (N i = 0; i < 4; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = value[sizeof(T) - i - 1]; + } + else + { + if (endianness == Endianness::LE) + for (N i = 0; i < 4; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = value[sizeof(T) - i - 1]; + else + for (N i = 0; i < 4; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + } + + offset += sizeof(T) * 4; + } + + template + void WriteMat2(const Mat2& value) + { + if (sizeof(T) * 4 > size - offset) + { + N remainder = sizeof(T) * 4 - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + for (N i = 0; i < 4; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + else + for (N i = 0; i < 4; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = ((Byte*)&value[i])[sizeof(T) - b - 1]; + } + else + { + if (endianness == Endianness::LE) + for (N i = 0; i < 4; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = ((Byte*)&value[i])[sizeof(T) - b - 1]; + else + for (N i = 0; i < 4; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + } + + offset += sizeof(T) * 4; + } + + template + void WriteMat3(const Mat3& value) + { + if (sizeof(T) * 9 > size - offset) + { + N remainder = sizeof(T) * 9 - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + for (N i = 0; i < 9; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + else + for (N i = 0; i < 9; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = ((Byte*)&value[i])[sizeof(T) - b - 1]; + } + else + { + if (endianness == Endianness::LE) + for (N i = 0; i < 9; ++i) + for (N b = 0; b < sizeof(T); ++b) + data[offset + i * sizeof(T) + b] = ((Byte*)&value[i])[sizeof(T) - b - 1]; + else + for (N i = 0; i < 9; ++i) + *(T*)&data[offset + i * sizeof(T)] = value[i]; + } + + offset += sizeof(T) * 9; + } + + template + void WriteMat4(const Mat4& value) + { + if (sizeof(T) * 16 > size - offset) + { + N remainder = sizeof(T) * 16 - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + for (N y = 0; y < 4; ++y) + for (N x = 0; x < 4; ++x) + *(T*)&data[offset + y * sizeof(T) * 4 + x * sizeof(T)] = value[y][x]; + else + for (N y = 0; y < 4; ++y) + for (N x = 0; x < 4; ++x) + for (N i = 0; i < sizeof(T); ++i) + data[offset + y * sizeof(T) * 4 + x * sizeof(T) + i] = ((Byte*)&value[y][x])[sizeof(T) - i - 1]; + } + else + { + if (endianness == Endianness::LE) + for (N y = 0; y < 4; ++y) + for (N x = 0; x < 4; ++x) + for (N i = 0; i < sizeof(T); ++i) + data[offset + y * sizeof(T) * 4 + x * sizeof(T) + i] = ((Byte*)&value[y][x])[sizeof(T) - i - 1]; + else + for (N y = 0; y < 4; ++y) + for (N x = 0; x < 4; ++x) + *(T*)&data[offset + y * sizeof(T) * 4 + x * sizeof(T)] = value[y][x]; + } + + offset += sizeof(T) * 16; + } + + void WriteSer(const Serializer& ser) + { + if (ser.endianness != endianness) + return; + + if (ser.Size() > size - offset) + { + N remainder = ser.Size() - (size - offset); + + Byte* result = new Byte[size + remainder]; + + Util::Copy(result, data, size); + + delete[] data; + data = result; + size += remainder; + } + + Util::Copy(&data[offset], &ser[0], ser.Size()); + + offset += ser.Size(); + } + + template + void Write(const T value) + { + if (sizeof(T) > size - offset) + { + N remainder = sizeof(T) - (size - offset); + + Byte* r = new Byte[size + remainder]; + + for (N i = 0; i < size; ++i) + r[i] = data[i]; + + delete[] data; + data = r; + size += remainder; + } + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + *(T*)&data[offset] = value; + else + for (N i = 0; i < sizeof(T); ++i) + data[offset + i] = ((Byte*)&value)[sizeof(T) - i - 1]; + } + else + { + if (endianness == Endianness::LE) + for (N i = 0; i < sizeof(T); ++i) + data[offset + i] = ((Byte*)&value)[sizeof(T) - i - 1]; + else + *(T*)&data[offset] = value; + } + + offset += sizeof(T); + } + + template + void ReadArray(T* const value, O* const size) + { + if (!*size) + *size = (O)Read(); + + for (N i = 0; i < *size; ++i) + value[i] = Read(); + } + + template + Array ReadArray(const O size = 0) + { + Array result(size ? size : (O)Read()); + + for (O i = 0; i < result.Size(); ++i) + result[i] = Read(); + + return result; + } + + template + Vector ReadVector(const O size = 0) + { + Vector result(size ? size : (O)Read()); + + for (O i = 0; i < result.Size(); ++i) + result[i] = Read(); + + return result; + } + + template + Str ReadStr(const O size = 0) + { + Str result(size ? size : (O)Read()); + + for (O i = 0; i < result.Size(); ++i) + result[i] = Read(); + + return result; + } + + Version ReadVersion() + { + return {Read(), Read(), Read()}; + } + + template + Vec2 ReadVec2() + { + return {Read(), Read()}; + } + + template + Vec3 ReadVec3() + { + return {Read(), Read(), Read()}; + } + + Color3 ReadColor3() + { + return {Read(), Read(), Read()}; + } + + template + Vec4 ReadVec4() + { + return {Read(), Read(), Read(), Read()}; + } + + template + Rect ReadRect() + { + return {Read(), Read(), Read(), Read()}; + } + + Color4 ReadColor4() + { + return {Read(), Read(), Read(), Read()}; + } + + template + Quat ReadQuat() + { + return {Read(), Read(), Read(), Read()}; + } + + template + Mat2 ReadMat2() + { + Mat2 result; + for (N i = 0; i < 4; ++i) + result[i] = Read(); + + return result; + } + + template + Mat3 ReadMat3() + { + Mat3 result; + for (N i = 0; i < 9; ++i) + result[i] = Read(); + + return result; + } + + template + Mat4 ReadMat4() + { + Mat4 result; + for (N i = 0; i < 16; ++i) + result[i] = Read(); + + return result; + } + + template + T Read() + { + T value = (T)0; + + if (CPU::GetEndianness() == Endianness::LE) + { + if (endianness == Endianness::LE) + value = *(T*)&data[offset]; + else + for (N i = 0; i < sizeof(T); ++i) + ((Byte*)&value)[sizeof(T) - i - 1] = data[offset + i]; + } + else + { + if (endianness == Endianness::LE) + for (N i = 0; i < sizeof(T); ++i) + ((Byte*)&value)[sizeof(T) - i - 1] = data[offset + i]; + else + value = *(T*)&data[offset]; + } + + offset += sizeof(T); + + return value; + } + + void SetOffset(const N offset) + { + this->offset = offset; + } + + N GetOffset() const + { + return offset; + } + + void Resize(const N newSize) + { + Byte* result = new Byte[newSize]; + Util::Copy(result, data, size); + delete[] data; + data = result; + size = newSize; + } + + N Size() const + { + return size; + } +}; \ No newline at end of file diff --git a/src/Str.h b/src/Str.h new file mode 100644 index 0000000..6139149 --- /dev/null +++ b/src/Str.h @@ -0,0 +1,1765 @@ +#pragma once + +#include "EHS.h" +#include "Util.h" +#include "Vector.h" + +#include + +enum class SearchPattern +{ + LEFT_RIGHT, + RIGHT_LEFT +}; + +enum class IndexResult +{ + BEGINNING, + ENDING +}; + +/// A helper class for C-style strings. +/// @tparam T The character's data type to use. +/// @tparam N The number data type to use. +template +class Str +{ +private: + N size; + T* data; + +public: + /// Frees any data created on the heap. + ~Str() + { + delete[] data; + } + + /// Default members initialization. + Str() + : size(0), data(nullptr) + { + } + + /// Initializes members with given C-style string. + /// @param [in] str The C-style string. + /// @param [in] size The size of the given C-style string. + Str(const T* const str, const N size) + : size((size) ? size : Len(str)), data(nullptr) + { + data = new T[this->size + 1]; + + Util::Copy(data, str, Size(true)); + + data[this->size] = 0; + } + + /// Initializes members with given C-style string. + /// @param [in] str The C-style string. + Str(const T* const str) + : size(Len(str)), data(nullptr) + { + data = new T[size + 1]; + + Util::Copy(data, str, Size(true)); + + data[size] = 0; + } + + /// Initializes string with the given size. + /// @param [in] size The size. + Str(const N size) + : size(size), data(new T[size + 1]) + { + data[size] = 0; + } + + /// Copies all members from the given string object. + /// @param [in] str The string object to copy from. + Str(const Str& str) + : size(str.size), data(new T[size + 1]) + { + Util::Copy(data, str.data, Size(true)); + + data[size] = 0; + } + + Str(Str&& str) noexcept + : size(str.size), data(str.data) + { + str.size = 0; + str.data = nullptr; + } + + /// Copies all members from the given string object. + /// @param [in] str The string object to copy from. + /// @returns The string that has been assigned to. + Str& operator=(const Str& str) + { + if (&str == this) + return *this; + + size = str.size; + + delete[] data; + data = new T[size + 1]; + Util::Copy(data, str.data, Size(true)); + data[size] = 0; + + return *this; + } + + Str& operator=(Str&& str) noexcept + { + if (this == &str) + return *this; + + size = str.size; + delete[] data; + data = str.data; + + str.size = 0; + str.data = nullptr; + + return *this; + } + + /// Copies the given C-style string and retrieves the size. + /// @param [in] str The C-style string to copy from. + /// @returns The string object that has been assigned to. + Str& operator=(const T* const str) + { + size = Len(str); + + delete[] data; + + data = new T[size + 1]; + + Util::Copy(data, str, Size(true)); + + data[size] = 0; + + return *this; + } + + /// Concatenates with the given C-style string. + /// @param [in] str The given C-style string. + /// @returns The result. + Str& operator+=(const T* const str) + { + N inputSize = Len(str); + + T* result = new T[size + inputSize + 1]; + + Util::Copy(result, data, Size(true)); + + delete[] data; + + Util::Copy(&result[size], str, inputSize * sizeof(T)); + + result[size + inputSize] = 0; + size += inputSize; + data = result; + + return *this; + } + + /// Concatenates with the given string object. + /// @param [in] str The given string object. + /// @returns The result. + Str& operator+=(const Str& str) + { + T* result = new T[size + str.size + 1]; + + Util::Copy(result, data, Size(true)); + + delete[] data; + + Util::Copy(&result[size], str, str.Size(true)); + + result[size + str.size] = 0; + size += str.Size(); + data = result; + + return *this; + } + + /// Concatenates with the given number. + /// @param [in] num The given number to concatenate. + /// @returns The result. + Str& operator+=(const SInt_64 num) + { + return operator+=(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] num The given number to concatenate. + /// @returns The result. + Str& operator+=(const UInt_64 num) + { + return operator+=(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] num The given number to concatenate. + /// @returns The result. + Str& operator+=(const SInt_32 num) + { + return operator+=(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] num The given number to concatenate. + /// @returns The result. + Str& operator+=(const UInt_32 num) + { + return operator+=(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] num The given number to concatenate. + /// @returns The result. + Str& operator+=(const SInt_16 num) + { + return operator+=(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] num The given number to concatenate. + /// @returns The result. + Str& operator+=(const UInt_16 num) + { + return operator+=(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] num The given number to concatenate. + /// @returns The result. + Str& operator+=(const SInt_8 num) + { + return operator+=(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] num The given number to concatenate. + /// @returns The result. + Str& operator+=(const UInt_8 num) + { + return operator+=(FromNum(num)); + } + + #ifdef OS_WINDOWS + /// Concatenates with the given number. + /// @param [in] num The given number to concatenate. + /// @returns The result. + Str& operator+=(const DWORD num) + { + return operator+=(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] num The given number to concatenate. + /// @returns The result. + Str& operator+=(const HRESULT num) + { + return operator+=(FromNum(num)); + } + #endif + + /// Concatenates with the given number. + /// @param [in] num The given number to concatenate. + /// @returns The result. + Str& operator+=(const float num) + { + return operator+=(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] num The given number to concatenate. + /// @returns The result. + Str& operator+=(const double num) + { + return operator+=(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] num The given number to concatenate. + /// @returns The result. + Str& operator+=(const long double num) + { + return operator+=(FromNum(num)); + } + + /// Concatenates with the given C-style string. + /// @param [in] str The given C-style string. + /// @returns The result. + Str operator+(const T* const str) const + { + N inSize = Len(str); + + Str result(size + inSize); + + Util::Copy(result.data, data, Size(true)); + + Util::Copy(&result.data[size], str, inSize * sizeof(T)); + + result.data[size + inSize] = 0; + + return result; + } + + /// Concatenates with the given string object. + /// @param [in] str The given string object. + /// @returns The result. + Str operator+(const Str& str) const + { + Str result(size + str.size); + + Util::Copy(result.data, data, Size(true)); + + Util::Copy(&result.data[size], str.data, str.Size(true)); + + result.data[size + str.size] = 0; + + return result; + } + + /// Concatenates with the given number. + /// @param [in] str The given number to Concatenate. + /// @returns The result. + Str operator+(const SInt_64 num) const + { + return operator+(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] str The given number to Concatenate. + /// @returns The result. + Str operator+(const UInt_64 num) const + { + return operator+(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] str The given number to Concatenate. + /// @returns The result. + Str operator+(const SInt_32 num) const + { + return operator+(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] str The given number to Concatenate. + /// @returns The result. + Str operator+(const UInt_32 num) const + { + return operator+(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] str The given number to Concatenate. + /// @returns The result. + Str operator+(const SInt_16 num) const + { + return operator+(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] str The given number to Concatenate. + /// @returns The result. + Str operator+(const UInt_16 num) const + { + return operator+(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] str The given number to Concatenate. + /// @returns The result. + Str operator+(const SInt_8 num) const + { + return operator+(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] str The given number to Concatenate. + /// @returns The result. + Str operator+(const UInt_8 num) const + { + return operator+(FromNum(num)); + } + + #ifdef OS_WINDOWS + /// Concatenates with the given number. + /// @param [in] str The given number to Concatenate. + /// @returns The result. + Str operator+(const DWORD num) const + { + return operator+(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] str The given number to Concatenate. + /// @returns The result. + Str operator+(const HRESULT num) const + { + return operator+(FromNum(num)); + } + #endif + + /// Concatenates with the given number. + /// @param [in] str The given number to Concatenate. + /// @returns The result. + Str operator+(const float num) const + { + return operator+(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] str The given number to Concatenate. + /// @returns The result. + Str operator+(const double num) const + { + return operator+(FromNum(num)); + } + + /// Concatenates with the given number. + /// @param [in] str The given number to Concatenate. + /// @returns The result. + Str operator+(const long double num) const + { + return operator+(FromNum(num)); + } + + bool operator==(T* str) const + { + if (size != Len(str)) + return false; + + return Util::IsEqual(data, str, Size(true)); + } + + /// Compares with a C-style string. First comparing sizes. + /// @param [in] str The C-style string to compare with. + /// @returns Whether or not they are equal. + bool operator==(const T* const str) const + { + if (size != Len(str)) + return false; + + return Util::IsEqual(data, str, Size(true)); + } + + /// Compares with a string object. First comparing sizes. + /// @param [in] str The string object to compare with. + /// @returns Whether or not they are equal. + bool operator==(const Str& str) const + { + if (size != str.size) + return false; + + return Util::IsEqual(data, str, Size(true)); + } + + /// Compares with a C-style string. First comparing sizes. + /// @param [in] str The C-style string to compare with. + /// @returns Whether or not they are equal. + bool operator!=(const T* const str) const + { + if (size != Len(str)) + return true; + + return !Util::IsEqual(data, str, Size(true)); + } + + /// Compares with a string object. First comparing sizes. + /// @param [in] str The string to compare with. + /// @returns Whether or not they are equal. + bool operator!=(const Str& str) const + { + if (size != str.size) + return true; + + return !Util::IsEqual(data, str, Size(true)); + } + + /// Retrieves the raw C-style string from casting a string object. + operator T* () const + { + return data; + } + + /// Resizes the string. + /// @param [in] newSize The size to change to. + void Resize(const N newSize) + { + if (newSize == size) + return; + + T* result = new T[newSize + 1]; + + if (newSize > size) + Util::Copy(result, data, Size(true)); + else + Util::Copy(result, data, newSize * sizeof(T)); + + size = newSize; + + delete[] data; + + data = result; + data[size] = 0; + } + + /// Retrieves the size of the string. + /// @param [in] inBytes To retrieve the size in bytes. + /// @returns The resulting size. + N Size(bool inBytes = false) const + { + if (inBytes) + return sizeof(T) * size; + else + return size; + } + + /// Finds a null terminator in the string and makes it the exact size if greater than. + void ExactSize() + { + size = Len(data); + + T* result = new T[size + 1]; + Util::Copy(result, data, Size(true)); + + delete[] data; + + result[size] = 0; + data = result; + } + + /// Copies a string object to the referenced string object. + /// @param dstOffset The offset index to copy to. + /// @param src The source string object to copy from. + void Copy(const N dstOffset, const Str& src) + { + if (dstOffset + src.size > size) + { + //Log_8 log(__FUNCSIG__, LogType::ERR, 0, "The parameters \"dstOffset\" (" + Str_8::FromNum(dstOffset) + ") + \"srcSize\" (" + Str_8::FromNum(src.Size()) + ") is greater than the referenced string object's size (" + Str_8::FromNum(size) + ")."); + return; + } + + Util::Copy(data[dstOffset], src, src.Size(true)); + } + + /// Copies a C-style string to the referenced string object. + /// @param dstOffset The offset index to copy to. + /// @param src The source C-style string to copy from. + void Copy(const N dstOffset, const T* const src) + { + N srcSize = Len(src); + + if (dstOffset + srcSize > size) + { + //Log_8 log(__FUNCSIG__, LogType::ERR, 0, "The parameters \"dstOffset\" (" + Str_8::FromNum(dstOffset) + ") + \"srcSize\" (" + Str_8::FromNum(srcSize) + ") is greater than the referenced string object's size (" + Str_8::FromNum(size) + ")."); + return; + } + + Util::Copy(data[dstOffset], src, srcSize * sizeof(T)); + } + + /// Copies a C-style string to the referenced string object. + /// @param dstOffset The offset index to copy to. + /// @param src The source C-style string to copy from. + /// @param srcSize The size of the source C-style string. + void Copy(const N dstOffset, const T* const src, const N srcSize) + { + if (dstOffset + srcSize > size) + { + //Log_8 log(__FUNCSIG__, LogType::ERR, 0, "The parameters \"dstOffset\" (" + Str_8::FromNum(dstOffset) + ") + \"srcSize\" (" + Str_8::FromNum(srcSize) + ") is greater than the referenced string object's size (" + Str_8::FromNum(size) + ")."); + return; + } + + Util::Copy(data[dstOffset], src, srcSize * sizeof(T)); + } + + /// Adds a value at the end of the string. + /// @param [in] value The character to push to the end of the string. + /// @note Automatically moves the null terminator after the value is pushed. + void Push(const Str &value) + { + T* result = new T[size + value.size + 1]; + Util::Copy(result, data, Size(true)); + Util::Copy(&result[size], value, value.Size(true)); + + result[size + value.Size()] = 0; + + delete[] data; + + data = result; + size += value.size; + } + + /// Adds a value at the end of the string. + /// @param [in] value The C-style string to push to the end of the string. + /// @param [in] size The size of the given C-style string. + /// @note Automatically moves the null terminator after the value is pushed. + void Push(const T* const value, const N size) + { + T* result = new T[this->size + size + 1]; + Util::Copy(result, data, Size(true)); + Util::Copy(&result[this->size], value, size * sizeof(T)); + + result[this->size + size] = 0; + + delete[] data; + + data = result; + this->size += size; + } + + /// Adds a value at the end of the string. + /// @param [in] value The C-style string to push to the end of the string. + /// @note Automatically moves the null terminator after the value is pushed. + void Push(const T* const value) + { + N inSize = Len(value); + + T* result = new T[size + inSize + 1]; + Util::Copy(result, data, Size(true)); + Util::Copy(result[size], value, inSize * sizeof(T)); + + result[size + inSize] = 0; + + delete[] data; + + data = result; + size += inSize; + } + + /// Adds a value at the end of the string. + /// @param [in] value The character to push to the end of the string. + /// @note Automatically moves the null terminator after the value is pushed. + void Push(const T value) + { + T* result = new T[size + 2]; + + Util::Copy(result, data, Size(true)); + + result[size] = value; + result[size + 1] = 0; + + delete[] data; + + data = result; + ++size; + } + + /// Removes a value at the end of the array. + /// @returns The value that was popped. + T Pop() + { + T* result = new T[size--]; + + T value = data[size]; + + Util::Copy(result, data, Size(true)); + + result[size] = 0; + + delete[] data; + + data = result; + + return value; + } + + /// Retrieves the string in bytes for serialization. + /// @returns The string in bytes. + const Byte* ToBytes() const + { + return (Byte*)data; + } + + /// Retrieves the string in bytes for serialization. + /// @returns The string in bytes. + Byte* ToBytes() + { + return (Byte*)data; + } + + /// Changes all upper-case ASCII characters to lower-case. + void ToLower() + { + for (N i = 0; i < size; ++i) + if (data[i] > 64 && data[i] < 91) + data[i] += 32; + } + + /// Changes all upper-case ASCII characters to lower-case. + /// @returns The result. + Str GetLower() const + { + Str result(size); + + for (N i = 0; i < size; ++i) + if (data[i] > 64 && data[i] < 91) + result[i] = data[i] + 32; + else + result[i] = data[i]; + + return result; + } + + /// Changes all lower-case ASCII characters to upper-case. + void ToUpper() + { + for (N i = 0; i < size; ++i) + if (data[i] > 96 && data[i] < 123) + data[i] -= 32; + } + + /// Changes all lower-case ASCII characters to upper-case. + /// @returns The result. + Str GetUpper() const + { + Str result(size); + + for (N i = 0; i < size; ++i) + if (data[i] > 96 && data[i] < 123) + result[i] = data[i] - 32; + else + result[i] = data[i]; + + return result; + } + + /// Reverses the entire referenced string object. + void Reverse() + { + if (size <= 1 || !data) + return; + + T* r = new T[size + 1]; + + for (N i = 0; i < size; ++i) + r[i] = data[size - 1 - i]; + + r[size] = 0; + + delete[] data; + + data = r; + } + + /// Reverses the entire string object. + /// @returns The result. + Str GetReverse() + { + if (size <= 1 || !data) + return *this; + + Str r(size); + + for (N i = 0; i < size; ++i) + r[i] = data[size - 1 - i]; + + return r; + } + + /// Clips the string at the given index and with the given size. + /// @param [in] index The index to clip at. + /// @param [in] size The size for the clip starting from the index. + /// @returns The result. + Str Sub(const N index, const N size = 0) const + { + if (index >= this->size) + { + //Log_8 log(__FUNCSIG__, LogType::ERR, 0, "The given index parameter, \"" + Str::FromNum(index) + "\" is greater than the string's size, \"" + Str::FromNum(this->size) + "\"."); + + return Str(); + } + + if (size) + { + if (size > this->size) + { + //Log_8 log(__FUNCSIG__, LogType::ERR, 1, "The given size parameter, \"" + Str::FromNum(size) + "\" is greater than the string's size, \"" + Str::FromNum(this->size) + "\", at the index, \"" + Str::FromNum(index) + "\"."); + + return Str(); + } + + Str result(size); + + Util::Copy(result, &data[index], result.Size(true)); + + return result; + } + else + { + Str result(this->size - index); + + Util::Copy(result, &data[index], result.Size(true)); + + return result; + } + } + + /// Splits a string into an array with the given separator. + /// @param [in] ide The given string as the separator. + /// @param [in] max The max amount of times to split the string. + /// @returns The result. + Vector, N> Split(const Str& ide, const N max = 0) const + { + Vector, N> result(0, 5); + + N b = 0; + + for (N i = 0, c = 0; i < size; ++i) + { + if (data[i] == ide[c]) + { + if (++c == ide.Size()) + { + N r = i - (c - 1) - b; + if (!r) + result.Push(Str()); + else + result.Push(Str(&data[b], r)); + + b = i + 1; + c = 0; + + if (max && result.Size() == max) + break; + } + } + else + { + c = 0; + } + } + + if (b < size) + result.Push(Str(&data[b], size - b)); + + return result; + } + + /// Removes all instances of the given string object. + /// @param [in] ide The string to look for. + /// @returns The result. + Str RemoveAll(const Str& ide) const + { + Str result(size); + + for (N i = 0, b = 0, c = 0; i < size; ++i) + { + if (data[i] == ide[c]) + { + if (++c == ide.Size()) + c = 0; + } + else + { + if (c) + for (N d = c; d < 0; --d) + result[b++] = data[i - d]; + else + result[b++] = data[i]; + + c = 0; + } + } + + return result; + } + + Str ReplaceAll(const Str& ide, const Str& replacer) const + { + Str result; + + for (N i = 0, b = 0; i < size; ++i) + { + if (data[i] == ide[b]) + { + if (++b == ide.Size()) + { + result.Push(replacer); + b = 0; + } + } + else + { + result.Push(data[i]); + } + } + + return result; + } + + /// Finds the first instance of the given string object. + /// @param [in] ide The string to look for. + /// @param [out] index The index of the string found. Can be a nullptr. + /// @param [in] pattern The search pattern for optimization. + /// @param [in] result What index to return where the first instance is found. + /// @returns The index where the instance was found with the result varying from the result parameter. + bool Find(const Str& ide, N* const index = nullptr, const SearchPattern pattern = SearchPattern::LEFT_RIGHT, const IndexResult result = IndexResult::BEGINNING) const + { + if (pattern == SearchPattern::LEFT_RIGHT) + { + for (N i = 0, c = 0; i < size; ++i) + { + if (data[i] == ide[c]) + { + if (++c == ide.Size()) + { + if (result == IndexResult::BEGINNING) + { + if (index) + *index = i - (c - 1); + + return true; + } + else + { + if (index) + *index = i; + + return true; + } + } + } + } + } + else if (pattern == SearchPattern::RIGHT_LEFT) + { + for (N i = size, c = ide.Size(); i > 0; --i) + { + if (data[i - 1] == ide[c - 1]) + { + if (--c == 0) + { + if (result == IndexResult::BEGINNING) + { + if (index) + *index = i - (ide.Size() - 1); + + return true; + } + else + { + if (index) + *index = i; + + return true; + } + } + } + } + } + + return false; + } + + bool Contains(const Str& ide, const SearchPattern pattern = SearchPattern::LEFT_RIGHT) const + { + if (pattern == SearchPattern::LEFT_RIGHT) + { + for (N i = 0, c = 0; i < size; ++i) + { + if (data[i] == ide[c]) + { + if (++c == ide.Size()) + { + return true; + } + } + } + } + else if (pattern == SearchPattern::RIGHT_LEFT) + { + for (N i = size, c = ide.Size(); i > 0; --i) + { + if (data[i - 1] == ide[c - 1]) + { + if (--c == 0) + { + return true; + } + } + } + } + + return false; + } + + /// Checks if the string represents a number. Must not have any alphabetical characters. + /// @returns The result. + bool IsNum() const + { + if (!size) + return false; + + if ((data[0] < '0' || data[0] > '9') && data[0] != '-' && data[0] != '.') + return false; + + for (N i = 1; i < size; ++i) + if ((data[i] < '0' || data[i] > '9') && data[i] != '.') + return false; + + return true; + } + + template + static Str NumToHex(const I num) + { + static const T hex[] = "0123456789ABCDEF"; + + Str result(sizeof(I) * 2); + + for (UInt_8 i = 0; i < sizeof(I); ++i) + { + result[i * 2] = hex[((Byte*)&num)[i] / 16]; + result[i * 2 + 1] = hex[((Byte*)&num)[i] % 16]; + } + + return result; + } + + template + static I HexToNum(const Str& in) + { + N offset = 0; + bool neg = false; + + if (in[offset] == 45) + { + neg = true; + ++offset; + } + else if (in[offset] == 43) + ++offset; + + if (in[offset] == 48 && (in[offset + 1] == 88 || in[offset + 1] == 120)) + offset += 2; + + N acc = 0; + + for (N i = offset; i < in.Size(); ++i) + { + I value = 0; + + if (in[i] > 47 && in[i] < 58) + value = in[i] - 48; + else if (in[i] > 64 && in[i] < 71) + value = in[i] - 55; + else if (in[i] > 96 && in[i] < 103) + value = in[i] - 87; + + if (value >= 16) + return 0; + + acc *= 16; + acc += value; + } + + return neg ? -acc : acc; + } + + template + I HexToNum() const + { + N offset = 0; + bool neg = false; + + if (data[offset] == 45) + { + neg = true; + ++offset; + } + else if (data[offset] == 43) + ++offset; + + if (data[offset] == 48 && (data[offset + 1] == 88 || data[offset + 1] == 120)) + offset += 2; + + N acc = 0; + + for (N i = offset; i < size; ++i) + { + I value = 0; + + if (data[i] > 47 && data[i] < 58) + value = data[i] - 48; + else if (data[i] > 64 && data[i] < 71) + value = data[i] - 55; + else if (data[i] > 96 && data[i] < 103) + value = data[i] - 87; + + if (value >= 16) + return 0; + + acc *= 16; + acc += value; + } + + return neg ? -acc : acc; + } + + /// Converts the string into a number. + /// @tparam I The resulting number's data type. + /// @returns The result. + /// @note Use "IsNum" before this if the referenced string object will not always be a number. + template + I ToDecimal() const + { + I r = 0; + + if (!size) + return r; + + for (N i = data[0] == '-' ? 1 : 0; i < size; ++i) + r = r * 10 + data[i] - '0'; + + if (data[0] == '-') + r *= -1; + + return r; + } + + float ToFloat() const + { + N decPoint = size; + Find(".", &decPoint); + + float result = 0.0f; + float fraction = 0.0f; + float scale = 1.0f; + + for (N i = 0; i < decPoint; ++i) + result = result * 10.0f + data[i] - '0'; + + for (N i = decPoint + 1; i < size; ++i) + { + fraction = fraction * 10.0f + data[i] - '0'; + scale *= 10.0f; + } + + result += fraction / scale; + + return result; + } + + double ToDouble() const + { + N decPoint = size; + Find(".", &decPoint); + + double result = 0.0f; + double fraction = 0.0f; + double scale = 1.0f; + + for (N i = 0; i < decPoint; ++i) + result = result * 10.0f + data[i] - '0'; + + for (N i = decPoint + 1; i < size; ++i) + { + fraction = fraction * 10.0f + data[i] - '0'; + scale *= 10.0f; + } + + result += fraction / scale; + + return result; + } + + long double ToLDouble() const + { + N decPoint = size; + Find(".", &decPoint); + + long double result = 0.0f; + long double fraction = 0.0f; + long double scale = 1.0f; + + for (N i = 0; i < decPoint; ++i) + result = result * 10.0f + data[i] - '0'; + + for (N i = decPoint + 1; i < size; ++i) + { + fraction = fraction * 10.0f + data[i] - '0'; + scale *= 10.0f; + } + + result += fraction / scale; + + return result; + } + + /// Converts the given number into a string. + /// @returns The result. + static Str FromNum(const SInt_64 num) + { + if (num == 0) + { + Str z(1); + z[0] = 48; + return z; + } + + Str r(21); + + SInt_64 nonNeg; + if (num < 0) + nonNeg = -num; + else + nonNeg = num; + + N i = 0; + + while (nonNeg != 0) + { + r[i++] = 48 + nonNeg % 10; + nonNeg /= 10; + } + + if (num < 0) + r[i++] = 45; + + r.Resize(i); + + return r.GetReverse(); + } + + /// Converts the given number into a string. + /// @returns The result. + static Str FromNum(const UInt_64 num) + { + if (num == 0) + { + Str z(1); + z[0] = 48; + return z; + } + + Str r(21); + + UInt_64 nonNeg = num; + + N i = 0; + + while (nonNeg != 0) + { + r[i++] = 48 + nonNeg % 10; + nonNeg /= 10; + } + + r.Resize(i); + + return r.GetReverse(); + } + + /// Converts the given number into a string. + /// @returns The result. + static Str FromNum(const SInt_32 num) + { + if (num == 0) + { + Str z(1); + z[0] = 48; + return z; + } + + Str r(11); + + SInt_32 nonNeg; + if (num < 0) + nonNeg = -num; + else + nonNeg = num; + + N i = 0; + + while (nonNeg != 0) + { + r[i++] = 48 + nonNeg % 10; + nonNeg /= 10; + } + + if (num < 0) + r[i++] = 45; + + r.Resize(i); + + return r.GetReverse(); + } + + /// Converts the given number into a string. + /// @returns The result. + static Str FromNum(const UInt_32 num) + { + if (num == 0) + { + Str z(1); + z[0] = 48; + return z; + } + + Str r(11); + + UInt_32 nonNeg = num; + + N i = 0; + + while (nonNeg != 0) + { + r[i++] = 48 + nonNeg % 10; + nonNeg /= 10; + } + + r.Resize(i); + + return r.GetReverse(); + } + + /// Converts the given number into a string. + /// @returns The result. + static Str FromNum(const SInt_16 num) + { + if (num == 0) + { + Str z(1); + z[0] = 48; + return z; + } + + Str r(6); + + SInt_16 nonNeg; + if (num < 0) + nonNeg = -num; + else + nonNeg = num; + + N i = 0; + + while (nonNeg != 0) + { + r[i++] = 48 + nonNeg % 10; + nonNeg /= 10; + } + + if (num < 0) + r[i++] = 45; + + r.Resize(i); + + return r.GetReverse(); + } + + /// Converts the given number into a string. + /// @returns The result. + static Str FromNum(const UInt_16 num) + { + if (num == 0) + { + Str z(1); + z[0] = 48; + return z; + } + + Str r(6); + + UInt_16 nonNeg = num; + + N i = 0; + + while (nonNeg != 0) + { + r[i++] = 48 + nonNeg % 10; + nonNeg /= 10; + } + + r.Resize(i); + + return r.GetReverse(); + } + + /// Converts the given number into a string. + /// @returns The result. + static Str FromNum(const SInt_8 num) + { + if (num == 0) + { + Str z(1); + z[0] = 48; + return z; + } + + Str r(4); + + SInt_8 nonNeg; + if (num < 0) + nonNeg = -num; + else + nonNeg = num; + + N i = 0; + + while (nonNeg != 0) + { + r[i++] = 48 + nonNeg % 10; + nonNeg /= 10; + } + + if (num < 0) + r[i++] = 45; + + r.Resize(i); + + return r.GetReverse(); + } + + /// Converts the given number into a string. + /// @returns The result. + static Str FromNum(const UInt_8 num) + { + if (num == 0) + { + Str z(1); + z[0] = 48; + return z; + } + + Str r(4); + + UInt_8 nonNeg = num; + + N i = 0; + + while (nonNeg != 0) + { + r[i++] = 48 + nonNeg % 10; + nonNeg /= 10; + } + + r.Resize(i); + + return r.GetReverse(); + } + + #ifdef OS_WINDOWS + /// Converts the given number into a string. + /// @returns The result. + static Str FromNum(const DWORD num) + { + if (num == 0) + { + Str z(1); + z[0] = 48; + return z; + } + + Str r(11); + + DWORD nonNeg = num; + + N i = 0; + + while (nonNeg != 0) + { + r[i++] = 48 + nonNeg % 10; + nonNeg /= 10; + } + + r.Resize(i); + + return r.GetReverse(); + } + + /// Converts the given number into a string. + /// @returns The result. + static Str FromNum(const HRESULT num) + { + if (num == 0) + { + Str z(1); + z[0] = 48; + return z; + } + + Str r(11); + + HRESULT nonNeg; + if (num < 0) + nonNeg = -num; + else + nonNeg = num; + + N i = 0; + + while (nonNeg != 0) + { + r[i++] = 48 + nonNeg % 10; + nonNeg /= 10; + } + + if (num < 0) + r[i++] = 45; + + r.Resize(i); + + return r.GetReverse(); + } + #endif + + /// Converts the given float into a string. + /// @returns The result. + static Str FromNum(const float num, const UInt_8 maxDecimals = 5) + { + SInt_64 whole = (SInt_64)num; + + Str result; + if (whole < 0) + result += "-"; + + result += Str::FromNum(whole); + + UInt_64 power = 10; + for (UInt_64 i = 0; i < (UInt_64)maxDecimals - 1; ++i) + power *= 10; + + SInt_64 fraction = (SInt_64)((num - (float)whole) * (float)power); + if (!fraction) + return result; + + result += "."; + + Str fResult(maxDecimals); + N i = 0; + + while (fraction) + { + fResult[i++] = 48 + fraction % 10; + fraction /= 10; + } + + while (i < maxDecimals) + fResult[i++] = 48; + + fResult.Reverse(); + result += fResult; + + return result; + } + + /// Converts the given double into a string. + /// @returns The result. + static Str FromNum(const double num, const UInt_8 maxDecimals = 5) + { + SInt_64 whole = (SInt_64)num; + + Str result; + if (whole < 0) + result += "-"; + + result += Str::FromNum(whole); + + UInt_64 power = 10; + for (UInt_64 i = 0; i < (UInt_64)maxDecimals - 1; ++i) + power *= 10; + + SInt_64 fraction = (SInt_64)((num - (double)whole) * (double)power); + if (!fraction) + return result; + + result += "."; + + Str fResult(maxDecimals); + N i = 0; + + while (fraction) + { + fResult[i++] = 48 + fraction % 10; + fraction /= 10; + } + + while (i < maxDecimals) + fResult[i++] = 48; + + fResult.Reverse(); + result += fResult; + + return result; + } + + /// Converts the given long double into a string. + /// @returns The result. + static Str FromNum(const long double num, const UInt_8 maxDecimals = 5) + { + SInt_64 whole = (SInt_64)num; + + Str result; + if (whole < 0) + result += "-"; + + result += Str::FromNum(whole); + + UInt_64 power = 10; + for (UInt_64 i = 0; i < (UInt_64)maxDecimals - 1; ++i) + power *= 10; + + SInt_64 fraction = (SInt_64)((num - (long double)whole) * (long double)power); + if (!fraction) + return result; + + result += "."; + + Str fResult(maxDecimals); + N i = 0; + + while (fraction) + { + fResult[i++] = 48 + fraction % 10; + fraction /= 10; + } + + while (i < maxDecimals) + fResult[i++] = 48; + + fResult.Reverse(); + result += fResult; + + return result; + } + + /// A 32-bit FNV-1a hash algorithm. + /// @param [in] str The string to hash. + /// @returns The resulting hash. + static UInt_32 Hash_32(const Str& str) + { + if (!str.Size()) + return 0; + + const Byte* const bytes = str.ToBytes(); + + UInt_32 hash = 2166136261ul; + + for (N i = 0; i < str.Size(true); ++i) + hash = (hash ^ bytes[i]) * 16777619; + + return hash; + } + + UInt_32 Hash_32() const + { + if (!size) + return 0; + + const Byte* const bytes = ToBytes(); + + UInt_32 hash = 2166136261ul; + + for (N i = 0; i < Size(true); ++i) + hash = (hash ^ bytes[i]) * 16777619; + + return hash; + } + + /// A 64-bit FNV-1a hash algorithm. + /// @param [in] str The string to hash. + /// @returns The resulting hash. + static UInt_64 Hash_64(const Str& str) + { + if (!str.Size()) + return 0; + + const Byte* const bytes = str.ToBytes(); + + UInt_64 hash = 14695981039346656037ull; + + for (N i = 0; i < str.Size(true); ++i) + hash = (hash ^ bytes[i]) * 1099511628211; + + return hash; + } + + UInt_64 Hash_64() const + { + if (!size) + return 0; + + const Byte* const bytes = ToBytes(); + + UInt_64 hash = 14695981039346656037ull; + + for (N i = 0; i < Size(true); ++i) + hash = (hash ^ bytes[i]) * 1099511628211; + + return hash; + } + + static N Len(const T* const str) + { + N count = 0; + while (str[count]) + ++count; + return count; + } + + static bool Cmp(const T* const a, const T* const b) + { + N aSize = Len(a); + N bSize = Len(b); + + if (aSize != bSize) + return false; + + for (UInt_64 i = 0; i < aSize; ++i) + if (a[i] != b[i]) + return false; + + return true; + } +}; + +typedef Str Str_32; +typedef Str Str_16; +typedef Str Str_8; + +template +bool operator==(const T* const first, const Str& second) +{ + N inSize = Str::Len(first); + if (second.Size() != inSize) + return false; + + return Util::IsEqual(first, second, second.Size(true)); +} + +template +bool operator!=(const T* const first, const Str& second) +{ + N inSize = Str::Len(first); + if (second.Size() != inSize) + return true; + + return !Util::IsEqual(first, second, second.Size(true)); +} + +/// Concatenates a C-style string with a string. +/// @param [in] first The given C-style string. +/// @param [in] second The given string. +/// @returns The result. +template +Str operator+(const T* const first, const Str& second) +{ + N inSize = Str::Len(first); + + Str result(inSize + second.Size()); + + Util::Copy(result, first, inSize * sizeof(T)); + Util::Copy(&result[inSize], &second[0], second.Size(true)); + + result[inSize + second.Size()] = 0; + + return result; +} \ No newline at end of file diff --git a/src/Util.cpp b/src/Util.cpp new file mode 100644 index 0000000..dea96c9 --- /dev/null +++ b/src/Util.cpp @@ -0,0 +1,109 @@ +#include "Util.h" + +bool Util::IsEqual(const void* const a, const void* const b, const UInt_64 size) +{ + Byte* aBytes = (Byte*)a; + Byte* bBytes = (Byte*)b; + UInt_64 remainder = size; + UInt_64 i = 0; + + while (i < size) + { + if (remainder >= sizeof(UInt_64)) + { + if (*(UInt_64*)&aBytes[i] != *(UInt_64*)&bBytes[i]) + return false; + + i += sizeof(UInt_64); + } + else if (remainder >= sizeof(UInt_32)) + { + if (*(UInt_32*)&aBytes[i] != *(UInt_32*)&bBytes[i]) + return false; + + i += sizeof(UInt_32); + } + else if (remainder >= sizeof(UInt_16)) + { + if (*(UInt_16*)&aBytes[i] != *(UInt_16*)&bBytes[i]) + return false; + + i += sizeof(UInt_16); + } + else + { + if (aBytes[i] != bBytes[i]) + return false; + + i += sizeof(Byte); + } + + remainder = size - i; + } + + return true; +} + +void Util::Copy(void* const out, const void* const in, const UInt_64 size) +{ + Byte* outB = (Byte*)out; + Byte* inB = (Byte*)in; + UInt_64 remainder = size; + + UInt_64 i = 0; + while (i < size) + { + if (remainder >= sizeof(UInt_64)) + { + *(UInt_64*)&outB[i] = *(UInt_64*)&inB[i]; + i += sizeof(UInt_64); + } + else if (remainder >= sizeof(UInt_32)) + { + *(UInt_32*)&outB[i] = *(UInt_32*)&inB[i]; + i += sizeof(UInt_32); + } + else if (remainder >= sizeof(UInt_16)) + { + *(UInt_16*)&outB[i] = *(UInt_16*)&inB[i]; + i += sizeof(UInt_16); + } + else + { + outB[i++] = inB[i]; + } + + remainder = size - i; + } +} + +void Util::Zero(void* const in, const UInt_64 size) +{ + Byte* inB = (Byte*)in; + UInt_64 remainder = size; + UInt_64 i = 0; + while (i < size) + { + if (remainder >= sizeof(UInt_64)) + { + *(UInt_64*)&inB[i] = 0; + i += sizeof(UInt_64); + } + else if (remainder >= sizeof(UInt_32)) + { + *(UInt_32*)&inB[i] = 0; + i += sizeof(UInt_32); + } + else if (remainder >= sizeof(UInt_16)) + { + *(UInt_16*)&inB[i] = 0; + i += sizeof(UInt_16); + } + else + { + inB[i++] = 0; + } + + remainder = size - i; + } +} \ No newline at end of file diff --git a/src/Util.h b/src/Util.h new file mode 100644 index 0000000..6c256e3 --- /dev/null +++ b/src/Util.h @@ -0,0 +1,13 @@ +#pragma once + +#include "EHS.h" + +class Util +{ +public: + static bool IsEqual(const void* const a, const void* const b, const UInt_64 size); + + static void Copy(void* const out, const void* const in, const UInt_64 size); + + static void Zero(void* const in, const UInt_64 size); +}; \ No newline at end of file diff --git a/src/Vec2.h b/src/Vec2.h new file mode 100644 index 0000000..b8287e0 --- /dev/null +++ b/src/Vec2.h @@ -0,0 +1,375 @@ +#pragma once + +#include "EHS.h" +#include "UTF.h" +#include "Str.h" +#include "Math.h" + +template +class Vec2 +{ +public: + T x; + T y; + + Vec2(const T x, const T y) + : x(x), y(y) + { + } + + template + Vec2(const Vec2& vec) + : x((T)vec.x), y((T)vec.y) + { + } + + Vec2(const T scalar = 0) + : x(scalar), y(scalar) + { + } + + template + Vec2& operator=(const Vec2& vec) + { + x = (T)vec.x; + y = (T)vec.y; + + return *this; + } + + bool operator==(const Vec2& vec) const + { + return Math::ComCmp(x, vec.x) && Math::ComCmp(x, vec.y); + } + + bool operator!=(const Vec2& vec) const + { + return !Math::ComCmp(x, vec.x) || !Math::ComCmp(x, vec.y); + } + + Vec2& operator+=(const Vec2& vec) + { + x += vec.x; + y += vec.y; + + return *this; + } + + Vec2 operator+(const Vec2& vec) const + { + Vec2 tmp; + + tmp.x = x + vec.x; + tmp.y = y + vec.y; + + return tmp; + } + + Vec2& operator+=(const T scalar) + { + x += scalar; + y += scalar; + + return *this; + } + + Vec2 operator+(const T scalar) const + { + Vec2 tmp; + + tmp.x = x + scalar; + tmp.y = y + scalar; + + return tmp; + } + + Vec2& operator-=(const Vec2& vec) + { + x -= vec.x; + y -= vec.y; + + return *this; + } + + Vec2 operator-(const Vec2& vec) const + { + Vec2 tmp; + + tmp.x = x - vec.x; + tmp.y = y - vec.y; + + return tmp; + } + + Vec2& operator-=(const T scalar) + { + x -= scalar; + y -= scalar; + + return *this; + } + + Vec2 operator-(const T scalar) const + { + Vec2 tmp; + + tmp.x = x - scalar; + tmp.y = y - scalar; + + return tmp; + } + + Vec2& operator/=(const Vec2& vec) + { + x /= vec.x; + y /= vec.y; + + return *this; + } + + Vec2 operator/(const Vec2& vec) const + { + Vec2 tmp; + + tmp.x = x / vec.x; + tmp.y = y / vec.y; + + return tmp; + } + + Vec2& operator/=(const T scalar) + { + x /= scalar; + y /= scalar; + + return *this; + } + + Vec2 operator/(const T scalar) const + { + + Vec2 tmp; + + tmp.x = x / scalar; + tmp.y = y / scalar; + + return tmp; + } + + Vec2& operator*=(const Vec2& vec) + { + x *= vec.x; + y *= vec.y; + + return *this; + } + + Vec2 operator*(const Vec2& vec) const + { + Vec2 tmp; + + tmp.x = x * vec.x; + tmp.y = y * vec.y; + + return tmp; + } + + Vec2& operator*=(const T scalar) + { + x *= scalar; + y *= scalar; + + return *this; + } + + Vec2 operator*(const T scalar) const + { + Vec2 tmp; + + tmp.x = x * scalar; + tmp.y = y * scalar; + + return tmp; + } + + bool operator<=(const Vec2& other) const + { + return x <= other.x && y <= other.y; + } + + bool operator<(const Vec2& other) const + { + return x < other.x && y < other.y; + } + + bool operator>=(const Vec2& other) const + { + return x >= other.x && y >= other.y; + } + + bool operator>(const Vec2& other) const + { + return x > other.x && y > other.y; + } + + T operator[](const UInt_64 index) const + { + switch (index) + { + case 0: + return x; + case 1: + return y; + default: + return x; + } + } + + T& operator[](const UInt_64 index) + { + switch (index) + { + case 0: + return x; + case 1: + return y; + default: + return x; + } + } + + Vec2 GetAbs() const + { + Vec2 tmp; + + tmp.x = Math::Abs(x); + tmp.y = Math::Abs(y); + + return tmp; + } + + void Abs() + { + x = Math::Abs(x); + y = Math::Abs(y); + } + + /// If positive, the vectors are pointing in the same direction. If negative, the vectors are pointing in opposing directions. + /// If zero, the vectors are perpendicular. + T GetDot(const Vec2& vec) const + { + return x * vec.x + y * vec.y; + } + + T GetAngle(const Vec2& vec) const + { + return Math::ACos(GetDot(vec) / Math::Sqrt(GetMagnitude2() * vec.GetMagnitude2())); + } + + Vec2 GetProjection(const Vec2& length) const + { + return operator*(length.GetDot(*this) / GetMagnitude2()); + } + + Vec2 GetPerpendicular(const Vec2& length) const + { + return length - GetProjection(length); + } + + Vec2 GetReflection(const Vec2& normal) const + { + return operator-(normal * (GetDot(normal) * 2)); + } + + T GetMagnitude() const + { + return Math::Sqrt(x * x + y * y); + } + + T GetMagnitude2() const + { + return x * x + y * y; + } + + T GetDistance(const Vec2& vec) const + { + return Math::Sqrt(Math::Pow(vec.x - x, 2) + Math::Pow(vec.y - y, 2)); + } + + T GetDistance2(const Vec2& vec) const + { + return Math::Pow(vec.x - x, 2) + Math::Pow(vec.y - y, 2); + } + + Vec2 GetNorm() const + { + Vec2 norm; + + T dis = GetMagnitude(); + + norm.x = x / dis; + norm.y = y / dis; + + return norm; + } + + void Norm() + { + T dis = GetMagnitude(); + + x /= dis; + y /= dis; + } + + Vec2 GetRads() const + { + Vec2 tmp; + + tmp.x = Math::Rads(x); + tmp.y = Math::Rads(y); + + return tmp; + } + + void ToRads() + { + x = Math::Rads(x); + y = Math::Rads(y); + } + + Vec2 GetDegr() const + { + Vec2 tmp; + + tmp.x = Math::Degr(x); + tmp.y = Math::Degr(y); + + return tmp; + } + + void ToDegr() + { + x = Math::Degr(x); + y = Math::Degr(y); + } + + static Vec2 Lerp(const Vec2& start, const Vec2& finish, const T t) + { + return start + (finish - start) * t; + } +}; + +typedef Vec2 Vec2_u64; +typedef Vec2 Vec2_s64; +typedef Vec2 Vec2_64; +typedef Vec2 Vec2_u32; +typedef Vec2 Vec2_s32; +typedef Vec2 Vec2_32; +typedef Vec2 Vec2_u16; +typedef Vec2 Vec2_s16; +typedef Vec2 Vec2_16; +typedef Vec2 Vec2_u8; +typedef Vec2 Vec2_s8; +typedef Vec2 Vec2_8; +typedef Vec2 Vec2_f; +typedef Vec2 Vec2_d; \ No newline at end of file diff --git a/src/Vec3.h b/src/Vec3.h new file mode 100644 index 0000000..829b19b --- /dev/null +++ b/src/Vec3.h @@ -0,0 +1,434 @@ +#pragma once + +#include "EHS.h" +#include "UTF.h" +#include "Str.h" +#include "Math.h" +#include "Vec2.h" + +template +class Vec3 +{ +public: + T x; + T y; + T z; + + Vec3(const T scalar = 0) + : x(scalar), y(scalar), z(scalar) + { + } + + Vec3(const T x, const T y, const T z) + : x(x), y(y), z(z) + { + } + + template + Vec3(const Vec2& vec, const T z = 0) + : x((T)vec.x), y((T)vec.y), z(z) + { + } + + template + Vec3(const Vec3& vec) + : x((T)vec.x), y((T)vec.y), z((T)vec.z) + { + } + + template + Vec3& operator=(const Vec2& vec) + { + x = (T)vec.x; + y = (T)vec.y; + z = 0; + + return *this; + } + + template + Vec3& operator=(const Vec3& vec) + { + x = (T)vec.x; + y = (T)vec.y; + z = (T)vec.z; + + return *this; + } + + bool operator==(const Vec3& vec) const + { + return Math::ComCmp(x, vec.x) && Math::ComCmp(y, vec.y) && Math::ComCmp(z, vec.z); + } + + + bool operator!=(const Vec3& vec) const + { + return !Math::ComCmp(z, vec.z) || !Math::ComCmp(y, vec.y) || !Math::ComCmp(z, vec.z); + } + + Vec3 operator+(const Vec3& vec) const + { + Vec3 tmp; + + tmp.x = x + vec.x; + tmp.y = y + vec.y; + tmp.z = z + vec.z; + + return tmp; + } + + Vec3& operator+=(const Vec3& vec) + { + x += vec.x; + y += vec.y; + z += vec.z; + + return *this; + } + + Vec3 operator+(const T scalar) const + { + Vec3 tmp; + + tmp.x = x + scalar; + tmp.y = y + scalar; + tmp.z = z + scalar; + + return tmp; + } + + Vec3& operator+=(const T scalar) + { + x += scalar; + y += scalar; + z += scalar; + + return *this; + } + + Vec3 operator-(const Vec3& vec) const + { + Vec3 tmp; + + tmp.x = x - vec.x; + tmp.y = y - vec.y; + tmp.z = z - vec.z; + + return tmp; + } + + Vec3& operator-=(const Vec3& vec) + { + x -= vec.x; + y -= vec.y; + z -= vec.z; + + return *this; + } + + Vec3 operator-(const T scalar) const + { + Vec3 tmp; + + tmp.x = x - scalar; + tmp.y = y - scalar; + tmp.z = z - scalar; + + return tmp; + } + + Vec3& operator-=(const T scalar) + { + x -= scalar; + y -= scalar; + z -= scalar; + + return *this; + } + + Vec3 operator*(const Vec3& vec) const + { + Vec3 tmp; + + tmp.x = x * vec.x; + tmp.y = y * vec.y; + tmp.z = z * vec.z; + + return tmp; + } + + Vec3& operator*=(const Vec3& vec) + { + x *= vec.x; + y *= vec.y; + z *= vec.z; + + return *this; + } + + Vec3 operator*(const T scalar) const + { + Vec3 tmp; + + tmp.x = x * scalar; + tmp.y = y * scalar; + tmp.z = z * scalar; + + return tmp; + } + + Vec3& operator*=(const T scalar) + { + x *= scalar; + y *= scalar; + z *= scalar; + + return *this; + } + + Vec3 operator/(const Vec3& vec) const + { + Vec3 tmp; + + tmp.x = x / vec.x; + tmp.y = y / vec.y; + tmp.z = z / vec.z; + + return tmp; + } + + Vec3& operator/=(const Vec3& vec) + { + x /= vec.x; + y /= vec.y; + z /= vec.z; + + return *this; + } + + Vec3 operator/(const T scalar) const + { + Vec3 tmp; + + tmp.x = x / scalar; + tmp.y = y / scalar; + tmp.z = z / scalar; + + return tmp; + } + + Vec3& operator/=(const T scalar) + { + x /= scalar; + y /= scalar; + z /= scalar; + + return *this; + } + + bool operator<=(const Vec3& other) const + { + return x <= other.x && y <= other.y && z <= other.z; + } + + bool operator<(const Vec3& other) const + { + return x < other.x && y < other.y && z < other.z; + } + + bool operator>=(const Vec3& other) const + { + return x >= other.x && y >= other.y && z >= other.z; + } + + bool operator>(const Vec3& other) const + { + return x > other.x && y > other.y && z > other.z; + } + + T operator[](const UInt_64 index) const + { + switch (index) + { + case 0: + return x; + case 1: + return y; + case 2: + return z; + default: + return x; + } + } + + T& operator[](const UInt_64 index) + { + switch (index) + { + case 0: + return x; + case 1: + return y; + case 2: + return z; + default: + return x; + } + } + + operator Vec2() + { + return Vec2(x, y); + } + + Vec3 GetAbs() const + { + Vec3 absolute; + + absolute.x = Math::Abs(x); + absolute.y = Math::Abs(y); + absolute.z = Math::Abs(z); + + return absolute; + } + + void Abs() + { + x = Math::Abs(x); + y = Math::Abs(y); + z = Math::Abs(z); + } + + Vec3 GetNorm() const + { + Vec3 norm; + + T dis = GetMagnitude(); + + norm.x = x / dis; + norm.y = y / dis; + norm.z = z / dis; + + return norm; + } + + void Norm() + { + T dis = GetMagnitude(); + + x /= dis; + y /= dis; + z /= dis; + } + + Vec3 GetCross(const Vec3& vec) const + { + return Vec3( + y * vec.z - z * vec.y, + z * vec.x - x * vec.z, + x * vec.y - y * vec.x + ); + } + + T GetDot(const Vec3& vec) const + { + return x * vec.x + y * vec.y + z * vec.z; + } + + T GetAngle(const Vec2& vec) const + { + return Math::ACos(GetDot(vec) / Math::Sqrt(GetMagnitude2() * vec.GetMagnitude2())); + } + + Vec2 GetProjection(const Vec2& length) const + { + return operator*(length.GetDot(*this) / GetMagnitude2()); + } + + Vec2 GetPerpendicular(const Vec2& length) const + { + return length - GetProjection(length); + } + + Vec2 GetReflection(const Vec2& normal) const + { + return operator-(normal * (GetDot(normal) * 2)); + } + + T GetMagnitude() const + { + return Math::Sqrt(x * x + y * y + z * z); + } + + T GetMagnitude2() const + { + return x * x + y * y + z * z; + } + + T GetDistance(const Vec3& vec) const + { + return (T)Math::Sqrt(Math::Pow(vec.x - x, 2) + Math::Pow(vec.y - y, 2) + Math::Pow(vec.z - z, 2)); + } + + T GetDistance2(const Vec3& vec) const + { + return static_cast(Math::Pow(vec.x - x, 2) + Math::Pow(vec.y - y, 2) + Math::Pow(vec.z - z, 2)); + } + + Vec3 GetRads() const + { + Vec3 tmp; + + tmp.x = Math::Rads(x); + tmp.y = Math::Rads(y); + tmp.z = Math::Rads(z); + + return tmp; + } + + void ToRads() + { + x = Math::Rads(x); + y = Math::Rads(y); + z = Math::Rads(z); + } + + Vec3 GetDegr() const + { + Vec3 tmp; + + tmp.x = Math::Degr(x); + tmp.y = Math::Degr(y); + tmp.z = Math::Degr(z); + + return tmp; + } + + void ToDegr() + { + x = Math::Degr(x); + y = Math::Degr(y); + z = Math::Degr(z); + } + + static Vec3 Lerp(const Vec3& start, const Vec3& finish, const T t) + { + return start + (finish - start) * t; + } +}; + +typedef Vec3 Vec3_u64; +typedef Vec3 Vec3_s64; +typedef Vec3 Vec3_64; +typedef Vec3 Vec3_u32; +typedef Vec3 Vec3_s32; +typedef Vec3 Vec3_32; +typedef Vec3 Vec3_u16; +typedef Vec3 Vec3_s16; +typedef Vec3 Vec3_16; +typedef Vec3 Vec3_u8; +typedef Vec3 Vec3_s8; +typedef Vec3 Vec3_8; +typedef Vec3 Vec3_f; +typedef Vec3 Vec3_d; \ No newline at end of file diff --git a/src/Vec4.h b/src/Vec4.h new file mode 100644 index 0000000..9c37b90 --- /dev/null +++ b/src/Vec4.h @@ -0,0 +1,339 @@ +#pragma once + +#include "EHS.h" +#include "UTF.h" +#include "Str.h" +#include "Math.h" +#include "Vec2.h" +#include "Vec3.h" + +template +class Vec4 +{ +public: + T x; + T y; + T z; + T w; + + Vec4(const T scalar = 0) + : x(scalar), y(scalar), z(scalar), w(scalar) + { + } + + Vec4(const T x, const T y, const T z, const T w) + : x(x), y(y), z(z), w(w) + { + } + + template + Vec4(const Vec2& vec, const T z = 0, const T w = 0) + : x((T)vec.x), y((T)vec.y), z(z), w(w) + { + } + + template + Vec4(const Vec3& vec, const T w = 1) + : x((T)vec.x), y((T)vec.y), z((T)vec.z), w(w) + { + } + + template + Vec4(const Vec4& vec) + : x((T)vec.x), y((T)vec.y), z((T)vec.z), w((T)vec.w) + { + } + + template + Vec4& operator=(const Vec2& vec) + { + x = (T)vec.x; + y = (T)vec.y; + z = (T)0; + w = (T)0; + + return*this; + } + + template + Vec4& operator=(const Vec3& vec) + { + x = (T)vec.x; + y = (T)vec.y; + z = (T)vec.z; + w = (T)0; + + return*this; + } + + template + Vec4& operator=(const Vec4& vec) + { + x = (T)vec.x; + y = (T)vec.y; + z = (T)vec.z; + w = (T)vec.w; + + return*this; + } + + bool operator==(const Vec4& vec) + { + return Math::ComCmp(x, vec.x) && Math::ComCmp(y, vec.y) && Math::ComCmp(z, vec.z) && Math::ComCmp(w, vec.w); + } + + bool operator!=(const Vec4& vec) + { + return !Math::ComCmp(z, vec.z) || !Math::ComCmp(y, vec.y) || !Math::ComCmp(z, vec.z) || !Math::ComCmp(w, vec.w); + } + + Vec4& operator+=(const Vec4& vec) + { + x += vec.x; + y += vec.y; + z += vec.z; + w += vec.w; + + return *this; + } + + Vec4 operator+(const Vec4& vec) + { + Vec4 tmp; + + tmp.x = x + vec.x; + tmp.y = y + vec.y; + tmp.z = z + vec.z; + tmp.w = w + vec.w; + + return tmp; + } + + Vec4& operator+=(const T scalar) + { + x += scalar; + y += scalar; + z += scalar; + w += scalar; + + return *this; + } + + Vec4 operator+(const T scalar) + { + Vec4 tmp; + + tmp.x = x + scalar; + tmp.y = y + scalar; + tmp.z = z + scalar; + tmp.w = w + scalar; + + return tmp; + } + + Vec4& operator-=(const Vec4& vec) + { + x -= vec.x; + y -= vec.y; + z -= vec.z; + w -= vec.w; + + return *this; + } + + Vec4 operator-(const Vec4& vec) + { + Vec4 tmp; + + tmp.x = x - vec.x; + tmp.y = y - vec.y; + tmp.z = z - vec.z; + tmp.w = w - vec.w; + + return tmp; + } + + Vec4& operator-=(const T scalar) + { + x -= scalar; + y -= scalar; + z -= scalar; + w -= scalar; + + return *this; + } + + Vec4 operator-(const T scalar) + { + Vec4 tmp; + + tmp.x = x - scalar; + tmp.y = y - scalar; + tmp.z = z - scalar; + tmp.w = w - scalar; + + return tmp; + } + + Vec4& operator*=(const Vec4& vec) + { + x *= vec.x; + y *= vec.y; + z *= vec.z; + w *= vec.w; + + return *this; + } + + Vec4 operator*(const Vec4& vec) + { + Vec4 tmp; + + tmp.x = x * vec.x; + tmp.y = y * vec.y; + tmp.z = z * vec.z; + tmp.w = w * vec.w; + + return tmp; + } + + Vec4& operator*=(const T scalar) + { + x *= scalar; + y *= scalar; + z *= scalar; + w *= scalar; + + return *this; + } + + Vec4 operator*(const T scalar) + { + Vec4 tmp; + + tmp.x = x * scalar; + tmp.y = y * scalar; + tmp.z = z * scalar; + tmp.w = w * scalar; + + return tmp; + } + + Vec4& operator/=(const Vec4& vec) + { + x /= vec.x; + y /= vec.y; + z /= vec.z; + w /= vec.w; + + return *this; + } + + Vec4 operator/(const Vec4& vec) + { + Vec4 tmp; + + tmp.x = x / vec.x; + tmp.y = y / vec.y; + tmp.z = z / vec.z; + tmp.w = w / vec.w; + + return tmp; + } + + Vec4& operator/=(const T scalar) + { + x /= scalar; + y /= scalar; + z /= scalar; + w /= scalar; + + return *this; + } + + Vec4 operator/(const T scalar) + { + Vec4 tmp; + + tmp.x = x / scalar; + tmp.y = y / scalar; + tmp.z = z / scalar; + tmp.w = w / scalar; + + return tmp; + } + + T operator[](const UInt_64 index) const + { + switch (index) + { + case 0: + return x; + case 1: + return y; + case 2: + return z; + case 3: + return w; + default: + return x; + } + } + + T& operator[](const UInt_64 index) + { + switch (index) + { + case 0: + return x; + case 1: + return y; + case 2: + return z; + case 3: + return w; + default: + return x; + } + } + + operator Vec3() + { + return Vec3(x, y, z); + } + + operator Vec2() + { + return Vec2(x, y); + } + + T GetDotProduct(const Vec4& vec) const + { + return x * vec.x + y * vec.y + z * vec.z + w * vec.w; + } + + T GetMagnitude() const + { + return Math::Sqrt(x * x + y * y + z * z + w * w); + } + + T GetMagnitude2() const + { + return x * x + y * y + z * z + w * w; + } +}; + +typedef Vec4 Vec4_u64; +typedef Vec4 Vec4_s64; +typedef Vec4 Vec4_64; +typedef Vec4 Vec4_u32; +typedef Vec4 Vec4_s32; +typedef Vec4 Vec4_32; +typedef Vec4 Vec4_u16; +typedef Vec4 Vec4_s16; +typedef Vec4 Vec4_16; +typedef Vec4 Vec4_u8; +typedef Vec4 Vec4_s8; +typedef Vec4 Vec4_8; +typedef Vec4 Vec4_f; +typedef Vec4 Vec4_d; \ No newline at end of file diff --git a/src/Vector.h b/src/Vector.h new file mode 100644 index 0000000..1c58f01 --- /dev/null +++ b/src/Vector.h @@ -0,0 +1,587 @@ +#pragma once + +#include "EHS.h" + +#include +#include + +/// An array with extra memory pre-allocated for fast pushes. +/// @tparam T Array data type to use. +/// @tparam N Number data type to use. +/// @note If extra memory is set to five then each time that memory is filled it will add five extra. +template +class Vector +{ +protected: + N rawSize; + N size; + N stride; + T* data; + +public: + /// Frees any data created on the heap. + ~Vector() + { + delete[] data; + } + + /// Default members initialization. + Vector() + : rawSize(0), size(0), stride(5), data(nullptr) + { + } + + /// Initializes members for pre-allocated memory to write to later. + /// @param [in] size The size of memory to pre-allocate. + /// @param [in] stride The stride size of memory to pre-allocate. + Vector(const N size, const N stride) + : rawSize(size + stride), size(size), stride(stride), data(new T[rawSize]) + { + } + + /// Initializes this vector with an initializer list object. + /// @param [in] list The given initializer list. + /// @param [in] stride The extra amount of memory to allocate. + Vector(std::initializer_list list, const N stride = 5) + : rawSize(0), size(list.size()), stride(stride), data(nullptr) + { + if (stride) + { + rawSize = list.size() / stride * stride; + if (list.size() % stride) + rawSize += stride; + } + else + { + rawSize = list.size(); + } + + data = new T[rawSize]; + + N i = 0; + for (auto v = list.begin(); v != list.end(); ++v) + data[i++] = std::move(*v); + } + + /// Initializes members with given C-style array. + /// @param [in] data The C-style array. + /// @param [in] size The size of the given C-style array. + /// @param [in] stride The size of the extra memory allocated. + Vector(const T* data, const N size, const N stride) + : rawSize(0), size(size), stride(stride), data(nullptr) + { + if (stride) + { + rawSize = size / stride * stride; + if (size % stride) + rawSize += stride; + } + else + { + rawSize = size; + } + + data = new T[rawSize]; + + for (N i = 0; i < size; ++i) + this->data[i] = data[i]; + } + + /// Copies all members from the given vector object. + /// @param [in] vec The vector object to copy from. + Vector(const Vector& vec) + : rawSize(vec.rawSize), size(vec.size), stride(vec.stride), data(new T[rawSize]) + { + for (N i = 0; i < size; ++i) + data[i] = vec.data[i]; + } + + Vector(Vector&& vec) noexcept + : rawSize(vec.rawSize), size(vec.size), stride(vec.stride), data(vec.data) + { + vec.rawSize = 0; + vec.size = 0; + vec.stride = 0; + vec.data = nullptr; + } + + /// Copies all members from the given vector object. + /// @param [in] vec The vector object to copy from. + /// @returns The vector that has been assigned to. + Vector& operator=(const Vector& vec) + { + if (this == &vec) + return *this; + + rawSize = vec.rawSize; + size = vec.size; + stride = vec.stride; + + delete[] data; + data = new T[rawSize]; + + for (N i = 0; i < size; ++i) + data[i] = vec.data[i]; + + return *this; + } + + Vector& operator=(Vector&& vec) noexcept + { + if (this == &vec) + return *this; + + rawSize = vec.rawSize; + size = vec.size; + stride = vec.stride; + delete[] data; + data = vec.data; + + vec.rawSize = 0; + vec.size = 0; + vec.stride = 0; + vec.data = nullptr; + + return *this; + } + + /// Adds a given initializer list at the end of the vector. + /// @param [in] value The given initializer list to push to the end of the vector. + Vector& operator+=(std::initializer_list value) + { + if (size + value.size() >= rawSize) + { + if (stride) + { + rawSize = (size + value.size()) / stride * stride; + if ((size + value.size()) % stride) + rawSize += stride; + } + else + { + rawSize = size + value.size(); + } + + T* result = new T[rawSize]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(std::move(data[i])); + + delete[] data; + data = result; + } + + for (auto v = value.begin(); v != value.end(); ++v) + data[size++] = std::move(*v); + + return *this; + } + + /// Adds a given value at the end of the vector. + /// @param [in] value The given value to push to the end of the vector. + Vector& operator+=(const T value) + { + if (size + 1 >= rawSize) + { + if (stride) + rawSize = size + stride; + else + rawSize = size + 1; + + T* result = new T[rawSize]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + delete[] data; + data = result; + } + + data[size++] = std::move(value); + + return *this; + } + + /// Retrieves the raw C-style array from casting an array object. + operator T* () const + { + return data; + } + + /// Retrieves the size of the vector object including the extra memory allocated. + /// @returns The raw size. + N RawSize() const + { + return rawSize; + } + + /// Retrieves the size of the array not including the extra memory allocated. + /// @returns The size. + N Size() const + { + return size; + } + + /// Retrieves the size of the extra memory allocated. + /// @returns The extra size. + N Stride() const + { + return stride; + } + + N End() const + { + return size ? size - 1 : size; + } + + /// Copies a vector object with offsets. + /// @param [in] dstOffset The offset index to copy the given vector object to. + /// @param [in] src The given vector object. + /// @param [in] srcOffset The offset index from the given vector object to copy from. + void Copy(const N dstOffset, Vector src, const N srcOffset = 0) + { + for (N i = 0; i < src.Size() - srcOffset; ++i) + data[i + dstOffset] = std::move(src[i + srcOffset]); + } + + /// Copies a C-style array with offsets. + /// @param [in] dstOffset The offset index to copy the given C-style array to. + /// @param [in] src The given C-style array. + /// @param [in] size The size from the given C-style array to copy. + void Copy(const N dstOffset, const T* src, const N size) + { + for (N i = 0; i < size; ++i) + data[i + dstOffset] = src[i]; + } + + /// Swaps two values in the vector. + /// @param [in] a The first index to swap with. + /// @param [in] b The second index to swap with. + void Swap(N a, N b) + { + T tmp = std::move(data[a]); + + data[a] = std::move(data[b]); + data[b] = std::move(tmp); + } + + /// Inserts a value at a specified index that is available. + /// @param [in] index The index to insert the value at. + /// @param [in] value The given value to insert. + void Insert(const N index, const T value) + { + N newSize = 0; + if (index > size - 1) + newSize = size + ((index + 1) - size); + else + newSize = size + 1; + + if (newSize >= rawSize) + { + if (stride) + rawSize += newSize + stride; + else + rawSize = newSize; + + T* result = new T[rawSize]; + + for (N i = 0; i < index; ++i) + result[i] = std::move(data[i]); + + result[index] = std::move(value); + + for (N i = index; i < size; ++i) + result[i + 1] = std::move(data[i]); + + delete[] data; + data = result; + } + else + { + for (N i = index; i < size; ++i) + data[i + 1] = std::move(data[i]); + + data[index] = std::move(value); + } + + size += newSize; + } + + /// Removes a value at a specified index. + /// @param [in] index The index to remove the value at. + /// @returns The removed data. + T Remove(const N index) + { + T popped = {}; + + if (!size || index >= size) + return popped; + + popped = std::move(data[index]); + + if (!stride) + { + rawSize = size - 1; + T* result = new T[rawSize]; + + for (N i = 0; i < index; ++i) + result[i] = std::move(data[i]); + + for (N i = index + 1; i < size; ++i) + result[i - 1] = std::move(data[i]); + + delete[] data; + data = result; + } + else if (rawSize - stride && size - 1 <= rawSize - stride) + { + rawSize -= stride; + T* result = new T[rawSize]; + + for (N i = 0; i < index; ++i) + result[i] = std::move(data[i]); + + for (N i = index + 1; i < size; ++i) + result[i - 1] = std::move(data[i]); + + delete[] data; + data = result; + } + else + { + for (N i = index + 1; i < size; ++i) + data[i - 1] = std::move(data[i]); + } + + --size; + + return popped; + } + + /// Adds a given C-style array at the end of the vector. + /// @param [in] value The given C-style array to push to the end of the vector. + /// @param [in] size The size of the given C-style array. + void Push(const T* const value, const N size) + { + if (this->size + size >= rawSize) + { + if (stride) + { + rawSize = (this->size + size()) / stride * stride; + if ((this->size + size) % stride) + rawSize += stride; + } + else + { + rawSize = this->size + size; + } + + T* result = new T[rawSize]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + delete[] data; + data = result; + } + + for (N i = 0; i < size; ++i) + data[this->size + i] = value[i]; + + this->size += size; + } + + /// Adds a given vector object at the end of the vector. + /// @param [in] value The given vector object to push to the end of the vector. + void Push(Vector value) + { + if (size + value.size >= rawSize) + { + if (stride) + { + rawSize = (size + value.size) / stride * stride; + if ((size + value.size) % stride) + rawSize += stride; + } + else + { + rawSize = size + value.size; + } + + T* result = new T[rawSize]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + delete[] data; + data = result; + } + + for (N i = 0; i < value.size; ++i) + data[size + i] = std::move(value.data[i]); + + size += value.size; + } + + /// Adds a given initializer at the end of the vector. + /// @param [in] value The given initializer list to push to the end of the vector. + void Push(std::initializer_list value) + { + if (size + value.size() >= rawSize) + { + if (stride) + { + rawSize = (size + value.size()) / stride * stride; + if ((size + value.size()) % stride) + rawSize += stride; + } + else + { + rawSize = size + value.size(); + } + + T* result = new T[rawSize]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + delete[] data; + data = result; + } + + for (auto v = value.begin(); v != value.end(); ++v) + data[size++] = std::move(*v); + } + + /// Adds a given value at the end of the vector. + /// @param [in] value The given value to push to the end of the vector. + void Push(T value) + { + if (size + 1 >= rawSize) + { + if (stride) + rawSize += stride; + else + rawSize = size + 1; + + T* result = new T[rawSize]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + delete[] data; + data = result; + } + + data[size++] = std::move(value); + } + + /// Much like the stack it pops a value at the end of the vector. + /// @returns The removed data. + T Pop() + { + T popped = {}; + + if (!size) + return popped; + + popped = std::move(data[--size]); + + if (!stride) + { + rawSize = size; + T* result = new T[rawSize]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + delete[] data; + data = result; + } + else if (rawSize - stride && size < rawSize - stride) + { + rawSize -= stride; + T* result = new T[rawSize]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + delete[] data; + data = result; + } + + return popped; + } + + /// Resizes the vector while keeping its alignment. + /// @param [in] newSize The size to change to. + void Resize(const N newSize) + { + if (newSize == size) + return; + + if (stride) + { + rawSize = newSize / stride * stride; + if (newSize % stride) + rawSize += stride; + } + else + { + rawSize = newSize; + } + + T* result = new T[rawSize]; + + for (N i = 0; i < size && i < newSize; ++i) + result[i] = std::move(data[i]); + + delete[] data; + data = result; + size = newSize; + } + + /// Removes any extra allocated memory. + void ExactSize() + { + if (!stride) + return; + + stride = 0; + + if (size) + { + rawSize = size; + T* result = new T[rawSize]; + + for (N i = 0; i < size; ++i) + result[i] = std::move(data[i]); + + delete[] data; + data = result; + } + else + { + rawSize = 0; + delete[] data; + data = nullptr; + } + } + + /// Clears all values in the vector object. + void Clear() + { + if (!size) + return; + + rawSize = stride; + size = 0; + + delete[] data; + + if (rawSize) + data = new T[rawSize]; + else + data = nullptr; + } +}; \ No newline at end of file diff --git a/src/Version.cpp b/src/Version.cpp new file mode 100644 index 0000000..1fd4dcf --- /dev/null +++ b/src/Version.cpp @@ -0,0 +1,68 @@ +#include "Version.h" + +Version::Version() + : major(0), minor(0), patch(0) +{ +} + +Version::Version(const unsigned int major, const unsigned int minor, const unsigned int patch) + : major(major), minor(minor), patch(patch) +{ +} + +Version::Version(const Version& version) + : major(version.major), minor(version.minor), patch(version.patch) +{ +} + +Version& Version::operator=(const Version& version) +{ + if (this == &version) + return *this; + + major = version.major; + minor = version.minor; + patch = version.patch; + + return *this; +} + +bool Version::operator==(const Version& version) const +{ + return major == version.major && minor == version.minor && patch == version.patch; +} + +bool Version::operator!=(const Version& version) const +{ + return major != version.major || minor != version.minor || patch != version.patch; +} + +unsigned int Version::operator[](const unsigned int i) const +{ + switch (i) + { + case 0: + return major; + case 1: + return minor; + case 2: + return patch; + default: + return major; + } +} + +unsigned int& Version::operator[](const unsigned int i) +{ + switch (i) + { + case 0: + return major; + case 1: + return minor; + case 2: + return patch; + default: + return major; + } +} \ No newline at end of file diff --git a/src/Version.h b/src/Version.h new file mode 100644 index 0000000..c43e021 --- /dev/null +++ b/src/Version.h @@ -0,0 +1,36 @@ +#pragma once + +/// A helper class for storing version major, minor and patch. +class Version +{ +public: + unsigned int major; + unsigned int minor; + unsigned int patch; + + /// Default members initialization. + Version(); + + /// Initializes members with given major, minor and patch. + /// @param [in] major The major version. + /// @param [in] minor The minor version. + /// @param [in] patch The patch version. + Version(const unsigned int major, const unsigned int minor, const unsigned int patch); + + /// Copies all members from the given version object. + /// @param [in] version The version object to copy from. + Version(const Version& version); + + /// Copies all members from the given version object. + /// @param [in] version The version object to copy from. + /// @returns The version object that has been assigned to. + Version& operator=(const Version& version); + + bool operator==(const Version& version) const; + + bool operator!=(const Version& version) const; + + unsigned int operator[](const unsigned int i) const; + + unsigned int& operator[](const unsigned int i); +}; \ No newline at end of file diff --git a/src/sys/CPU.cpp b/src/sys/CPU.cpp new file mode 100644 index 0000000..8f0f9b4 --- /dev/null +++ b/src/sys/CPU.cpp @@ -0,0 +1,432 @@ +#include "CPU.h" + +Architecture CPU::GetArchitecture() +{ + #if defined(ARCH_X64) + return Architecture::X64; + #elif defined(ARCH_ARM64) + return Architecture::ARM64; + #else + return Architecture::UNKNOWN; + #endif +} + +UInt_8 CPU::PointerSize() +{ + return sizeof(void*); +} + +Endianness CPU::GetEndianness() +{ + #if defined(LITTLE_ENDIAN) + return Endianness::LE; + #elif defined(BIG_ENDIAN) + return Endianness::BE; + #else + UInt_16 tmp = 1; + if (((Byte*)&tmp)[0] == 1) + return Endianness::LE; + + return Endianness::BE; + #endif +} + +UInt_64 CPU::GetTSC() +{ + TSC tsc; + RDTSCP(&tsc); + + #if defined(ARCH_X64) + UInt_64 result = 0; + + #if defined(LITTLE_ENDIAN) + ((UInt_32*)&result)[0] = tsc.lowCount; + ((UInt_32*)&result)[1] = tsc.highCount; + #elif defined(BIG_ENDIAN) + ((UInt_32*)&result)[0] = tsc.highCount; + ((UInt_32*)&result)[1] = tsc.lowCount; + #endif + + return result; + #elif defined(ARCH_X86) + return tsc.lowPart; + #endif + + return 0; +} + +UInt_8 CPU::GetSteppingId() +{ + return (UInt_8)GetInfoBits() & 0x00001111; +} + +UInt_8 CPU::GetModelId() +{ + return (UInt_8)GetInfoBits() & 0x11110000; +} + +UInt_8 CPU::GetFamilyId() +{ + return (UInt_8)(GetInfoBits() >> 8) & 0x00001111; +} + +UInt_8 CPU::GetProcessorTypeId() +{ + return (UInt_8)(GetInfoBits() >> 12) & 0x00000011; +} + +UInt_8 CPU::GetExtModelId() +{ + return (UInt_8)(GetInfoBits() >> 16) & 0x00001111; +} + +UInt_8 CPU::GetExtFamilyId() +{ + return (UInt_8)(GetInfoBits() >> 20); +} + +bool CPU::HasFPU() +{ + return GetFeatureBits_1() & 0b00000000000000000000000000000001; +} + +bool CPU::HasVME() +{ + return GetFeatureBits_1() & 0b00000000000000000000000000000010; +} + +bool CPU::HasDE() +{ + return GetFeatureBits_1() & 0b00000000000000000000000000000100; +} + +bool CPU::HasPSE() +{ + return GetFeatureBits_1() & 0b00000000000000000000000000001000; +} + +bool CPU::HasTSC() +{ + return GetFeatureBits_1() & 0b00000000000000000000000000010000; +} + +bool CPU::HasMSR() +{ + return GetFeatureBits_1() & 0b00000000000000000000000000100000; +} + +bool CPU::HasPAE() +{ + return GetFeatureBits_1() & 0b00000000000000000000000001000000; +} + +bool CPU::HasMCE() +{ + return GetFeatureBits_1() & 0b00000000000000000000000010000000; +} + +bool CPU::HasCX8() +{ + return GetFeatureBits_1() & 0b00000000000000000000000100000000; +} + +bool CPU::HasAPIC() +{ + return GetFeatureBits_1() & 0b00000000000000000000001000000000; +} + +bool CPU::HasSEP() +{ + return GetFeatureBits_1() & 0b00000000000000000000100000000000; +} + +bool CPU::HasMTRR() +{ + return GetFeatureBits_1() & 0b00000000000000000001000000000000; +} + +bool CPU::HasPGE() +{ + return GetFeatureBits_1() & 0b00000000000000000010000000000000; +} + +bool CPU::HasMCA() +{ + return GetFeatureBits_1() & 0b00000000000000000100000000000000; +} + +bool CPU::HasCMOV() +{ + return GetFeatureBits_1() & 0b00000000000000001000000000000000; +} + +bool CPU::HasPAT() +{ + return GetFeatureBits_1() & 0b00000000000000010000000000000000; +} + +bool CPU::HasPSE_36() +{ + return GetFeatureBits_1() & 0b00000000000000100000000000000000; +} + +bool CPU::HasPSN() +{ + return GetFeatureBits_1() & 0b00000000000001000000000000000000; +} + +bool CPU::HasCLFSH() +{ + return GetFeatureBits_1() & 0b00000000000010000000000000000000; +} + +bool CPU::HasDS() +{ + return GetFeatureBits_1() & 0b00000000001000000000000000000000; +} + +bool CPU::HasACPI() +{ + return GetFeatureBits_1() & 0b00000000010000000000000000000000; +} + +bool CPU::HasMMX() +{ + return GetFeatureBits_1() & 0b00000000100000000000000000000000; +} + +bool CPU::HasFXSR() +{ + return GetFeatureBits_1() & 0b00000001000000000000000000000000; +} + +bool CPU::HasSSE() +{ + return GetFeatureBits_1() & 0b00000010000000000000000000000000; +} + +bool CPU::HasSSE2() +{ + return GetFeatureBits_1() & 0b00000100000000000000000000000000; +} + +bool CPU::HasSS() +{ + return GetFeatureBits_1() & 0b00001000000000000000000000000000; +} + +bool CPU::HasHTT() +{ + return GetFeatureBits_1() & 0b00010000000000000000000000000000; +} + +bool CPU::HasTM() +{ + return GetFeatureBits_1() & 0b00100000000000000000000000000000; +} + +bool CPU::HasIA64() +{ + return GetFeatureBits_1() & 0b01000000000000000000000000000000; +} + +bool CPU::HasPBE() +{ + return GetFeatureBits_1() & 0b10000000000000000000000000000000; +} + +bool CPU::HasSSE3() +{ + return GetFeatureBits_2() & 0b00000000000000000000000000000001; +} + +bool CPU::HasPCLMULQDQ() +{ + return GetFeatureBits_2() & 0b00000000000000000000000000000010; +} + +bool CPU::HasDTES64() +{ + return GetFeatureBits_2() & 0b00000000000000000000000000000100; +} + +bool CPU::HasMONITOR() +{ + return GetFeatureBits_2() & 0b00000000000000000000000000001000; +} + +bool CPU::HasDS_CPL() +{ + return GetFeatureBits_2() & 0b00000000000000000000000000010000; +} + +bool CPU::HasVMX() +{ + return GetFeatureBits_2() & 0b00000000000000000000000000100000; +} + +bool CPU::HasSMX() +{ + return GetFeatureBits_2() & 0b00000000000000000000000001000000; +} + +bool CPU::HasEST() +{ + return GetFeatureBits_2() & 0b00000000000000000000000010000000; +} + +bool CPU::HasTM2() +{ + return GetFeatureBits_2() & 0b00000000000000000000000100000000; +} + +bool CPU::HasSSSE3() +{ + return GetFeatureBits_2() & 0b00000000000000000000001000000000; +} + +bool CPU::HasCNXT_ID() +{ + return GetFeatureBits_2() & 0b00000000000000000000010000000000; +} + +bool CPU::HasSDBG() +{ + return GetFeatureBits_2() & 0b00000000000000000000100000000000; +} + +bool CPU::HasFMA() +{ + return GetFeatureBits_2() & 0b00000000000000000001000000000000; +} + +bool CPU::HasCX16() +{ + return GetFeatureBits_2() & 0b00000000000000000010000000000000; +} + +bool CPU::HasXTPR() +{ + return GetFeatureBits_2() & 0b00000000000000000100000000000000; +} + +bool CPU::HasPDCM() +{ + return GetFeatureBits_2() & 0b00000000000000001000000000000000; +} + +bool CPU::HasPCID() +{ + return GetFeatureBits_2() & 0b00000000000000100000000000000000; +} + +bool CPU::HasDCA() +{ + return GetFeatureBits_2() & 0b00000000000001000000000000000000; +} + +bool CPU::HasSSE4_1() +{ + return GetFeatureBits_2() & 0b00000000000010000000000000000000; +} + +bool CPU::HasSSE4_2() +{ + return GetFeatureBits_2() & 0b00000000000100000000000000000000; +} + +bool CPU::HasX2APIC() +{ + return GetFeatureBits_2() & 0b00000000001000000000000000000000; +} + +bool CPU::HasMOVBE() +{ + return GetFeatureBits_2() & 0b00000000010000000000000000000000; +} + +bool CPU::HasPOPCNT() +{ + return GetFeatureBits_2() & 0b00000000100000000000000000000000; +} + +bool CPU::HasTSC_DEADLINE() +{ + return GetFeatureBits_2() & 0b00000001000000000000000000000000; +} + +bool CPU::HasAES() +{ + return GetFeatureBits_2() & 0b00000010000000000000000000000000; +} + +bool CPU::HasXSAVE() +{ + return GetFeatureBits_2() & 0b00000100000000000000000000000000; +} + +bool CPU::HasOSXSAVE() +{ + return GetFeatureBits_2() & 0b00001000000000000000000000000000; +} + +bool CPU::HasAVX() +{ + return GetFeatureBits_2() & 0b00010000000000000000000000000000; +} + +bool CPU::HasF16C() +{ + return GetFeatureBits_2() & 0b00100000000000000000000000000000; +} + +bool CPU::HasRDRND() +{ + return GetFeatureBits_2() & 0b01000000000000000000000000000000; +} + +bool CPU::HasHYPERVISOR() +{ + return GetFeatureBits_2() & 0b10000000000000000000000000000000; +} + +bool CPU::HasAVX2() +{ + return GetExtFeatureBits_1() & 0b00000000000000000000000000100000; +} + +bool CPU::HasRDSEED() +{ + return GetExtFeatureBits_1() & 0b00000000000001000000000000000000; +} + +bool CPU::HasADX() +{ + return GetExtFeatureBits_1() & 0b00000000000010000000000000000000; +} + +/* +Str_8 CPU::ToStr() +{ + return "Manufacturer: " + GetManufacturer() + "\r\n" + + "Brand: " + GetBrand() + "\r\n" + + "Stepping Id: " + Str_8::FromNum(GetSteppingId()) + "\r\n" + + "GpuModel Id: " + Str_8::FromNum(GetModelId()) + "\r\n" + + "Family Id: " + Str_8::FromNum(GetFamilyId()) + "\r\n" + + "Processor Type Id: " + Str_8::FromNum(GetProcessorTypeId()) + "\r\n" + + "Extended GpuModel Id: " + Str_8::FromNum(GetExtModelId()) + "\r\n" + + "Extended Family Id: " + Str_8::FromNum(GetExtFamilyId()) + "\r\n" + + "Has FPU: " + Str_8::FromNum((UInt_8)HasFPU()) + "\r\n" + + "Has SSE: " + Str_8::FromNum((UInt_8)HasSSE()) + "\r\n" + + "Has SSE 2: " + Str_8::FromNum((UInt_8)HasSSE2()) + "\r\n" + + "Has SSE 3: " + Str_8::FromNum((UInt_8)HasSSE3()) + "\r\n" + + "Has SSSE 3: " + Str_8::FromNum((UInt_8)HasSSSE3()) + "\r\n" + + "Has SSE 4.1: " + Str_8::FromNum((UInt_8)HasSSE4_1()) + "\r\n" + + "Has SSE 4.2: " + Str_8::FromNum((UInt_8)HasSSE4_2()) + "\r\n" + + "Has AVX: " + Str_8::FromNum((UInt_8)HasAVX()) + "\r\n" + + "Has RDRND: " + Str_8::FromNum((UInt_8)HasRDRND()) + "\r\n" + + "Has AVX 2: " + Str_8::FromNum((UInt_8)HasAVX2()) + "\r\n" + + "Has ADX: " + Str_8::FromNum((UInt_8)HasADX()) + "\r\n" + + "Has RDSEED: " + Str_8::FromNum((UInt_8)HasRDSEED()); +} +*/ \ No newline at end of file diff --git a/src/sys/CPU.h b/src/sys/CPU.h new file mode 100644 index 0000000..03577e8 --- /dev/null +++ b/src/sys/CPU.h @@ -0,0 +1,203 @@ +#pragma once + +#include "../EHS.h" +#include "../Str.h" +#include "../Array.h" + +enum class Architecture : UInt_8 +{ + X64, + X86, + ARM64, + ARM, + UNKNOWN +}; + +enum class Endianness : UInt_8 +{ + LE, + BE +}; + +struct TSC +{ + UInt_32 coreId = 0; + UInt_32 highCount = 0; + UInt_32 lowCount = 0; +}; + +class CPU +{ +public: + static Architecture GetArchitecture(); + + static UInt_8 PointerSize(); + + static Endianness GetEndianness(); + + static void RDTSCP(TSC* tsc); + + static UInt_64 GetTSC(); + + /// Retrieves the CPU manufacturer id as a null-terminated ASCII string. + /// @param[out] input A twelve byte character array representing the manufacturer id. + static void GetManufacturer(Char_8* input); + + static UInt_32 GetInfoBits(); + + static UInt_8 GetSteppingId(); + + static UInt_8 GetModelId(); + + static UInt_8 GetFamilyId(); + + static UInt_8 GetProcessorTypeId(); + + static UInt_8 GetExtModelId(); + + static UInt_8 GetExtFamilyId(); + + static UInt_32 GetFeatureBits_1(); + + static bool HasFPU(); + + static bool HasVME(); + + static bool HasDE(); + + static bool HasPSE(); + + static bool HasTSC(); + + static bool HasMSR(); + + static bool HasPAE(); + + static bool HasMCE(); + + static bool HasCX8(); + + static bool HasAPIC(); + + static bool HasSEP(); + + static bool HasMTRR(); + + static bool HasPGE(); + + static bool HasMCA(); + + static bool HasCMOV(); + + static bool HasPAT(); + + static bool HasPSE_36(); + + static bool HasPSN(); + + static bool HasCLFSH(); + + static bool HasDS(); + + static bool HasACPI(); + + static bool HasMMX(); + + static bool HasFXSR(); + + static bool HasSSE(); + + static bool HasSSE2(); + + static bool HasSS(); + + static bool HasHTT(); + + static bool HasTM(); + + static bool HasIA64(); + + static bool HasPBE(); + + static UInt_32 GetFeatureBits_2(); + + static bool HasSSE3(); + + static bool HasPCLMULQDQ(); + + static bool HasDTES64(); + + static bool HasMONITOR(); + + static bool HasDS_CPL(); + + static bool HasVMX(); + + static bool HasSMX(); + + static bool HasEST(); + + static bool HasTM2(); + + static bool HasSSSE3(); + + static bool HasCNXT_ID(); + + static bool HasSDBG(); + + static bool HasFMA(); + + static bool HasCX16(); + + static bool HasXTPR(); + + static bool HasPDCM(); + + static bool HasPCID(); + + static bool HasDCA(); + + static bool HasSSE4_1(); + + static bool HasSSE4_2(); + + static bool HasX2APIC(); + + static bool HasMOVBE(); + + static bool HasPOPCNT(); + + static bool HasTSC_DEADLINE(); + + static bool HasAES(); + + static bool HasXSAVE(); + + static bool HasOSXSAVE(); + + static bool HasAVX(); + + static bool HasF16C(); + + static bool HasRDRND(); + + static bool HasHYPERVISOR(); + + static UInt_32 GetExtFeatureBits_1(); + + static bool HasAVX2(); + + static bool HasRDSEED(); + + static bool HasADX(); + + static UInt_32 GetExtFeatureBits_2(); + + static UInt_32 GetExtFeatureBits_3(); + + /// Retrieves the CPU brand as a null-terminated ASCII string. + /// @param[out] input A 48 byte character array representing the brand. + static void GetBrand(Char_8* input); + + //static Str_8 ToStr(); +}; \ No newline at end of file diff --git a/src/sys/CPU_GCC_AMD64.asm b/src/sys/CPU_GCC_AMD64.asm new file mode 100644 index 0000000..98a5cc0 --- /dev/null +++ b/src/sys/CPU_GCC_AMD64.asm @@ -0,0 +1,132 @@ +global _ZN3lwe3CPU6RDTSCPEPNS_3TSCE +global _ZN3lwe3CPU15GetManufacturerEPc +global _ZN3lwe3CPU11GetInfoBitsEv +global _ZN3lwe3CPU16GetFeatureBits_1Ev +global _ZN3lwe3CPU16GetFeatureBits_2Ev +global _ZN3lwe3CPU19GetExtFeatureBits_1Ev +global _ZN3lwe3CPU19GetExtFeatureBits_2Ev +global _ZN3lwe3CPU19GetExtFeatureBits_3Ev +global _ZN3lwe3CPU8GetBrandEPc + +section .text + _ZN3lwe3CPU6RDTSCPEPNS_3TSCE: + RDTSCP + MOV DWORD [RDI], ECX + MOV DWORD [RDI + 4], EDX + MOV DWORD [RDI + 8], EAX + RET + + _ZN3lwe3CPU15GetManufacturerEPc: + PUSH RBX + + XOR EAX, EAX + CPUID + + MOV DWORD [RDI], EBX + MOV DWORD [RDI + 4], EDX + MOV DWORD [RDI + 8], ECX + + POP RBX + + RET + + _ZN3lwe3CPU11GetInfoBitsEv: + PUSH RBX + + MOV EAX, 1 + CPUID + + POP RBX + + RET + + _ZN3lwe3CPU16GetFeatureBits_1Ev: + PUSH RBX + + MOV EAX, 1 + CPUID + + MOV EAX, EDX + + POP RBX + + RET + + _ZN3lwe3CPU16GetFeatureBits_2Ev: + PUSH RBX + + MOV EAX, 1 + CPUID + + MOV EAX, ECX + + POP RBX + + RET + + _ZN3lwe3CPU19GetExtFeatureBits_1Ev: + PUSH RBX + + MOV EAX, 7 + XOR ECX, ECX + CPUID + + MOV EAX, EBX + + POP RBX + + RET + + _ZN3lwe3CPU19GetExtFeatureBits_2Ev: + PUSH RBX + + MOV EAX, 7 + XOR ECX, ECX + CPUID + + MOV EAX, ECX + + POP RBX + + RET + + _ZN3lwe3CPU19GetExtFeatureBits_3Ev: + PUSH RBX + + MOV EAX, 7 + XOR ECX, ECX + CPUID + + MOV EAX, EDX + + POP RBX + + RET + + _ZN3lwe3CPU8GetBrandEPc: + PUSH RBX + + MOV EAX, 80000002h + CPUID + MOV DWORD [RDI], EAX + MOV DWORD [RDI + 4], EBX + MOV DWORD [RDI + 8], ECX + MOV DWORD [RDI + 12], EDX + + MOV EAX, 80000003h + CPUID + MOV DWORD [RDI + 16], EAX + MOV DWORD [RDI + 20], EBX + MOV DWORD [RDI + 24], ECX + MOV DWORD [RDI + 28], EDX + + MOV EAX, 80000004h + CPUID + MOV DWORD [RDI + 32], EAX + MOV DWORD [RDI + 36], EBX + MOV DWORD [RDI + 40], ECX + MOV DWORD [RDI + 44], EDX + + POP RBX + + RET \ No newline at end of file diff --git a/src/sys/CPU_MSVC_AMD64.asm b/src/sys/CPU_MSVC_AMD64.asm new file mode 100644 index 0000000..a43c345 --- /dev/null +++ b/src/sys/CPU_MSVC_AMD64.asm @@ -0,0 +1,127 @@ +global ?GetManufacturer@CPU@lwe@@SAXPEAD@Z +global ?GetInfoBits@CPU@lwe@@SAIXZ +global ?GetFeatureBits_1@CPU@lwe@@SAIXZ +global ?GetFeatureBits_2@CPU@lwe@@SAIXZ +global ?GetExtFeatureBits_1@CPU@lwe@@SAIXZ +global ?GetExtFeatureBits_2@CPU@lwe@@SAKXZ +global ?GetExtFeatureBits_3@CPU@lwe@@SAKXZ +global ?GetBrand@CPU@lwe@@SAXPEAD@Z + +section .text + ?GetManufacturer@CPU@lwe@@SAXPEAD@Z: + PUSH RBX + + XOR EAX, EAX + MOV R8, RCX + CPUID + + MOV DWORD [R8], EBX + MOV DWORD [R8 + 4], EDX + MOV DWORD [R8 + 8], ECX + + POP RBX + + RET + + ?GetInfoBits@CPU@lwe@@SAIXZ: + PUSH RBX + + MOV EAX, 1 + CPUID + + POP RBX + + RET + + ?GetFeatureBits_1@CPU@lwe@@SAIXZ: + PUSH RBX + + MOV EAX, 1 + CPUID + + MOV EAX, EDX + + POP RBX + + RET + + ?GetFeatureBits_2@CPU@lwe@@SAIXZ: + PUSH RBX + + MOV EAX, 1 + CPUID + + MOV EAX, ECX + + POP RBX + + RET + + ?GetExtFeatureBits_1@CPU@lwe@@SAIXZ: + PUSH RBX + + MOV EAX, 7 + XOR ECX, ECX + CPUID + + MOV EAX, EBX + + POP RBX + + RET + + ?GetExtFeatureBits_2@CPU@lwe@@SAKXZ: + PUSH RBX + + MOV EAX, 7 + XOR ECX, ECX + CPUID + + MOV EAX, ECX + + POP RBX + + RET + + ?GetExtFeatureBits_3@CPU@lwe@@SAKXZ: + PUSH RBX + + MOV EAX, 7 + XOR ECX, ECX + CPUID + + MOV EAX, EDX + + POP RBX + + RET + + ?GetBrand@CPU@lwe@@SAXPEAD@Z: + PUSH RBX + + MOV R8, RCX + + MOV EAX, 80000002h + CPUID + MOV DWORD [R8], EAX + MOV DWORD [R8 + 4], EBX + MOV DWORD [R8 + 8], ECX + MOV DWORD [R8 + 12], EDX + + MOV EAX, 80000003h + CPUID + MOV DWORD [R8 + 16], EAX + MOV DWORD [R8 + 20], EBX + MOV DWORD [R8 + 24], ECX + MOV DWORD [R8 + 28], EDX + + MOV EAX, 80000004h + CPUID + MOV DWORD [R8 + 32], EAX + MOV DWORD [R8 + 36], EBX + MOV DWORD [R8 + 40], ECX + MOV DWORD [R8 + 44], EDX + + POP RBX + + RET \ No newline at end of file