first commit of some basics

This commit is contained in:
2026-01-17 09:13:59 +01:00
parent f9bc556ad9
commit c770c62400
41 changed files with 13610 additions and 0 deletions

1
.gitignore vendored
View File

@@ -100,3 +100,4 @@ Module.symvers
Mkfile.old
dkms.conf
build

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"cmake.ignoreCMakeListsMissing": true
}

53
TSE_Base/CMakeLists.txt Normal file
View File

@@ -0,0 +1,53 @@
#cmake version
cmake_minimum_required(VERSION 3.31)
#project name
project(TSE_Base)
#cpp settings
find_program(CLANG_C NAMES clang)
find_program(CLANG_CXX NAMES clang++)
if(CLANG_C AND CLANG_CXX)
message(STATUS "foung Clang, using as Compiler")
set(CMAKE_C_COMPILER ${CLANG_C} CACHE STRING "C Compiler" FORCE)
set(CMAKE_CXX_COMPILER ${CLANG_CXX} CACHE STRING "C++ Compiler" FORCE)
else()
message(STATUS "Clang not found, using Standard-Compiler")
endif()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
#project output settings
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/lib")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${PROJECT_SOURCE_DIR}/lib/Debug")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/lib/Release")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${PROJECT_SOURCE_DIR}/lib/Debug")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/lib/Release")
#source files
file(GLOB CPP_SOURCE_TSE
"${PROJECT_SOURCE_DIR}/src/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*/*/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*/*/*/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*.c"
"${PROJECT_SOURCE_DIR}/src/*/*.c"
"${PROJECT_SOURCE_DIR}/src/*/*/*.c"
"${PROJECT_SOURCE_DIR}/src/*/*/*/*.c"
)
#includes
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_SOURCE_DIR}/include)
#project def
if(Lib)
add_library(TSE_Base SHARED ${CPP_SOURCE_TSE})
else()
add_library(TSE_Base STATIC ${CPP_SOURCE_TSE})
endif()
#flags
target_compile_options(TSE_Base PRIVATE -march=native)

10664
TSE_Base/include/LuaBridge.h Normal file

File diff suppressed because it is too large Load Diff

82
TSE_Base/src/Debug.cpp Normal file
View File

@@ -0,0 +1,82 @@
#include "Debug.hpp"
#include "PathHelper.hpp"
std::ofstream TSE::Debug::logFile;
const std::string fileName = "log.txt";
const std::string fileNameOld = "lastlog.txt";
int luaPrintRedirect(lua_State* L)
{
int n = lua_gettop(L);
std::string out;
out.reserve(256);
for (int i = 1; i <= n; ++i) {
const char* s = lua_tostring(L, i);
if (s)
out += s;
else
out += "<non-string>";
if (i < n)
out += "\t";
}
TSE_LOG(out);
return 0;
}
void TSE::Debug::Init()
{
std::string path = "";
std::string oldpath = "";
GetAppDataPath(path);
CombinePaths(oldpath, path, fileNameOld);
CombinePaths(path, path, fileName);
if(FileExists(path))
{
if(FileExists(oldpath))
{
std::remove(oldpath.c_str());
}
std::rename(path.c_str(), oldpath.c_str());
}
CreateFileWriting(logFile, path);
luabridge::getGlobalNamespace(TSE_LUA_STATE)
.beginNamespace("debug")
.addFunction("log", TSE::Debug::Log)
.addFunction("warning", TSE::Debug::Warning)
.addFunction("error", TSE::Debug::Error)
.endNamespace();
lua_pushcfunction(TSE_LUA_STATE, luaPrintRedirect);
lua_setglobal(TSE_LUA_STATE, "print");
}
void TSE::Debug::Log(string msg)
{
std::cout << msg << std::endl;
logFile << msg << std::endl;
}
void TSE::Debug::Error(string msg)
{
std::cerr << "[Error] " << msg << std::endl;
logFile << "[Error] " << msg << std::endl;
}
void TSE::Debug::Warning(string msg)
{
std::cout << "[Warning] " << msg << std::endl;
logFile << "[Warning] " << msg << std::endl;
}
void TSE::Debug::Close()
{
logFile.flush();
logFile.close();
}

35
TSE_Base/src/Debug.hpp Normal file
View File

@@ -0,0 +1,35 @@
#pragma once
#include "LuaStateHandler.hpp"
#include "Types.hpp"
#define TSE_LOG(msg) TSE::Debug::Log(msg)
#define TSE_ERROR(msg) TSE::Debug::Error(msg)
#define TSE_WARNING(msg) TSE::Debug::Warning(msg)
namespace TSE
{
class Debug
{
public:
/// @brief initializes the log file in app data or .local, and binds lua functions
static void Init();
/// @brief logs soumething to the stdout, and into the log file
/// @param msg the message to be logged
static void Log(string msg);
/// @brief logs soumething to the stdout, and into the log file
/// @param msg the message to be logged
static void Error(string msg);
/// @brief logs soumething to the stdout, and into the log file
/// @param msg the message to be logged
static void Warning(string msg);
/// @brief closes the log file
static void Close();
private:
static std::ofstream logFile;
};
} // namespace TSE

View File

@@ -0,0 +1,42 @@
#include "LuaStateHandler.hpp"
#include "version.h"
#include "Debug.hpp"
void printVersionString()
{
TSE_LOG("TSE: " + TSE_VERSION_STRING);
}
void TSE::LuaStateHandler::InitLuaState()
{
L = luaL_newstate();
luaL_openlibs(L);
luabridge::getGlobalNamespace(TSE_LUA_STATE)
.beginNamespace("engine")
.addProperty("version", getVersionString)
.addFunction("printVersion", printVersionString)
.endNamespace();
}
void TSE::LuaStateHandler::RunLuaString(string cmd)
{
int res = luaL_dostring(L, cmd.c_str());
if (res != LUA_OK)
{
const char* err = lua_tostring(L, -1);
TSE_ERROR(err ? err : "<unknown lua error>");
lua_pop(L,1);
}
}
void TSE::LuaStateHandler::RunLuaScript(string path)
{
int res = luaL_dofile(L, path.c_str());
if (res != LUA_OK)
{
const char* err = lua_tostring(L, -1);
TSE_ERROR(err ? err : "<unknown lua error>");
lua_pop(L,1);
}
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include <lua5.4/lua.hpp>
#include "LuaBridge.h"
#include "Types.hpp"
#define TSE_LUA_STATE TSE::LuaStateHandler::L
#define TSE_LUA_RUN_COMMAND(cmd) TSE::LuaStateHandler::RunLuaString(cmd)
#define TSE_LUA_RUN_SCRIPT(path) TSE::LuaStateHandler::RunLuaScript(path)
namespace TSE
{
class LuaStateHandler
{
public:
static inline lua_State* L;
static void InitLuaState();
static void RunLuaString(string cmd);
static void RunLuaScript(string path);
};
} // namespace TSE

View File

@@ -0,0 +1,68 @@
#include "PathHelper.hpp"
#include <filesystem>
#include <cstdlib>
#ifdef _WIN32
#include <windows.h>
#include <shlobj.h> // SHGetFolderPath
#pragma comment(lib, "shell32.lib")
#else
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#endif
bool TSE::FileExists(const std::string &path)
{
return std::filesystem::exists(path);
}
void TSE::OpenFileReading(std::ifstream &stream, const std::string &path)
{
stream.open(path, std::ios::in);
}
void TSE::CreateFileWriting(std::ofstream &stream, const std::string &path)
{
stream.open(path, std::ios::out);
}
void TSE::AppendFileWriting(std::ofstream &stream, const std::string &path)
{
stream.open(path, std::ios::app);
}
void TSE::GetAppDataPath(std::string &path)
{
#ifdef _WIN32
char appDataPath[MAX_PATH];
if (SUCCEEDED(SHGetFolderPathA(nullptr, CSIDL_APPDATA, nullptr, 0, appDataPath))) {
path = std::string(appDataPath) + "\\TSE";
} else {
path = ".\\TSE"; // fallback
}
#else
const char* homeDir = getenv("HOME");
if (!homeDir) {
struct passwd* pw = getpwuid(getuid());
homeDir = pw->pw_dir;
}
path = std::string(homeDir) + "/.local/share/TSE";
#endif
if(!FileExists(path)){
std::filesystem::create_directory(path);
}
}
void TSE::CombinePaths(std::string &res, const std::string &path1, const std::string &path2)
{
#ifdef _WIN32
//check for path parts containing forwardlasches
res = path1 + "\\" + path2;
#else
//check for path parts containing backslasches
res = path1 + "/" + path2;
#endif
}

View File

@@ -0,0 +1,33 @@
#pragma once
#include "Types.hpp"
#include <fstream>
namespace TSE
{
/// @brief checks if a file exists at a path
/// @param path the path to check
/// @return file exists
bool FileExists(const std::string& path);
/// @brief opens a path for reading
/// @param stream the stream to be assigned
/// @param path the path to open
void OpenFileReading(std::ifstream& stream, const std::string& path);
/// @brief opens a path for writing
/// @param stream the stream to be assigned
/// @param path the path to open
void CreateFileWriting(std::ofstream& stream, const std::string& path);
/// @brief opens a path for appending
/// @param stream the stream to be assigned
/// @param path the path to open
void AppendFileWriting(std::ofstream& stream, const std::string& path);
/// @brief gets the platform specific tmp folder in appdata or .local
/// @param path the resulting path
void GetAppDataPath(std::string& path);
/// @brief combines two paths in a platform specific way
/// @param res the resulting path
/// @param path1 path part 1
/// @param path2 path part 2
void CombinePaths(std::string& res,const std::string& path1,const std::string& path2);
} // namespace TSE

17
TSE_Base/src/Types.hpp Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
#include <string>
namespace TSE
{
typedef std::string string;
typedef char byte;
typedef signed char sbyte;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
} // namespace TSE

10
TSE_Base/src/version.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include <string>
#define TSE_VERSION_MAJOR 0
#define TSE_VERSION_MINOR 0
#define TSE_VERSION_BUILD 1
#define TSE_VERSION_STRING std::to_string(TSE_VERSION_MAJOR) + "." + std::to_string(TSE_VERSION_MINOR) + "." + std::to_string(TSE_VERSION_BUILD)
std::string getVersionString() { return TSE_VERSION_STRING; }

56
TSE_Core/CMakeLists.txt Normal file
View File

@@ -0,0 +1,56 @@
#cmake version
cmake_minimum_required(VERSION 3.31)
#project name
project(TSE_Core)
#cpp settings
find_program(CLANG_C NAMES clang)
find_program(CLANG_CXX NAMES clang++)
if(CLANG_C AND CLANG_CXX)
message(STATUS "foung Clang, using as Compiler")
set(CMAKE_C_COMPILER ${CLANG_C} CACHE STRING "C Compiler" FORCE)
set(CMAKE_CXX_COMPILER ${CLANG_CXX} CACHE STRING "C++ Compiler" FORCE)
else()
message(STATUS "Clang not found, using Standard-Compiler")
endif()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
#project output settings
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/lib")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${PROJECT_SOURCE_DIR}/lib/Debug")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/lib/Release")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${PROJECT_SOURCE_DIR}/lib/Debug")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/lib/Release")
#source files
file(GLOB CPP_SOURCE_TSE
"${PROJECT_SOURCE_DIR}/src/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*/*/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*/*/*/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*.c"
"${PROJECT_SOURCE_DIR}/src/*/*.c"
"${PROJECT_SOURCE_DIR}/src/*/*/*.c"
"${PROJECT_SOURCE_DIR}/src/*/*/*/*.c"
)
#includes
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_SOURCE_DIR}/../TSE_Math/src)
include_directories(${PROJECT_SOURCE_DIR}/../TSE_Base/src)
include_directories(${PROJECT_SOURCE_DIR}/../TSE_Base/include)
#project def
if(Lib)
add_library(TSE_Core SHARED ${CPP_SOURCE_TSE})
else()
add_library(TSE_Core STATIC ${CPP_SOURCE_TSE})
endif()
#flags
target_compile_options(TSE_Core PRIVATE -march=native)

View File

@@ -0,0 +1,13 @@
#pragma once
namespace TSE
{
enum WindowType
{
Unnknown = 0,
Windowed = 1,
Fullscreen = 2,
FullscreenWindowed = 3,
Maximized = 4,
};
} // namespace TSE

View File

@@ -0,0 +1,16 @@
#pragma once
#include "IResizable.hpp"
namespace TSE
{
class IRenderTarget : public IResizable
{
public:
int UnitScaler = 32;
virtual void Update();
virtual void Bind();
virtual void Unbind();
};
} // namespace TSE

View File

@@ -0,0 +1,29 @@
#pragma once
#include "Color.hpp"
namespace TSE
{
class IWindow;
class IRenderingBackend
{
protected:
Color backgroundColor;
bool vsync;
int samples = 0;
bool useseImGui = false;
public:
IWindow* window = nullptr;
virtual void InitPreWindow() = 0;
virtual bool InitPostWindow() = 0;
virtual void onResize(int width, int height) = 0;
virtual void onUpdate() const = 0;
virtual void onClear() const = 0;
virtual void onClearDepthBuffer() const = 0;
};
} // namespace TSE

View File

@@ -0,0 +1,25 @@
#include "IResizable.hpp"
void TSE::IResizable::AddResizeNotifiable(IResizeNotifiable *obj)
{
std::list<IResizeNotifiable*>::iterator it;
for (it = objectsToResize.begin(); it != objectsToResize.end(); ++it)
{
if((*it) == obj){
return; //return if already in list
}
}
objectsToResize.push_back(obj);
}
void TSE::IResizable::RemoveResizeNotifiable(IResizeNotifiable *obj)
{
std::list<IResizeNotifiable*>::iterator it;
for (it = objectsToResize.begin(); it != objectsToResize.end(); ++it)
{
if((*it) == obj){
objectsToResize.erase(it);
break;
}
}
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include <list>
#include "IResizeNotifiable.hpp"
namespace TSE
{
class IResizable
{
protected:
float width;
float height;
std::list<IResizeNotifiable*> objectsToResize;
public:
void AddResizeNotifiable(IResizeNotifiable* obj);
void RemoveResizeNotifiable(IResizeNotifiable* obj);
};
} // namespace TSE

View File

@@ -0,0 +1,18 @@
#pragma once
namespace TSE
{
class IResizable;
class IResizeNotifiable
{
public:
/// @brief gets called, when a Resizable gets resized as an event.
/// @param width the new width
/// @param height the new height
/// @param resizable the resizable that got changed
virtual void OnResize(float width, float height, IResizable* resizable);
virtual ~IResizeNotifiable() = default;
};
} // namespace TSE

View File

@@ -0,0 +1,16 @@
#include "IWindow.hpp"
#include "Debug.hpp"
#include "LuaStateHandler.hpp"
TSE::IWindow* TSE::IWindow::lastWindow = nullptr;
bool TSE::IWindow::BaseInit() const
{
LuaStateHandler::InitLuaState();
Debug::Init();
}
TSE::IWindow::~IWindow()
{
Debug::Close();
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "IRenderTarget.hpp"
#include "Types.hpp"
namespace TSE
{
class IWindow : public IRenderTarget
{
public:
static IWindow* lastWindow;
string title;
protected:
virtual bool Init() = 0;
public:
virtual void Clear() const = 0;
virtual void Update() const = 0;
virtual void ClearDepthBuffer() const = 0;
virtual bool ShouldClose() const = 0;
bool BaseInit() const;
~IWindow();
};
} // namespace TSE

55
TSE_Math/CMakeLists.txt Normal file
View File

@@ -0,0 +1,55 @@
#cmake version
cmake_minimum_required(VERSION 3.31)
#project name
project(TSE_Math)
#cpp settings
find_program(CLANG_C NAMES clang)
find_program(CLANG_CXX NAMES clang++)
if(CLANG_C AND CLANG_CXX)
message(STATUS "foung Clang, using as Compiler")
set(CMAKE_C_COMPILER ${CLANG_C} CACHE STRING "C Compiler" FORCE)
set(CMAKE_CXX_COMPILER ${CLANG_CXX} CACHE STRING "C++ Compiler" FORCE)
else()
message(STATUS "Clang not found, using Standard-Compiler")
endif()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
#project output settings
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/lib")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${PROJECT_SOURCE_DIR}/lib/Debug")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/lib/Release")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${PROJECT_SOURCE_DIR}/lib/Debug")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/lib/Release")
#source files
file(GLOB CPP_SOURCE_TSE
"${PROJECT_SOURCE_DIR}/src/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*/*/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*/*/*/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*.c"
"${PROJECT_SOURCE_DIR}/src/*/*.c"
"${PROJECT_SOURCE_DIR}/src/*/*/*.c"
"${PROJECT_SOURCE_DIR}/src/*/*/*/*.c"
)
#includes
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_SOURCE_DIR}/../TSE_Base/src)
#project def
#add_library(TSE_Math STATIC ${CPP_SOURCE_TSE})
if(Lib)
add_library(TSE_Math SHARED ${CPP_SOURCE_TSE})
else()
add_library(TSE_Math STATIC ${CPP_SOURCE_TSE})
endif()
#flags
target_compile_options(TSE_Math PRIVATE -march=native)

178
TSE_Math/src/Color.cpp Normal file
View File

@@ -0,0 +1,178 @@
#include "Color.hpp"
#include "Vector4.hpp"
#include <cmath>
TSE::Color const TSE::Color::red = TSE::Color(1.0f,0.0f,0.0f);
TSE::Color const TSE::Color::blue = TSE::Color(0.0f,1.0f,0.0f);
TSE::Color const TSE::Color::green = TSE::Color(0.0f,0.0f,1.0f);
TSE::Color const TSE::Color::white = TSE::Color(1.0f,1.0f,1.0f);
TSE::Color const TSE::Color::black = TSE::Color(0.0f,0.0f,0.0f);
TSE::Color const TSE::Color::gray = TSE::Color(0.5f,0.5f,0.5f);
TSE::Color const TSE::Color::darkGray = TSE::Color(0.2f,0.2f,0.2f);
TSE::Color const TSE::Color::yellow = TSE::Color(1.0f,1.0f,0.0f);
TSE::Color const TSE::Color::orange = TSE::Color(1.0f,0.5f,0.0f);
TSE::Color const TSE::Color::aqua = TSE::Color(0.0f,1.0f,1.0f);
TSE::Color::Color() { }
TSE::Color::Color(float _r, float _g, float _b)
{
r = _r;
g = _g;
b = _b;
}
TSE::Color::Color(float _r, float _g, float _b, float _a)
{
r = _r;
g = _g;
b = _b;
a = _a;
}
TSE::Color::Color(byte _r, byte _g, byte _b)
{
r = _r / 255.0f;
g = _g / 255.0f;
b = _b / 255.0f;
}
TSE::Color::Color(byte _r, byte _g, byte _b, byte _a)
{
r = _r / 255.0f;
g = _g / 255.0f;
b = _b / 255.0f;
a = _a / 255.0f;
}
TSE::Color::Color(const Color &other)
{
r = other.r;
g = other.g;
b = other.b;
a = other.a;
}
TSE::Color::Color(const Vector4 &other)
{
r = other.x;
g = other.y;
b = other.z;
a = other.w;
}
bool TSE::Color::IsValid() const
{
return (!std::isnan(r) && r >= 0 && r <= 1) && (!std::isnan(g) && g >= 0 && g <= 1) && (!std::isnan(b) && b >= 0 && b <= 1) && (!std::isnan(a) && a >= 0 && a <= 1);
}
TSE::byte TSE::Color::R() const
{
return r * 255;
}
TSE::byte TSE::Color::G() const
{
return g * 255;
}
TSE::byte TSE::Color::B() const
{
return b * 255;
}
TSE::byte TSE::Color::A() const
{
return a * 255;
}
TSE::string TSE::Color::ToString() const
{
return "(" + std::to_string(r) + "|" + std::to_string(g) + "|" + std::to_string(b) + "|" + std::to_string(a) + ")";
}
TSE::Vector4 TSE::Color::ToVector4() const
{
return Vector4(r,g,b,a);
}
TSE::Color TSE::Color::Lerp(const Color &a, const Color &b, const float t)
{
return a + (b - a) * t;
}
TSE::Color TSE::Color::operator+(const Color &other) const
{
return Vector4(r + other.r, g + other.g, b + other.b, a + other.a);
}
TSE::Color TSE::Color::operator+=(const Color &other)
{
*this = *this + other;
return *this;
}
TSE::Color TSE::Color::operator-(const Color &other) const
{
return Vector4(r - other.r, g - other.g, b - other.b, a - other.a);
}
TSE::Color TSE::Color::operator-=(const Color &other)
{
*this = *this - other;
return *this;
}
TSE::Color TSE::Color::operator*(const Color &other) const
{
return Vector4(r * other.r, g * other.g, b * other.b, a * other.a);
}
TSE::Color TSE::Color::operator*=(const Color &other)
{
*this = *this * other;
return *this;
}
TSE::Color TSE::Color::operator/(const Color &other) const
{
return Vector4(r / other.r, g / other.g, b / other.b, a / other.a);
}
TSE::Color TSE::Color::operator/=(const Color &other)
{
*this = *this / other;
return *this;
}
TSE::Color TSE::Color::operator*(const float other) const
{
return Vector4(r * other, g * other, b * other, a * other);
}
TSE::Color TSE::Color::operator*=(const float other)
{
*this = *this * other;
return *this;
}
TSE::Color TSE::Color::operator/(const float other) const
{
return Vector4(r / other, g / other, b / other, a / other);
}
TSE::Color TSE::Color::operator/=(const float other)
{
*this = *this / other;
return *this;
}
bool TSE::Color::operator==(const Color &other) const
{
return r == other.r && g == other.g && b == other.b && a == other.a;
}
bool TSE::Color::operator!=(const Color &other) const
{
return !(*this == other);
}

113
TSE_Math/src/Color.hpp Normal file
View File

@@ -0,0 +1,113 @@
#pragma once
#include "Types.hpp"
namespace TSE
{
class Vector4;
/// @brief the color class for the engine
class Color
{
public:
#pragma region members
float r = 0, g = 0, b = 0, a = 1;
#pragma endregion members
#pragma region consts
static const Color red;
static const Color green;
static const Color blue;
static const Color white;
static const Color black;
static const Color gray;
static const Color darkGray;
static const Color yellow;
static const Color orange;
static const Color aqua;
#pragma endregion consts
#pragma region ctor
/// @brief empty constructor. Gives you a black color with a full alpha
Color();
/// @brief construct a color with float values ranging from 0 - 1
/// @param _r red component
/// @param _g green component
/// @param _b blue component
Color(float _r, float _g, float _b);
/// @brief construct a color with float values ranging from 0 - 1
/// @param _r red component
/// @param _g green component
/// @param _b blue component
/// @param _a alpha component
Color(float _r, float _g, float _b, float _a);
/// @brief construct a color with byte values ranging from 0 - 255
/// @param _r red component
/// @param _g green component
/// @param _b blue component
Color(byte _r, byte _g, byte _b);
/// @brief construct a color with byte values ranging from 0 - 255
/// @param _r red component
/// @param _g green component
/// @param _b blue component
/// @param _a alpha component
Color(byte _r, byte _g, byte _b, byte _a);
/// @brief copy constructor. It copies the values from the input color
/// @param other input color
Color(const Color& other);
/// @brief convert constructor. It converts the values from the input vector4, where x -> r, y -> g, z -> b, w -> a
/// @param other input vector4
Color(const Vector4& other);
#pragma endregion ctor
#pragma region methods
/// @brief checks if the individual color chanels have valid values
/// @return are the values valid
bool IsValid() const;
/// @brief gives you the red component as a byte
/// @return the red component
byte R() const;
/// @brief gives you the green component as a byte
/// @return the green component
byte G() const;
/// @brief gives you the blue component as a byte
/// @return the blue component
byte B() const;
/// @brief gives you the alpha component as a byte
/// @return the alpha component
byte A() const;
/// @brief gives you the color as a string representation. mostly for debugging
/// @return the color in a format like (r|g|b|a)
string ToString() const;
/// @brief creates a Vector4 with the same values as the color, where x -> r, y -> g, z -> b, w -> a
/// @return the color as a Vector4
Vector4 ToVector4() const;
#pragma region static
/// @brief Linearlie interpolates between two colors using t
/// @param a Color1
/// @param b Color2
/// @param t the value that defines how much it schould be Color1 (0) or Color2 (1)
/// @return the lerped color
static Color Lerp(const Color& a, const Color& b, const float t);
#pragma endregion static
#pragma region operators
Color operator+(const Color& other) const;
Color operator+=(const Color& other);
Color operator-(const Color& other) const;
Color operator-=(const Color& other);
Color operator*(const Color& other) const;
Color operator*=(const Color& other);
Color operator/(const Color& other) const;
Color operator/=(const Color& other);
Color operator*(const float other) const;
Color operator*=(const float other);
Color operator/(const float other) const;
Color operator/=(const float other);
bool operator==(const Color& other) const;
bool operator!=(const Color& other) const;
#pragma endregion operators
#pragma endregion methods
};
} // namespace TSE

27
TSE_Math/src/MathF.hpp Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
#include "Types.hpp"
namespace TSE
{
/// @brief definition of PI for the engine
constexpr float TSE_PI = 3.14159265358979323846f;
/// @brief the epsilon used as min float value for comparisons in the engine
constexpr float TSE_EPSILON = 1e-6f;
/// @brief a simple degrees to radiant conversion function
/// @param deg the degrees value
/// @return the radiant value
inline float Deg2Rad(const float& deg) {
return deg * (TSE_PI / 180.0f);
}
/// @brief a simple radiant to degrees conversion function
/// @param rad the radiant value
/// @return the degrees value
inline float Rad2Deg( const float& rad) {
return rad * (180.0f / TSE_PI);
}
} // namespace TSE

428
TSE_Math/src/Matrix4x4.cpp Normal file
View File

@@ -0,0 +1,428 @@
#include "Matrix4x4.hpp"
#include "MathF.hpp"
#include <cstring>
#include <cmath>
#ifdef __unix__
#include <immintrin.h>
#endif
#if defined(_MSC_VER)
#if defined(__AVX2__)
#define SIMD_HAS_FMA 1
#endif
#elif defined(__FMA__)
#define SIMD_HAS_FMA 1
#endif
#if defined(__SSE4_1__) || (defined(_MSC_VER) && defined(__AVX2__))
#define SIMD_HAS_DPPS 1
#endif
TSE::Matrix4x4::Matrix4x4()
{
std::memset(m, 0, sizeof(m));
}
TSE::Matrix4x4::Matrix4x4(float d)
{
std::memset(m, 0, sizeof(m));
for (int i = 0; i < 4; ++i)
m[i][i] = d;
}
TSE::Matrix4x4::Matrix4x4(const Matrix4x4 &other)
{
std::memcpy(m, other.m, sizeof(m));
}
bool TSE::Matrix4x4::IsIdentityMatrix() const
{
Matrix4x4 id = Identity();
return std::memcmp(m, id.m, sizeof(m)) == 0;
}
bool TSE::Matrix4x4::IsValid() const
{
bool valid = true;
for (byte x = 0; x < 4; x++)
{
for (byte y = 0; y < 4; y++)
{
valid &= !std::isnan(m[x][y]);
}
}
return valid;
}
void TSE::Matrix4x4::Invert()
{
const float det = Determinant();
if(std::abs(det) < TSE_EPSILON)
{
*this = Matrix4x4::Identity();
return;
}
Matrix4x4 conj = Conjucate();
float invDet = 1.0f / det;
*this = conj * invDet;
return;
}
float det3(float a00, float a01, float a02, float a10, float a11, float a12, float a20, float a21, float a22)
{
return a00 * (a11 * a22 - a12 * a21)
- a01 * (a10 * a22 - a12 * a20)
+ a02 * (a10 * a21 - a11 * a20);
}
float minor3(const TSE::Matrix4x4& M, int i, int j)
{
int ri[3], ci[3];
for (int r = 0, rr = 0; r < 4; ++r) if (r != i) ri[rr++] = r;
for (int c = 0, cc = 0; c < 4; ++c) if (c != j) ci[cc++] = c;
return det3(
M.m[ri[0]][ci[0]], M.m[ri[0]][ci[1]], M.m[ri[0]][ci[2]],
M.m[ri[1]][ci[0]], M.m[ri[1]][ci[1]], M.m[ri[1]][ci[2]],
M.m[ri[2]][ci[0]], M.m[ri[2]][ci[1]], M.m[ri[2]][ci[2]]
);
}
float cofactorSign(TSE::byte x, TSE::byte y)
{
return ((x + y) & 1) ? -1.0f : 1.0f;
}
TSE::Matrix4x4 TSE::Matrix4x4::Conjucate() const
{
Matrix4x4 conj;
for (byte x = 0; x < 4; x++)
{
for (byte y = 0; y < 4; y++)
{
conj.m[x][y] = cofactorSign(x,y) * minor3(*this, x, y);
}
}
return conj;
}
float TSE::Matrix4x4::Determinant() const
{
const float c00 = cofactorSign(0,0) * minor3(*this, 0, 0);
const float c01 = cofactorSign(0,1) * minor3(*this, 0, 1);
const float c02 = cofactorSign(0,2) * minor3(*this, 0, 2);
const float c03 = cofactorSign(0,3) * minor3(*this, 0, 3);
return m[0][0] * c00 + m[0][1] * c01 + m[0][2] * c02 + m[0][3] * c03;
}
bool TSE::Matrix4x4::IsAffine() const
{
return std::abs(m[3][0]) < TSE_EPSILON &&
std::abs(m[3][1]) < TSE_EPSILON &&
std::abs(m[3][2]) < TSE_EPSILON &&
std::abs(m[3][3] - 1.0f) < TSE_EPSILON;
}
void TSE::Matrix4x4::InvertAffine()
{
const float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];
const float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];
const float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];
const float tx = m[0][3], ty = m[1][3], tz = m[2][3];
const float det =
a00*(a11*a22 - a12*a21) -
a01*(a10*a22 - a12*a20) +
a02*(a10*a21 - a11*a20);
if (std::abs(det) < TSE_EPSILON) {
*this = Matrix4x4::Identity();
return;
}
const float invDet = 1.0f / det;
m[0][0] = (a11*a22 - a12*a21) * invDet;
m[0][1] = -(a01*a22 - a02*a21) * invDet;
m[0][2] = (a01*a12 - a02*a11) * invDet;
m[1][0] = -(a10*a22 - a12*a20) * invDet;
m[1][1] = (a00*a22 - a02*a20) * invDet;
m[1][2] = -(a00*a12 - a02*a10) * invDet;
m[2][0] = (a10*a21 - a11*a20) * invDet;
m[2][1] = -(a00*a21 - a01*a20) * invDet;
m[2][2] = (a00*a11 - a01*a10) * invDet;
m[0][3] = -(m[0][0]*tx + m[0][1]*ty + m[0][2]*tz);
m[1][3] = -(m[1][0]*tx + m[1][1]*ty + m[1][2]*tz);
m[2][3] = -(m[2][0]*tx + m[2][1]*ty + m[2][2]*tz);
m[3][0] = 0.0f;
m[3][1] = 0.0f;
m[3][2] = 0.0f;
m[3][3] = 1.0f;
}
const float *TSE::Matrix4x4::ToArrayRowMajor() const
{
return &m[0][0];
}
void TSE::Matrix4x4::ToArrayColumnMajor(float out[16]) const
{
for (byte row = 0; row < 4; ++row)
for (byte col = 0; col < 4; ++col)
out[col * 4 + row] = m[row][col];
}
TSE::Matrix4x4 TSE::Matrix4x4::Identity()
{
return Matrix4x4(1.0f);
}
TSE::Matrix4x4 TSE::Matrix4x4::Orthographic(float left, float right, float bottom, float top, float near, float far)
{
Matrix4x4 result = Matrix4x4(1.0f);
result.m[0][0] = 2.0f / (right - left);
result.m[1][1] = 2.0f / (top - bottom);
result.m[2][2] = -2.0f / (far - near);
result.m[0][3] = (left + right) / (left - right);
result.m[1][3] = (bottom + top) / (bottom - top);
result.m[2][3] = -(near + far) / (near - far);
return result;
}
TSE::Matrix4x4 TSE::Matrix4x4::Perspective(float fov, float aspectRatio, float near, float far)
{
Matrix4x4 result = Matrix4x4(1.0f);
float q = 1 / tan(Deg2Rad(0.5f * fov));
float a = q / aspectRatio;
float b = (near + far) / (near - far);
float c = (2 * near * far) / (near - far);
result.m[0][0] = a;
result.m[1][1] = q;
result.m[2][2] = b;
result.m[3][2] = -1;
result.m[2][3] = c;
return result;
}
TSE::Matrix4x4 TSE::Matrix4x4::ToTranslationMatrix(const Vector3 &pos)
{
Matrix4x4 result = Identity();
result.m[0][3] = pos.x;
result.m[1][3] = pos.y;
result.m[2][3] = pos.z;
return result;
}
TSE::Matrix4x4 TSE::Matrix4x4::ToRotationMatrix(const Quaternion &rot)
{
Matrix4x4 result = Identity();
float xx = rot.x * rot.x;
float yy = rot.y * rot.y;
float zz = rot.z * rot.z;
float xy = rot.x * rot.y;
float xz = rot.x * rot.z;
float yz = rot.y * rot.z;
float wx = rot.w * rot.x;
float wy = rot.w * rot.y;
float wz = rot.w * rot.z;
result.m[0][0] = 1.0f - 2.0f * (yy + zz);
result.m[0][1] = 2.0f * (xy - wz);
result.m[0][2] = 2.0f * (xz + wy);
result.m[1][0] = 2.0f * (xy + wz);
result.m[1][1] = 1.0f - 2.0f * (xx + zz);
result.m[1][2] = 2.0f * (yz - wx);
result.m[2][0] = 2.0f * (xz - wy);
result.m[2][1] = 2.0f * (yz + wx);
result.m[2][2] = 1.0f - 2.0f * (xx + yy);
return result;
}
TSE::Matrix4x4 TSE::Matrix4x4::ToRotationMatrixFromZAxisOnly(float angle)
{
Matrix4x4 result = Identity();
float c = std::cos(angle);
float s = std::sin(angle);
result.m[0][0] = c;
result.m[0][1] = -s;
result.m[1][0] = s;
result.m[1][1] = c;
return result;
}
TSE::Matrix4x4 TSE::Matrix4x4::ToScaleMatrix(const Vector3 &scale)
{
Matrix4x4 result = Identity();
result.m[0][0] = scale.x;
result.m[1][1] = scale.y;
result.m[2][2] = scale.z;
return result;
}
TSE::Matrix4x4 TSE::Matrix4x4::Invert(const Matrix4x4 &mat)
{
Matrix4x4 invers (mat);
if(invers.IsAffine())
{
invers.InvertAffine();
}
else
{
invers.Invert();
}
return invers;
}
TSE::Matrix4x4 mulsse(const TSE::Matrix4x4& A, const TSE::Matrix4x4& B)
{
using namespace TSE;
Matrix4x4 C;
const __m128 b0 = _mm_loadu_ps(&B.m[0][0]);
const __m128 b1 = _mm_loadu_ps(&B.m[1][0]);
const __m128 b2 = _mm_loadu_ps(&B.m[2][0]);
const __m128 b3 = _mm_loadu_ps(&B.m[3][0]);
for (int r = 0; r < 4; ++r) {
__m128 row;
#if SIMD_HAS_FMA
row = _mm_mul_ps(_mm_set1_ps(A.m[r][0]), b0);
row = _mm_fmadd_ps(_mm_set1_ps(A.m[r][1]), b1, row);
row = _mm_fmadd_ps(_mm_set1_ps(A.m[r][2]), b2, row);
row = _mm_fmadd_ps(_mm_set1_ps(A.m[r][3]), b3, row);
#else
row = _mm_mul_ps(_mm_set1_ps(A.m[r][0]), b0);
row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(A.m[r][1]), b1));
row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(A.m[r][2]), b2));
row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(A.m[r][3]), b3));
#endif
_mm_storeu_ps(&C.m[r][0], row);
}
return C;
}
float hsum_ps(__m128 v) {
__m128 shuf = _mm_movehdup_ps(v);
__m128 sums = _mm_add_ps(v, shuf);
shuf = _mm_movehl_ps(shuf, sums);
sums = _mm_add_ss(sums, shuf);
return _mm_cvtss_f32(sums);
}
TSE::Matrix4x4 TSE::Matrix4x4::operator*(const Matrix4x4 &other) const
{
return mulsse(*this, other);
}
TSE::Matrix4x4 TSE::Matrix4x4::operator*=(const Matrix4x4 &other)
{
*this = *this * other;
return *this;
}
TSE::Matrix4x4 TSE::Matrix4x4::operator*(float scalar) const
{
Matrix4x4 R;
#if defined(__SSE__)
const __m128 s = _mm_set1_ps(scalar);
for (int r = 0; r < 4; ++r) {
__m128 row = _mm_loadu_ps(&m[r][0]);
row = _mm_mul_ps(row, s);
_mm_storeu_ps(&R.m[r][0], row);
}
#else
for (int r = 0; r < 4; ++r)
for (int c = 0; c < 4; ++c)
R.m[r][c] = m[r][c] * scalar;
#endif
return R;
}
TSE::Matrix4x4 TSE::Matrix4x4::operator*=(float scalar)
{
*this = *this * scalar;
return *this;
}
TSE::Vector3 TSE::Matrix4x4::operator*(const Vector3 &v) const
{
#if defined(__SSE__)
const __m128 vec = _mm_set_ps(1.0f, v.z, v.y, v.x);
__m128 r0 = _mm_loadu_ps(&m[0][0]);
__m128 r1 = _mm_loadu_ps(&m[1][0]);
__m128 r2 = _mm_loadu_ps(&m[2][0]);
#if SIMD_HAS_DPPS
float x = _mm_cvtss_f32(_mm_dp_ps(r0, vec, 0xF1));
float y = _mm_cvtss_f32(_mm_dp_ps(r1, vec, 0xF1));
float z = _mm_cvtss_f32(_mm_dp_ps(r2, vec, 0xF1));
#else
float x = hsum_ps(_mm_mul_ps(r0, vec));
float y = hsum_ps(_mm_mul_ps(r1, vec));
float z = hsum_ps(_mm_mul_ps(r2, vec));
#endif
return Vector3{ x, y, z };
#else
return Vector3{
m[0][0]*v.x + m[0][1]*v.y + m[0][2]*v.z + m[0][3],
m[1][0]*v.x + m[1][1]*v.y + m[1][2]*v.z + m[1][3],
m[2][0]*v.x + m[2][1]*v.y + m[2][2]*v.z + m[2][3]
};
#endif
}
TSE::Vector4 TSE::Matrix4x4::operator*(const Vector4 &v) const
{
#if defined(__SSE__)
const __m128 vec = _mm_set_ps(v.w, v.z, v.y, v.x);
__m128 r0 = _mm_loadu_ps(&m[0][0]);
__m128 r1 = _mm_loadu_ps(&m[1][0]);
__m128 r2 = _mm_loadu_ps(&m[2][0]);
__m128 r3 = _mm_loadu_ps(&m[3][0]);
#if SIMD_HAS_DPPS
float x = _mm_cvtss_f32(_mm_dp_ps(r0, vec, 0xF1));
float y = _mm_cvtss_f32(_mm_dp_ps(r1, vec, 0xF1));
float z = _mm_cvtss_f32(_mm_dp_ps(r2, vec, 0xF1));
float w = _mm_cvtss_f32(_mm_dp_ps(r3, vec, 0xF1));
#else
float x = hsum_ps(_mm_mul_ps(r0, vec));
float y = hsum_ps(_mm_mul_ps(r1, vec));
float z = hsum_ps(_mm_mul_ps(r2, vec));
float w = hsum_ps(_mm_mul_ps(r3, vec));
#endif
return Vector4{ x, y, z, w };
#else
return Vector4{
m[0][0]*v.x + m[0][1]*v.y + m[0][2]*v.z + m[0][3]*v.w,
m[1][0]*v.x + m[1][1]*v.y + m[1][2]*v.z + m[1][3]*v.w,
m[2][0]*v.x + m[2][1]*v.y + m[2][2]*v.z + m[2][3]*v.w,
m[3][0]*v.x + m[3][1]*v.y + m[3][2]*v.z + m[3][3]*v.w
};
#endif
}

View File

@@ -0,0 +1,96 @@
#pragma once
#include "Vector3.hpp"
#include "Vector4.hpp"
#include "Quaternion.hpp"
namespace TSE
{
class Matrix4x4
{
public:
float m[4][4]; // Row Major Layout
/// @brief default Constructor. all values are 0
Matrix4x4();
/// @brief sets the diagonal to a custom value
/// @param d the value for the diagonal
Matrix4x4(float d);
/// @brief copy constructor
/// @param other the matrix to be copied
Matrix4x4(const Matrix4x4& other);
/// @brief checks if the matrix is an identity matrix aka the diagonal is set to 1, and everithing else is 0
/// @return is identity matrix
bool IsIdentityMatrix() const;
/// @brief chacks if the matrix ist valid aka the values are not NaN
/// @return is valid
bool IsValid() const;
/// @brief inverts the current matrix with the generic invertion method
void Invert();
/// @brief gets the conjuget of the current matrix
/// @return the conjuget
Matrix4x4 Conjucate() const;
/// @brief Gets the determinant of the matrix
/// @return the determinant
float Determinant() const;
/// @brief checks if the current matrix is an affine matrix aka a transformation matrix only translation, rotation, and scale set.
/// @return is affine
bool IsAffine() const;
/// @brief inverts an affine matrix. simply a faster inversion method for affine matrecies.
void InvertAffine();
/// @brief gets the pointer to the contents of this matrix.
/// @return the contens as row major
const float* ToArrayRowMajor() const;
/// @brief fills an array with the matrix contens as column major
/// @param out the array to be filled
void ToArrayColumnMajor(float out[16]) const;
/// @brief generates an identity matrix
/// @return identity matrix
static Matrix4x4 Identity();
/// @brief generates an orthographics projection matrix.
/// @param left the left clipping plane
/// @param right the right clipping plane
/// @param bottom the bottom clipping plane
/// @param top the top clipping plane
/// @param near the near clipping plane
/// @param far the far clipping plane
/// @return an orthoraphic projection matrix
static Matrix4x4 Orthographic(float left, float right, float bottom, float top, float near, float far);
/// @brief generates a perspectiv projection marix
/// @param fov the field of view in deg
/// @param aspectRatio the aspect ratio of the render target
/// @param near the near clipping plane
/// @param far the far clipping plane
/// @return a perspective projection matrix
static Matrix4x4 Perspective(float fov, float aspectRatio, float near, float far);
/// @brief generaties a translation matrix from a position
/// @param pos the position to use
/// @return the generated matrix
static Matrix4x4 ToTranslationMatrix(const Vector3& pos);
/// @brief generates a rotation matrix from a quaternion
/// @param rot the quaternion to use
/// @return the generated matrix
static Matrix4x4 ToRotationMatrix(const Quaternion& rot);
/// @brief generates a rotation matrix from an angle around the z axis (2D)
/// @param angle the angle to rotate about
/// @return the generated matrix
static Matrix4x4 ToRotationMatrixFromZAxisOnly(float angle);
/// @brief generates a scale matrix from a scale vector
/// @param scale the scale to use
/// @return the generated matrix
static Matrix4x4 ToScaleMatrix(const Vector3& scale);
/// @brief inverts a the given matrix, when possible it trys to use less calculations
/// @param mat the matrix to invert
/// @return the inverted matrix
static Matrix4x4 Invert(const Matrix4x4& mat);
Matrix4x4 operator*(const Matrix4x4& other) const;
Matrix4x4 operator*=(const Matrix4x4& other);
Matrix4x4 operator*(float scalar) const;
Matrix4x4 operator*=(float scalar);
Vector3 operator*(const Vector3& v) const;
Vector4 operator*(const Vector4& v) const;
};
} // namespace TSE

78
TSE_Math/src/Mesh.cpp Normal file
View File

@@ -0,0 +1,78 @@
#include "Mesh.hpp"
#include "MathF.hpp"
#include <cmath>
TSE::Mesh::Mesh()
{
name = "";
}
TSE::Mesh::Mesh(string _name, const std::vector<Vector3> &_vertecies, const std::vector<ushort> &_indecies, const std::vector<Vector2> &_uvs)
{
name = _name;
vertecies = std::move(_vertecies);
indecies = std::move(_indecies);
uvs = std::move(_uvs);
}
size_t TSE::Mesh::IndeciesCount() const
{
return indecies.size();
}
size_t TSE::Mesh::VerteciesCount() const
{
return vertecies.size();
}
TSE::Mesh TSE::Mesh::GetCircleMesh(ushort segments)
{
std::vector<Vector3> verts;
std::vector<ushort> indices;
std::vector<Vector2> uvs;
verts.emplace_back(0.0f, 0.0f, 0.0f);
uvs.emplace_back(0.5f, 0.5f);
float angleStep = 2.0f * TSE_PI / segments;
for (int i = 0; i <= segments; ++i) {
float angle = i * angleStep;
float x = std::cos(angle) * 0.5f;
float y = std::sin(angle) * 0.5f;
verts.emplace_back(x, y, 0);
uvs.emplace_back(x + 0.5f, y + 0.5f);
if (i > 0) {
indices.push_back(0);
indices.push_back(i);
indices.push_back(i + 1);
}
}
return Mesh("Circle", verts, indices, uvs);
}
TSE::Mesh TSE::Mesh::GetQuadMesh()
{
std::vector<Vector3> verts = {
Vector3(-0.5f, -0.5f, 0),
Vector3( 0.5f, -0.5f, 0),
Vector3( 0.5f, 0.5f, 0),
Vector3(-0.5f, 0.5f, 0)
};
std::vector<Vector2> uvs = {
Vector2(0.0f, 0.0f),
Vector2(1.0f, 0.0f),
Vector2(1.0f, 1.0f),
Vector2(0.0f, 1.0f)
};
std::vector<unsigned short> indices = {
0, 1, 2,
2, 3, 0
};
return Mesh("Quad", verts, indices, uvs);
}

45
TSE_Math/src/Mesh.hpp Normal file
View File

@@ -0,0 +1,45 @@
#pragma once
#include <vector>
#include "Types.hpp"
#include "Vector3.hpp"
#include "Vector2.hpp"
namespace TSE
{
class Mesh
{
public:
string name;
std::vector<Vector3> vertecies;
std::vector<ushort> indecies;
std::vector<Vector2> uvs;
/// @brief gives you an empty mesh with the name set to an empty string
Mesh();
/// @brief constructs a mesh with custom parameters
/// @param _name name of the mesh
/// @param _vertecies the vertecies
/// @param _indecies the indecies
/// @param _uvs the uvs
Mesh(string _name,
const std::vector<Vector3>& _vertecies,
const std::vector<ushort>& _indecies,
const std::vector<Vector2>& _uvs);
/// @brief gives you the count of indecies in this mesh
/// @return the indecie count
size_t IndeciesCount() const;
/// @brief gives you the count of vertecies in this mesh
/// @return the vertex count
size_t VerteciesCount() const;
/// @brief generates a circle mesh with the defined amounts of segments
/// @param segments amount of "pizza slices" to make the mesh out of. default 16
/// @return the resulting mesh
static Mesh GetCircleMesh(ushort segments = 16);
/// @brief gives you a basic unit quad with (-0.5, -0.5) -> (0.5, 0.5)
/// @return the resulting mesh
static Mesh GetQuadMesh();
};
} // namespace TSE

137
TSE_Math/src/Quaternion.cpp Normal file
View File

@@ -0,0 +1,137 @@
#include "Quaternion.hpp"
#include "Vector4.hpp"
#include "Vector3.hpp"
#include "MathF.hpp"
#include <cmath>
TSE::Quaternion::Quaternion() { }
TSE::Quaternion::Quaternion(float _x, float _y, float _z, float _w)
{
x = _x;
y = _y;
z = _z;
w = _w;
}
TSE::Quaternion::Quaternion(const Quaternion &other)
{
x = other.x;
y = other.y;
z = other.z;
w = other.w;
}
TSE::Quaternion::Quaternion(const Vector4 &other)
{
x = other.x;
y = other.y;
z = other.z;
w = other.w;
}
TSE::Vector3 TSE::Quaternion::ToEulerAngles() const
{
Vector3 euler;
float sinr_cosp = 2.0f * (w * x + y * z);
float cosr_cosp = 1.0f - 2.0f * (x * x + y * y);
euler.x = Rad2Deg(std::atan2(sinr_cosp, cosr_cosp));
float sinp = 2.0f * (w * y - z * x);
if (std::abs(sinp) >= 1)
euler.y = Rad2Deg(std::copysign(TSE_PI / 2.0f, sinp));
else
euler.y = Rad2Deg(std::asin(sinp));
float siny_cosp = 2.0f * (w * z + x * y);
float cosy_cosp = 1.0f - 2.0f * (y * y + z * z);
euler.z = Rad2Deg(std::atan2(siny_cosp, cosy_cosp));
return euler;
}
TSE::Vector3 TSE::Quaternion::Rotate(const Vector3 &v) const
{
Vector3 qv(x, y, z);
Vector3 t = Vector3::Cross(qv, v) * 2.0f;
return v + t * w + Vector3::Cross(qv, t);
}
void TSE::Quaternion::Normalize()
{
float lensq = w*w + x*x + y*y + z*z;
if(lensq <= TSE_EPSILON) return;
const float inv = 1.0f / std::sqrt(lensq);
x *= inv; y *= inv; z *= inv; w *= inv;
}
TSE::Quaternion TSE::Quaternion::FromAngleAxis(float angleRad, const Vector3 &axis)
{
Vector3 a = Vector3::Normalize(axis);
float half = angleRad * 0.5f;
float s = sin(half);
Quaternion q;
q.w = std::cos(half);
q.x = a.x * s;
q.y = a.y * s;
q.z = a.z * s;
q.Normalize();
return q;
}
TSE::Quaternion TSE::Quaternion::FromEulerAngles(const Vector3 &euler)
{
float roll = Deg2Rad(euler.x);
float pitch = Deg2Rad(euler.y);
float yaw = Deg2Rad(euler.z);
float cr = std::cos(roll * 0.5f);
float sr = std::sin(roll * 0.5f);
float cp = std::cos(pitch * 0.5f);
float sp = std::sin(pitch * 0.5f);
float cy = std::cos(yaw * 0.5f);
float sy = std::sin(yaw * 0.5f);
return Quaternion(
sr * cp * cy - cr * sp * sy,
cr * sp * cy + sr * cp * sy,
cr * cp * sy - sr * sp * cy,
cr * cp * cy + sr * sp * sy
);
}
TSE::Vector3 TSE::Quaternion::ToEulerAngles(const Quaternion &q)
{
return q.ToEulerAngles();
}
TSE::Quaternion TSE::Quaternion::operator*(const Quaternion &other) const
{
Quaternion b = *this;
Quaternion r;
r.w = b.w*other.w - b.x*other.x - b.y*other.y - b.z*other.z;
r.x = b.w*other.x + b.x*other.w + b.y*other.z - b.z*other.y;
r.y = b.w*other.y - b.x*other.z + b.y*other.w + b.z*other.x;
r.z = b.w*other.z + b.x*other.y - b.y*other.x + b.z*other.w;
return r;
}
TSE::Quaternion TSE::Quaternion::operator*=(const Quaternion &other)
{
*this = *this * other;
return *this;
}
bool TSE::Quaternion::operator==(const Quaternion &other) const
{
return x == other.x && y == other.y && z == other.z && w == other.w;
}
bool TSE::Quaternion::operator!=(const Quaternion &other) const
{
return !(*this == other);
}

View File

@@ -0,0 +1,69 @@
#pragma once
#include "Types.hpp"
namespace TSE
{
class Vector3;
class Vector4;
class Quaternion
{
public:
#pragma region members
float x = 0, y = 0, z = 0, w = 1;
#pragma endregion members
#pragma region ctor
/// @brief constructs a default Quaternion
Quaternion();
/// @brief constructs a Quaternion with given values
/// @param _x the x component
/// @param _y the y component
/// @param _z the z component
/// @param _w the w component
Quaternion(float _x, float _y, float _z, float _w);
/// @brief copy constructor
/// @param other the quaternion to be copied
Quaternion(const Quaternion& other);
/// @brief conversion constructor
/// @param other the vector4 to be converted
Quaternion(const Vector4& other);
#pragma endregion ctor
#pragma region methods
/// @brief converts the Quaternion to a Vector3 with yaw, pitch, and roll
/// @return the euler angles
Vector3 ToEulerAngles() const;
/// @brief rotates a point with the quaternion
/// @param v the point to rotate
/// @return the rotated point
Vector3 Rotate(const Vector3& v) const;
/// @brief normalizes the current quaternion
void Normalize();
#pragma region static
/// @brief gives you a quaternion based on an angle axis input
/// @param angleRad the angle in radiants
/// @param axis the axis to ratate around
/// @return the resulting quaternion
static Quaternion FromAngleAxis(float angleRad, const Vector3& axis);
/// @brief gives you a quaternion based on euler angles
/// @param euler the euler angles
/// @return the resulting quaternion
static Quaternion FromEulerAngles(const Vector3& euler);
/// @brief converts a Quaternion to a Vector3 with yaw, pitch, and roll
/// @param q the quaternion to convert
/// @return the euler angles
static Vector3 ToEulerAngles(const Quaternion& q);
#pragma endregion static
#pragma region operators
Quaternion operator*(const Quaternion& other) const;
Quaternion operator*=(const Quaternion& other);
bool operator==(const Quaternion& other) const;
bool operator!=(const Quaternion& other) const;
#pragma endregion operators
#pragma endregion methods
};
} // namespace TSE

56
TSE_Math/src/Rect.cpp Normal file
View File

@@ -0,0 +1,56 @@
#include "Rect.hpp"
TSE::Rect::Rect()
{
p1 = {0,0};
p2 = {0,0};
}
TSE::Rect::Rect(float x1, float y1, float x2, float y2)
{
p1 = {x1, y1};
p2 = {x2, y2};
}
TSE::Rect::Rect(const Vector2 &_p1, const Vector2 &_p2)
{
p1 = Vector2(_p1);
p2 = Vector2(_p2);
}
TSE::Rect::Rect(const Vector4 &v)
{
p1 = {v.x, v.y};
p1 = {v.z, v.w};
}
TSE::Rect::Rect(const Rect &r)
{
p1 = Vector2(r.p1);
p2 = Vector2(r.p2);
}
float TSE::Rect::width() const
{
return std::abs(p2.x - p1.x);
}
float TSE::Rect::height() const
{
return std::abs(p2.y - p1.y);
}
float TSE::Rect::area() const
{
return width() * height();
}
bool TSE::Rect::operator==(const Rect &other) const
{
return p1 == other.p1 && p2 == other.p2;
}
bool TSE::Rect::operator!=(const Rect &other) const
{
return !(*this == other);
}

48
TSE_Math/src/Rect.hpp Normal file
View File

@@ -0,0 +1,48 @@
#pragma once
#include "Vector2.hpp"
#include "Vector4.hpp"
#include "Types.hpp"
#include <vector>
namespace TSE
{
class Rect
{
public:
Vector2 p1, p2;
/// @brief default constructer wicht all points starting at (0,0)
Rect();
/// @brief constructor with floats for custom values
/// @param x1 x component of min
/// @param y1 y component of min
/// @param x2 x component of max
/// @param y2 y component of max
Rect(float x1, float y1, float x2, float y2);
/// @brief constructer with Vector2 for custom values
/// @param _p1 min
/// @param _p2 max
Rect(const Vector2& _p1, const Vector2& _p2);
/// @brief constructor wich Vector4 for custom Values
/// @param v min -> (x,y) max -> (z,w)
Rect(const Vector4& v);
/// @brief copy constructor
/// @param r the rect to me copied
Rect(const Rect& r);
/// @brief gives you the current width of the rect
/// @return the width in local rect space
float width() const;
/// @brief gives you the current height of the rect
/// @return the height in local rect space
float height() const;
/// @brief gives you the area of the rect based on the height() and width() functions
/// @return the area in local rect space
float area() const;
bool operator==(const Rect& other) const;
bool operator!=(const Rect& other) const;
};
} // namespace TSE

View File

@@ -0,0 +1,24 @@
#include "TransformationStack.hpp"
TSE::TransformationStack::TransformationStack()
{
stack.push_back(Matrix4x4::Identity());
}
const TSE::Matrix4x4 &TSE::TransformationStack::Top() const
{
return stack.back();
}
void TSE::TransformationStack::Push(const Matrix4x4 &matrix)
{
stack.push_back(Top() * matrix);
}
void TSE::TransformationStack::Pop()
{
if (stack.size() > 1)
{
stack.pop_back();
}
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include <vector>
#include "Matrix4x4.hpp"
namespace TSE
{
class TransformationStack
{
private:
std::vector<Matrix4x4> stack;
public:
/// @brief generates an empty transformation stack, based on an identity matrix
TransformationStack();
/// @brief gets the current value of the stack
/// @return the current value
const Matrix4x4& Top() const;
/// @brief pusches a new value on to the stack
/// @param matrix the value to be pusched
void Push(const Matrix4x4& matrix);
/// @brief pops the last value off the stack
void Pop();
};
} // namespace TSE

217
TSE_Math/src/Vector2.cpp Normal file
View File

@@ -0,0 +1,217 @@
#include "Vector2.hpp"
#include "Vector3.hpp"
#include "Vector4.hpp"
#include "MathF.hpp"
#include <cmath>
const TSE::Vector2 TSE::Vector2::left = TSE::Vector2(-1,0);
const TSE::Vector2 TSE::Vector2::right = TSE::Vector2(1,0);
const TSE::Vector2 TSE::Vector2::up = TSE::Vector2(0,1);
const TSE::Vector2 TSE::Vector2::down = TSE::Vector2(0,-1);
const TSE::Vector2 TSE::Vector2::one = TSE::Vector2(1,1);
const TSE::Vector2 TSE::Vector2::zero = TSE::Vector2(0,0);
TSE::Vector2::Vector2() { }
TSE::Vector2::Vector2(float _x, float _y)
{
x = _x;
y = _y;
}
TSE::Vector2::Vector2(const Vector2 &other)
{
x = other.x;
y = other.y;
}
TSE::Vector2::Vector2(const Vector3 &other)
{
x = other.x;
y = other.y;
}
TSE::Vector2::Vector2(const Vector4 &other)
{
x = other.x;
y = other.y;
}
float TSE::Vector2::Length() const
{
return std::sqrt(x*x + y*y);
}
float TSE::Vector2::LengthSqr() const
{
return x*x + y*y;
}
bool TSE::Vector2::IsValid() const
{
return !std::isnan(x) && !std::isnan(y);
}
void TSE::Vector2::Normalize()
{
float lensq = LengthSqr();
if(lensq <= TSE_EPSILON) return;
const float inv = 1.0f / std::sqrt(lensq);
x *= inv; y *= inv;
}
void TSE::Vector2::NormalizeSafe(const Vector2 &fallback)
{
float lensq = LengthSqr();
if(lensq <= TSE_EPSILON)
{
*this = fallback;
return;
}
const float inv = 1.0f / std::sqrt(lensq);
x *= inv; y *= inv;
if(!IsValid())
{
*this = fallback;
}
}
TSE::string TSE::Vector2::ToString() const
{
return "(" + std::to_string(x) + "|" + std::to_string(y) + ")";
}
TSE::Vector3 TSE::Vector2::ToVector3() const
{
return Vector3(x,y,0);
}
TSE::Vector4 TSE::Vector2::ToVector4() const
{
return Vector4(x,y,0,0);
}
float TSE::Vector2::Distance(const Vector2 &a, const Vector2 &b)
{
return (a - b).Length();
}
float TSE::Vector2::DistanceSqr(const Vector2 &a, const Vector2 &b)
{
return (a - b).LengthSqr();
}
TSE::Vector2 TSE::Vector2::Normalize(const Vector2 &v)
{
Vector2 result = v;
result.Normalize();
return result;
}
TSE::Vector2 TSE::Vector2::NormalizeSafe(const Vector2 &v, const Vector2 &fallback)
{
Vector2 result = v;
result.NormalizeSafe(fallback);
return result;
}
TSE::Vector2 TSE::Vector2::Lerp(const Vector2 &a, const Vector2 &b, float t)
{
return a + (b - a) * t;
}
TSE::Vector2 TSE::Vector2::Berp(const Vector2 &a, const Vector2 &b, const Vector2 &c, float t)
{
return Lerp(Lerp(a, b, t), Lerp(b, c, t), t);
}
TSE::Vector2 TSE::Vector2::Midpoint(const Vector2 &a, const Vector2 &b)
{
return (a + b) / 2.0f;
}
float TSE::Vector2::Dot(const Vector2 &a, const Vector2 &b)
{
return a.x * b.x + a.y * b.y;
}
float TSE::Vector2::Cross(const Vector2 &a, const Vector2 &b)
{
return a.x * b.y - a.y * b.x;
}
TSE::Vector2 TSE::Vector2::operator+(const Vector2 &other) const
{
return Vector2(x + other.x, y + other.y);
}
TSE::Vector2 TSE::Vector2::operator+=(const Vector2 &other)
{
*this = *this + other;
return *this;
}
TSE::Vector2 TSE::Vector2::operator-(const Vector2 &other) const
{
return Vector2(x - other.x, y - other.y);
}
TSE::Vector2 TSE::Vector2::operator-=(const Vector2 &other)
{
*this = *this - other;
return *this;
}
TSE::Vector2 TSE::Vector2::operator*(const Vector2 &other) const
{
return Vector2(x * other.x, y * other.y);
}
TSE::Vector2 TSE::Vector2::operator*=(const Vector2 &other)
{
*this = *this * other;
return *this;
}
TSE::Vector2 TSE::Vector2::operator/(const Vector2 &other) const
{
return Vector2(x / other.x, y / other.y);
}
TSE::Vector2 TSE::Vector2::operator/=(const Vector2 &other)
{
*this = *this / other;
return *this;
}
TSE::Vector2 TSE::Vector2::operator*(const float other) const
{
return Vector2(x * other, y * other);
}
TSE::Vector2 TSE::Vector2::operator*=(const float other)
{
*this = *this * other;
return *this;
}
TSE::Vector2 TSE::Vector2::operator/(const float other) const
{
return Vector2(x / other, y / other);
}
TSE::Vector2 TSE::Vector2::operator/=(const float other)
{
*this = *this / other;
return *this;
}
bool TSE::Vector2::operator==(const Vector2 &other) const
{
return x == other.x && y == other.y;
}
bool TSE::Vector2::operator!=(const Vector2 &other) const
{
return !(*this == other);
}

137
TSE_Math/src/Vector2.hpp Normal file
View File

@@ -0,0 +1,137 @@
#pragma once
#include "Types.hpp"
namespace TSE
{
class Vector3;
class Vector4;
class Vector2
{
public:
#pragma region members
float x = 0, y = 0;
#pragma endregion members
#pragma region consts
static const Vector2 left;
static const Vector2 right;
static const Vector2 up;
static const Vector2 down;
static const Vector2 one;
static const Vector2 zero;
#pragma endregion
#pragma region ctor
/// @brief enpty constructor defined as (0,0)
Vector2();
/// @brief constructs a vector2 with custom values
/// @param _x the x component
/// @param _y the y component
Vector2(float _x, float _y);
/// @brief copy constructor
/// @param other the vector2 to be copied from
Vector2(const Vector2& other);
/// @brief converter constructor. it converts a Vector3 to a Vector2 without encointing for the z component
/// @param other the Vector3 to convert
Vector2(const Vector3& other);
/// @brief converter constructor. it converts a Vector4 to a Vector2 without encointing for the z, and w component
/// @param other the Vector4 to convert
Vector2(const Vector4& other);
#pragma endregion ctor
#pragma region methods
/// @brief the length of the vector
/// @return the length
float Length() const;
/// @brief the length² of the vector
/// @return the length²
float LengthSqr() const;
/// @brief checks if the individual components have valid values aka are not nan
/// @return are the values valid
bool IsValid() const;
/// @brief normalizes the Vector2 to have a length of 1
void Normalize();
/// @brief normalizes the Vector2 to have a length of 1. If the current length of the vector is smaller then epsilon, it gives you the fallback value.
/// @param fallback the value to set the vector to if the current length is smaller then epsilon
void NormalizeSafe(const Vector2& fallback);
/// @brief gives you the vector2 as a string representation. mostly for debugging
/// @return the vector2 in a format like (x|y)
string ToString() const;
/// @brief creates a Vector3 with the same values as the Vector2, the y component gets the value 0
/// @return the Vector2 as a Vector3
Vector3 ToVector3() const;
/// @brief creates a Vector4 with the same values as the Vector2, the y and w components get the value 0
/// @return the Vector2 as a Vector4
Vector4 ToVector4() const;
#pragma region static
/// @brief gives you the distance between two vectors.
/// @param a point 1
/// @param b point 2
/// @return the distance between point 1 and point 2
static float Distance(const Vector2& a, const Vector2& b);
/// @brief gives you the distance² between two vectors.
/// @param a point 1
/// @param b point 2
/// @return the distance² between point 1 and point 2
static float DistanceSqr(const Vector2& a, const Vector2& b);
/// @brief normalizes a copy of the Vector2 to have a length of 1
/// @param v the vector to be normaliezed
/// @return a normalies copy of the vector
static Vector2 Normalize(const Vector2& v);
/// @brief normalizes a copy of the Vector2 to have a length of 1. If the current length of the vector is smaller then epsilon, it gives you the fallback value.
/// @param fallback the value to set the vector to if the current length is smaller then epsilon
/// @param v the vector to be normaliezed
/// @return a normalies copy of the vector
static Vector2 NormalizeSafe(const Vector2& v, const Vector2& fallback);
/// @brief linearly interpolates between two points using t
/// @param a point 1
/// @param b point 2
/// @param t the amoint to interpolate by
/// @return the interpolated point
static Vector2 Lerp(const Vector2& a, const Vector2& b, float t);
/// @brief bezier interpolation using three points using t
/// @param a point 1
/// @param b controll point
/// @param c point 2
/// @param t the amoint to interpolate by
/// @return the interpolated point
static Vector2 Berp(const Vector2& a, const Vector2& b, const Vector2& c, float t);
/// @brief gives you the midpoint between two points
/// @param a point 1
/// @param b point 2
/// @return the midpoint
static Vector2 Midpoint(const Vector2& a, const Vector2& b);
/// @brief gives you the dot product between to vectors
/// @param a vector 1
/// @param b vector 2
/// @return the dot product
static float Dot(const Vector2& a, const Vector2& b);
/// @brief it gives you the "2D Cross Product" (there is no real 2D Cross product, but this function is still usefull sometimes)
/// @param a vector 1
/// @param b vector 2
/// @return 2D cross product
static float Cross(const Vector2& a, const Vector2& b);
#pragma endregion static
#pragma region operators
Vector2 operator+(const Vector2& other) const;
Vector2 operator+=(const Vector2& other);
Vector2 operator-(const Vector2& other) const;
Vector2 operator-=(const Vector2& other);
Vector2 operator*(const Vector2& other) const;
Vector2 operator*=(const Vector2& other);
Vector2 operator/(const Vector2& other) const;
Vector2 operator/=(const Vector2& other);
Vector2 operator*(const float other) const;
Vector2 operator*=(const float other);
Vector2 operator/(const float other) const;
Vector2 operator/=(const float other);
bool operator==(const Vector2& other) const;
bool operator!=(const Vector2& other) const;
#pragma endregion operators
#pragma endregion methods
};
} // namespace TSE

233
TSE_Math/src/Vector3.cpp Normal file
View File

@@ -0,0 +1,233 @@
#include "Vector3.hpp"
#include "Vector2.hpp"
#include "Vector4.hpp"
#include "MathF.hpp"
#include <cmath>
const TSE::Vector3 TSE::Vector3::left = TSE::Vector3(-1,0,0);
const TSE::Vector3 TSE::Vector3::right = TSE::Vector3(1,0,0);
const TSE::Vector3 TSE::Vector3::up = TSE::Vector3(0,1,0);
const TSE::Vector3 TSE::Vector3::down = TSE::Vector3(0,-1,0);
const TSE::Vector3 TSE::Vector3::forward = TSE::Vector3(0,0,1);
const TSE::Vector3 TSE::Vector3::back = TSE::Vector3(0,0,-1);
const TSE::Vector3 TSE::Vector3::one = TSE::Vector3(1,1,1);
const TSE::Vector3 TSE::Vector3::zero = TSE::Vector3(0,0,0);
TSE::Vector3::Vector3() { }
TSE::Vector3::Vector3(float _x, float _y)
{
x = _x;
y = _y;
z = 0;
}
TSE::Vector3::Vector3(float _x, float _y, float _z)
{
x = _x;
y = _y;
z = _z;
}
TSE::Vector3::Vector3(const Vector3 &other)
{
x = other.x;
y = other.y;
z = other.z;
}
TSE::Vector3::Vector3(const Vector2 &other)
{
x = other.x;
y = other.y;
}
TSE::Vector3::Vector3(const Vector4 &other)
{
x = other.x;
y = other.y;
z = other.z;
}
float TSE::Vector3::Length() const
{
return std::sqrt(x*x + y*y + z*z);
}
float TSE::Vector3::LengthSqr() const
{
return x*x + y*y + z*z;
}
bool TSE::Vector3::IsValid() const
{
return !std::isnan(x) && !std::isnan(y) && !std::isnan(z);
}
void TSE::Vector3::Normalize()
{
float lensq = LengthSqr();
if(lensq <= TSE_EPSILON) return;
const float inv = 1.0f / std::sqrt(lensq);
x *= inv; y *= inv; z *= inv;
}
void TSE::Vector3::NormalizeSafe(const Vector3 &fallback)
{
float lensq = LengthSqr();
if(lensq <= TSE_EPSILON)
{
*this = fallback;
return;
}
const float inv = 1.0f / std::sqrt(lensq);
x *= inv; y *= inv; z *= inv;
if(!IsValid())
{
*this = fallback;
}
}
TSE::string TSE::Vector3::ToString() const
{
return "(" + std::to_string(x) + "|" + std::to_string(y) + "|" + std::to_string(z) + ")";
}
TSE::Vector2 TSE::Vector3::ToVector2() const
{
return Vector2(x,y);
}
TSE::Vector4 TSE::Vector3::ToVector4() const
{
return Vector4(x,y,z,0);
}
float TSE::Vector3::Distance(const Vector3 &a, const Vector3 &b)
{
return (a - b).Length();
}
float TSE::Vector3::DistanceSqr(const Vector3 &a, const Vector3 &b)
{
return (a - b).LengthSqr();
}
TSE::Vector3 TSE::Vector3::Normalize(const Vector3 &v)
{
Vector3 result = v;
result.Normalize();
return result;
}
TSE::Vector3 TSE::Vector3::NormalizeSafe(const Vector3 &v, const Vector3 &fallback)
{
Vector3 result = v;
result.NormalizeSafe(fallback);
return result;
}
TSE::Vector3 TSE::Vector3::Lerp(const Vector3 &a, const Vector3 &b, float t)
{
return a + (b - a) * t;
}
TSE::Vector3 TSE::Vector3::Berp(const Vector3 &a, const Vector3 &b, const Vector3 &c, float t)
{
return Lerp(Lerp(a, b, t), Lerp(b, c, t), t);
}
TSE::Vector3 TSE::Vector3::Midpoint(const Vector3 &a, const Vector3 &b)
{
return (a + b) / 2.0f;
}
float TSE::Vector3::Dot(const Vector3 &a, const Vector3 &b)
{
return a.x * b.x + a.y * b.y + a.z * b.z;
}
TSE::Vector3 TSE::Vector3::Cross(const Vector3 &a, const Vector3 &b)
{
return Vector3(
a.y * b.z - a.z * b.y,
a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x
);
}
TSE::Vector3 TSE::Vector3::operator+(const Vector3 &other) const
{
return Vector3(x + other.x, y + other.y, z + other.z);
}
TSE::Vector3 TSE::Vector3::operator+=(const Vector3 &other)
{
*this = *this + other;
return *this;
}
TSE::Vector3 TSE::Vector3::operator-(const Vector3 &other) const
{
return Vector3(x - other.x, y - other.y, z - other.z);
}
TSE::Vector3 TSE::Vector3::operator-=(const Vector3 &other)
{
*this = *this - other;
return *this;
}
TSE::Vector3 TSE::Vector3::operator*(const Vector3 &other) const
{
return Vector3(x * other.x, y * other.y, z * other.z);
}
TSE::Vector3 TSE::Vector3::operator*=(const Vector3 &other)
{
*this = *this * other;
return *this;
}
TSE::Vector3 TSE::Vector3::operator/(const Vector3 &other) const
{
return Vector3(x / other.x, y / other.y, z / other.z);
}
TSE::Vector3 TSE::Vector3::operator/=(const Vector3 &other)
{
*this = *this / other;
return *this;
}
TSE::Vector3 TSE::Vector3::operator*(const float other) const
{
return Vector3(x * other, y * other, z * other);
}
TSE::Vector3 TSE::Vector3::operator*=(const float other)
{
*this = *this * other;
return *this;
}
TSE::Vector3 TSE::Vector3::operator/(const float other) const
{
return Vector3(x / other, y / other, z / other);
}
TSE::Vector3 TSE::Vector3::operator/=(const float other)
{
*this = *this / other;
return *this;
}
bool TSE::Vector3::operator==(const Vector3 &other) const
{
return x == other.x && y == other.y && z == other.z;
}
bool TSE::Vector3::operator!=(const Vector3 &other) const
{
return !(*this == other);
}

147
TSE_Math/src/Vector3.hpp Normal file
View File

@@ -0,0 +1,147 @@
#pragma once
#include "Types.hpp"
namespace TSE
{
class Vector2;
class Vector4;
class Vector3
{
public:
#pragma region member
float x = 0, y = 0, z = 0;
#pragma endregion member
#pragma region consts
static const Vector3 left;
static const Vector3 right;
static const Vector3 up;
static const Vector3 down;
static const Vector3 forward;
static const Vector3 back;
static const Vector3 one;
static const Vector3 zero;
#pragma endregion consts
#pragma region ctor
/// @brief default constructer constructs a Vector3 with (0,0,0)
Vector3();
/// @brief constructor where you only need to set x and y. z stays 0.
/// @param _x x component
/// @param _y y component
Vector3(float _x, float _y);
/// @brief constructor with custom values
/// @param _x x component
/// @param _y y component
/// @param _z z component
Vector3(float _x, float _y, float _z);
/// @brief copy constructor
/// @param other the vector3 to be copied
Vector3(const Vector3& other);
/// @brief converter constructer. it converts a Vector2 to a vector3 where z gets value 0
/// @param other the Vector2 to be converted
Vector3(const Vector2& other);
/// @brief converter constructer. it converts a Vector4 to a vector3 where w gets disregarded
/// @param other the Vector3 to be converted
Vector3(const Vector4& other);
#pragma endregion ctor
#pragma region methods
/// @brief the length of the vector
/// @return the length
float Length() const;
/// @brief the length² of the vector
/// @return the length²
float LengthSqr() const;
/// @brief checks if the individual components have valid values aka are not nan
/// @return are the values valid
bool IsValid() const;
/// @brief normalizes the Vector3 to have a length of 1
void Normalize();
/// @brief normalizes the Vector3 to have a length of 1. If the current length of the vector is smaller then epsilon, it gives you the fallback value.
/// @param fallback the value to set the vector to if the current length is smaller then epsilon
void NormalizeSafe(const Vector3& fallback);
/// @brief gives you the vector3 as a string representation. mostly for debugging
/// @return the vector3 in a format like (x|y|z)
string ToString() const;
/// @brief creates a Vector2 with the same values as the Vector3, the y component gets disregarded
/// @return the Vector3 as a Vector2
Vector2 ToVector2() const;
/// @brief creates a Vector4 with the same values as the Vector3, the w component get the value 0
/// @return the Vector3 as a Vector4
Vector4 ToVector4() const;
#pragma region static
/// @brief gives you the distance between two vectors.
/// @param a point 1
/// @param b point 2
/// @return the distance between point 1 and point 2
static float Distance(const Vector3& a, const Vector3& b);
/// @brief gives you the distance² between two vectors.
/// @param a point 1
/// @param b point 2
/// @return the distance² between point 1 and point 2
static float DistanceSqr(const Vector3& a, const Vector3& b);
/// @brief normalizes a copy of the Vector3 to have a length of 1
/// @param v the vector to be normaliezed
/// @return a normalies copy of the vector
static Vector3 Normalize(const Vector3& v);
/// @brief normalizes a copy of the Vector3 to have a length of 1. If the current length of the vector is smaller then epsilon, it gives you the fallback value.
/// @param fallback the value to set the vector to if the current length is smaller then epsilon
/// @param v the vector to be normaliezed
/// @return a normalies copy of the vector
static Vector3 NormalizeSafe(const Vector3& v, const Vector3& fallback);
/// @brief linearly interpolates between two points using t
/// @param a point 1
/// @param b point 2
/// @param t the amoint to interpolate by
/// @return the interpolated point
static Vector3 Lerp(const Vector3& a, const Vector3& b, float t);
/// @brief bezier interpolation using three points using t
/// @param a point 1
/// @param b controll point
/// @param c point 2
/// @param t the amoint to interpolate by
/// @return the interpolated point
static Vector3 Berp(const Vector3& a, const Vector3& b, const Vector3& c, float t);
/// @brief gives you the midpoint between two points
/// @param a point 1
/// @param b point 2
/// @return the midpoint
static Vector3 Midpoint(const Vector3& a, const Vector3& b);
/// @brief gives you the dot product between to vectors
/// @param a vector 1
/// @param b vector 2
/// @return the dot product
static float Dot(const Vector3& a, const Vector3& b);
/// @brief it gives you the Cross Product
/// @param a vector 1
/// @param b vector 2
/// @return cross product
static Vector3 Cross(const Vector3& a, const Vector3& b);
#pragma endregion static
#pragma region operators
Vector3 operator+(const Vector3& other) const;
Vector3 operator+=(const Vector3& other);
Vector3 operator-(const Vector3& other) const;
Vector3 operator-=(const Vector3& other);
Vector3 operator*(const Vector3& other) const;
Vector3 operator*=(const Vector3& other);
Vector3 operator/(const Vector3& other) const;
Vector3 operator/=(const Vector3& other);
Vector3 operator*(const float other) const;
Vector3 operator*=(const float other);
Vector3 operator/(const float other) const;
Vector3 operator/=(const float other);
bool operator==(const Vector3& other) const;
bool operator!=(const Vector3& other) const;
#pragma endregion operators
#pragma endregion methods
};
} // namespace TSE

162
TSE_Math/src/Vector4.cpp Normal file
View File

@@ -0,0 +1,162 @@
#include "Vector4.hpp"
#include "Vector3.hpp"
#include "Vector2.hpp"
#include "Color.hpp"
#include "Quaternion.hpp"
#include <cmath>
const TSE::Vector4 TSE::Vector4::one = TSE::Vector4(1,1,1,1);
const TSE::Vector4 TSE::Vector4::zero = TSE::Vector4(0,0,0,0);
TSE::Vector4::Vector4() { }
TSE::Vector4::Vector4(float _x, float _y, float _z, float _w)
{
x = _x;
y = _y;
z = _z;
w = _w;
}
TSE::Vector4::Vector4(const Vector4 &other)
{
x = other.x;
y = other.y;
z = other.z;
w = other.w;
}
TSE::Vector4::Vector4(const Vector2 &other)
{
x = other.x;
y = other.y;
}
TSE::Vector4::Vector4(const Vector3 &other)
{
x = other.x;
y = other.y;
z = other.z;
}
TSE::Vector4::Vector4(const Color &other)
{
x = other.r;
y = other.g;
z = other.b;
w = other.a;
}
TSE::Vector4::Vector4(const Quaternion &other)
{
x = other.x;
y = other.y;
z = other.z;
w = other.w;
}
bool TSE::Vector4::IsValid() const
{
return !std::isnan(x) && !std::isnan(y) && !std::isnan(z) && !std::isnan(w);
}
TSE::string TSE::Vector4::ToString() const
{
return "(" + std::to_string(x) + "|" + std::to_string(y) + "|" + std::to_string(z) + "|" + std::to_string(w) + ")";
}
TSE::Vector2 TSE::Vector4::ToVector2() const
{
return Vector2(x,y);
}
TSE::Vector3 TSE::Vector4::ToVector3() const
{
return Vector3(x,y,z);
}
TSE::Color TSE::Vector4::ToColor() const
{
return Color(x,y,z,w);
}
TSE::Quaternion TSE::Vector4::ToQuaternion() const
{
return Quaternion(x,y,z,w);
}
TSE::Vector4 TSE::Vector4::operator+(const Vector4 &other) const
{
return Vector4(x + other.x, y + other.y, z + other.z, w + other.w);
}
TSE::Vector4 TSE::Vector4::operator+=(const Vector4 &other)
{
*this = *this + other;
return *this;
}
TSE::Vector4 TSE::Vector4::operator-(const Vector4 &other) const
{
return Vector4(x - other.x, y - other.y, z - other.z, w - other.w);
}
TSE::Vector4 TSE::Vector4::operator-=(const Vector4 &other)
{
*this = *this - other;
return *this;
}
TSE::Vector4 TSE::Vector4::operator*(const Vector4 &other) const
{
return Vector4(x * other.x, y * other.y, z * other.z, w * other.w);
}
TSE::Vector4 TSE::Vector4::operator*=(const Vector4 &other)
{
*this = *this * other;
return *this;
}
TSE::Vector4 TSE::Vector4::operator/(const Vector4 &other) const
{
return Vector4(x / other.x, y / other.y, z / other.z, w / other.w);
}
TSE::Vector4 TSE::Vector4::operator/=(const Vector4 &other)
{
*this = *this / other;
return *this;
}
TSE::Vector4 TSE::Vector4::operator*(const float other) const
{
return Vector4(x * other, y * other, z * other, w * other);
}
TSE::Vector4 TSE::Vector4::operator*=(const float other)
{
*this = *this * other;
return *this;
}
TSE::Vector4 TSE::Vector4::operator/(const float other) const
{
return Vector4(x / other, y / other, z / other, w / other);
}
TSE::Vector4 TSE::Vector4::operator/=(const float other)
{
*this = *this / other;
return *this;
}
bool TSE::Vector4::operator==(const Vector4 &other) const
{
return x == other.x && y == other.y && z == other.z && w == other.w;
}
bool TSE::Vector4::operator!=(const Vector4 &other) const
{
return !(*this == other);
}

88
TSE_Math/src/Vector4.hpp Normal file
View File

@@ -0,0 +1,88 @@
#pragma once
#include "Types.hpp"
namespace TSE
{
class Vector2;
class Vector3;
class Color;
class Quaternion;
class Vector4
{
public:
#pragma region members
float x = 0, y = 0, z = 0, w = 0;
#pragma endregion members
#pragma region consts
static const Vector4 one;
static const Vector4 zero;
#pragma endregion consts
#pragma region ctor
/// @brief default constructer constructs a Vector4 with (0,0,0,0)
Vector4();
/// @brief constructor with custom values
/// @param _x x component
/// @param _y y component
/// @param _z z component
/// @param _w w component
Vector4(float _x, float _y, float _z, float _w);
/// @brief copy constructor
/// @param other the vector4 to be copied
Vector4(const Vector4& other);
/// @brief converter constructer. it converts a Vector2 to a vector4 where z and w gets value 0
/// @param other the Vector2 to be converted
Vector4(const Vector2& other);
/// @brief converter constructer. it converts a Vector3 to a vector4 where w gets value 0
/// @param other the Vector3 to be converted
Vector4(const Vector3& other);
/// @brief converter constructer. it converts a Color to a vector4
/// @param other the Color to be converted
Vector4(const Color& other);
/// @brief converter constructer. it converts a Quaternion to a vector4
/// @param other the Quaternion to be converted
Vector4(const Quaternion& other);
#pragma endregion ctor
#pragma region methods
/// @brief checks if the individual components have valid values aka are not nan
/// @return are the values valid
bool IsValid() const;
/// @brief gives you the vector4 as a string representation. mostly for debugging
/// @return the vector4 in a format like (x|y|z|w)
string ToString() const;
/// @brief creates a Vector2 with the same values as the Vector4, the w and y component gets disregarded
/// @return the Vector4 as a Vector2
Vector2 ToVector2() const;
/// @brief creates a Vector3 with the same values as the Vector4, the w component gets disregarded
/// @return the Vector4 as a Vector3
Vector3 ToVector3() const;
/// @brief creates a Color with the same values as the Vector4
/// @return the Vector4 as a Color
Color ToColor() const;
/// @brief creates a Quaternion with the same values as the Vector4
/// @return the Vector4 as a Quaternion
Quaternion ToQuaternion() const;
#pragma region operators
Vector4 operator+(const Vector4& other) const;
Vector4 operator+=(const Vector4& other);
Vector4 operator-(const Vector4& other) const;
Vector4 operator-=(const Vector4& other);
Vector4 operator*(const Vector4& other) const;
Vector4 operator*=(const Vector4& other);
Vector4 operator/(const Vector4& other) const;
Vector4 operator/=(const Vector4& other);
Vector4 operator*(const float other) const;
Vector4 operator*=(const float other);
Vector4 operator/(const float other) const;
Vector4 operator/=(const float other);
bool operator==(const Vector4& other) const;
bool operator!=(const Vector4& other) const;
#pragma endregion operators
#pragma endregion methods
};
} // namespace TSE