Math module initial
This commit is contained in:
parent
e29328a0dd
commit
4a2ab6f5d0
25 changed files with 2725 additions and 5 deletions
22
Math/CMakeLists.txt
Normal file
22
Math/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
|
||||
project(Math)
|
||||
|
||||
### ---------------------- Static Library --------------------- ###
|
||||
file(GLOB SOURCES "./private/*.cpp")
|
||||
file(GLOB HEADERS "./public/*.hpp")
|
||||
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Utils)
|
||||
|
||||
### -------------------------- Tests -------------------------- ###
|
||||
enable_testing()
|
||||
file(GLOB TEST_SOURCES "./tests/*.cpp")
|
||||
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils)
|
||||
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib)
|
||||
132
Math/private/Camera.cpp
Normal file
132
Math/private/Camera.cpp
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
#include "Camera.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
Camera::Camera() {
|
||||
lookAtPoint({ 0, 0, 0 }, { 2, 0, 0 }, { 0, 0, 1 });
|
||||
}
|
||||
|
||||
Vec3F Camera::getTarget() const { return mTarget; }
|
||||
|
||||
void Camera::offset_target(halnf val) { mTarget += (mPos - mTarget).normalize() * val; }
|
||||
|
||||
Vec3F Camera::getForward() const { return (mTarget - mPos).normalize(); }
|
||||
|
||||
Vec3F Camera::getUp() const { return mUp; }
|
||||
|
||||
Vec3F& Camera::getPos() { return mPos; }
|
||||
|
||||
halnf Camera::getFar() const { return mFar; }
|
||||
|
||||
halnf Camera::getNear() const { return mNear; }
|
||||
|
||||
halnf Camera::getRatio() const { return mRatio; }
|
||||
|
||||
void Camera::setRatio(halnf in) { mRatio = in; }
|
||||
|
||||
void Camera::setFOV(halnf in) { mFOV = in; }
|
||||
|
||||
halnf Camera::getFOV() const { return mFOV; }
|
||||
|
||||
Mat4F Camera::calculateTransformationMatrix() {
|
||||
return calculateProjectionMatrix() * calculateViewMatrix();
|
||||
}
|
||||
|
||||
Mat4F Camera::calculateViewMatrix() {
|
||||
const Vec3F& F = (mPos - mTarget).unitV();
|
||||
const Vec3F& S = mUp * F;
|
||||
const Vec3F& U = F * S;
|
||||
const Vec3F& P = mPos;
|
||||
|
||||
Mat4F out;
|
||||
out[0] = Vec4F(S.x, S.y, S.z, -P.dot(S));
|
||||
out[1] = Vec4F(U.x, U.y, U.z, -P.dot(U));
|
||||
out[2] = Vec4F(F.x, F.y, F.z, -P.dot(F));
|
||||
out[3] = Vec4F(0, 0, 0, 1);
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat4F Camera::calculateProjectionMatrix() const {
|
||||
auto r = (halnf) sqrt(mRatio);
|
||||
halnf c = 1 / r;
|
||||
auto s = halnf(1.f / tan(mFOV / 2.f));
|
||||
|
||||
Mat4F out;
|
||||
out[0] = Vec4F(s * r, 0, 0, 0);
|
||||
out[1] = Vec4F(0, s * c, 0, 0);
|
||||
out[2] = Vec4F(0, 0, -2.f / (mFar - mNear), -(mFar + mNear) / (mFar - mNear));
|
||||
out[3] = Vec4F(0, 0, -1, 0);
|
||||
return out;
|
||||
}
|
||||
|
||||
Vec3F Camera::project(Vec2F normalized) {
|
||||
auto camMat = calculateTransformationMatrix();
|
||||
auto inv = camMat.inv();
|
||||
|
||||
halnf z = halnf((((mTarget - mPos).length() - mNear) / (mFar - mNear) - 1.f / 2) * 2.f);
|
||||
halnf w = halnf((mTarget - mPos).length());
|
||||
Vec4<halnf> world_pos4(normalized.x * w, normalized.y * w, z, w);
|
||||
|
||||
return inv * world_pos4;
|
||||
}
|
||||
|
||||
Vec2F Camera::project(const Vec3F& world) {
|
||||
Vec4F world_pos4(world.x, world.y, world.z, 1);
|
||||
Vec4F transformed = calculateViewMatrix() * world_pos4;
|
||||
transformed = calculateProjectionMatrix() * transformed;
|
||||
return { transformed[0] / transformed[3], transformed[1] / transformed[3] };
|
||||
}
|
||||
|
||||
Vec2F Camera::project(const tp::Vec3F& world, const tp::Mat4F& viewMat, const tp::Mat4F& projMat) {
|
||||
Vec4F world_pos4(world.x, world.y, world.z, 1);
|
||||
Vec4F transformed = viewMat * world_pos4;
|
||||
transformed = projMat * transformed;
|
||||
return { transformed[0] / transformed[3], transformed[1] / transformed[3] };
|
||||
}
|
||||
|
||||
void Camera::lookAtPoint(const Vec3F& aTarget, const Vec3F& aPos, Vec3F aUp) {
|
||||
if (aTarget == aPos) return;
|
||||
mPos = aPos;
|
||||
mTarget = aTarget;
|
||||
Vec3F f = (mPos - mTarget).normalize();
|
||||
mUp = f * (aUp.normalize() * f);
|
||||
}
|
||||
|
||||
void Camera::zoom(halnf ratio) {
|
||||
ratio = abs(ratio);
|
||||
if (ratio < 0.1f) {
|
||||
return;
|
||||
}
|
||||
if (abs((mPos - mTarget).length2()) < 0.05f && ratio < 1.f) {
|
||||
return;
|
||||
}
|
||||
mPos = mTarget + (mPos - mTarget) * ratio;
|
||||
lookAtPoint(mTarget, mPos, mUp);
|
||||
}
|
||||
|
||||
void Camera::move(Vec2F aPos, Vec2F aPrevPos) {
|
||||
Vec3F p1 = project(aPrevPos);
|
||||
Vec3F p2 = project(aPos);
|
||||
Vec3F move = p1 - p2;
|
||||
mPos += move;
|
||||
mTarget += move;
|
||||
lookAtPoint(mTarget, mPos, mUp);
|
||||
}
|
||||
|
||||
void Camera::rotate(halnf angleX, halnf angleY) {
|
||||
Vec3F wup(0, 0, 1);
|
||||
mPos -= mTarget;
|
||||
|
||||
mat3f rotZ = mat3f::rotatorDir(wup, angleX);
|
||||
mPos = rotZ * mPos;
|
||||
mUp = rotZ * mUp;
|
||||
|
||||
Vec3F f = mPos.unitV();
|
||||
Vec3F s = mUp * f;
|
||||
|
||||
mPos = mat3f::rotatorDir(s, -angleY) * mPos;
|
||||
|
||||
mPos += mTarget;
|
||||
|
||||
lookAtPoint(mTarget, mPos, mUp);
|
||||
}
|
||||
169
Math/private/Color.cpp
Normal file
169
Math/private/Color.cpp
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
|
||||
#include "Color.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
RGB::RGB() { r = g = b = 1.f; }
|
||||
RGB::RGB(flt4 pr, flt4 pg, flt4 pb) { set(pr, pg, pb); }
|
||||
RGB::RGB(flt4 val) { set(val, val, val); }
|
||||
|
||||
void RGB::set(flt4 pr, flt4 pg, flt4 pb) {
|
||||
r = pr;
|
||||
b = pb;
|
||||
g = pg;
|
||||
}
|
||||
|
||||
RGB::operator HSV() const {
|
||||
|
||||
HSV out;
|
||||
alnf min, max, delta;
|
||||
|
||||
min = r < g ? r : g;
|
||||
min = min < b ? min : b;
|
||||
max = r > g ? r : g;
|
||||
max = max > b ? max : b;
|
||||
|
||||
out.v = (halnf) max;
|
||||
delta = max - min;
|
||||
|
||||
if (delta < 0.00001) {
|
||||
out.s = 0;
|
||||
// undefined, maybe nan?
|
||||
out.h = 0;
|
||||
return out;
|
||||
}
|
||||
if (max > 0.f) {
|
||||
// NOTE: if Max is == 0, this divide would cause a crash
|
||||
out.s = (halnf) (delta / max);
|
||||
|
||||
} else {
|
||||
// if max is 0, then r = g = b = 0
|
||||
// s = 0, h is undefined
|
||||
out.s = 0.f;
|
||||
out.h = 0.f;
|
||||
return out;
|
||||
}
|
||||
if (r >= max) {
|
||||
// between yellow & magenta
|
||||
out.h = (halnf) ((g - b) / delta);
|
||||
} else {
|
||||
if (g >= max) {
|
||||
// between cyan & yellow
|
||||
out.h = (halnf) (2.0 + (b - r) / delta);
|
||||
} else {
|
||||
// between magenta & cyan
|
||||
out.h = (halnf) (4.0 + (r - g) / delta);
|
||||
}
|
||||
}
|
||||
|
||||
out.h *= 60.f;
|
||||
|
||||
if (out.h < 0.0) {
|
||||
out.h += 360.f;
|
||||
}
|
||||
|
||||
out.h = (halnf) (out.h / 360.f * (PI2));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
HSV::HSV() { h = s = v = 0.f; }
|
||||
|
||||
HSV::HSV(flt4 ph, flt4 ps, flt4 pv) { set(ph, ps, pv); }
|
||||
|
||||
void HSV::set(flt4 ph, flt4 ps, flt4 pv) {
|
||||
h = ph;
|
||||
s = ps;
|
||||
v = pv;
|
||||
}
|
||||
|
||||
HSV::operator RGB() const {
|
||||
alnf hh, p, q, t, ff;
|
||||
alni i;
|
||||
RGB out;
|
||||
|
||||
if (s <= 0.0) { // < is bogus, just shuts up warnings
|
||||
out.r = v;
|
||||
out.g = v;
|
||||
out.b = v;
|
||||
return out;
|
||||
}
|
||||
|
||||
hh = h / (PI2) * 360;
|
||||
|
||||
if (hh >= 360.0) {
|
||||
hh = 0.0;
|
||||
}
|
||||
|
||||
hh /= 60.0;
|
||||
i = (long) hh;
|
||||
ff = hh - i;
|
||||
p = v * (1.0 - s);
|
||||
q = v * (1.0 - (s * ff));
|
||||
t = v * (1.0 - (s * (1.0 - ff)));
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
out.r = (halnf) v;
|
||||
out.g = (halnf) t;
|
||||
out.b = (halnf) p;
|
||||
break;
|
||||
case 1:
|
||||
out.r = (halnf) q;
|
||||
out.g = (halnf) v;
|
||||
out.b = (halnf) p;
|
||||
break;
|
||||
case 2:
|
||||
out.r = (halnf) p;
|
||||
out.g = (halnf) v;
|
||||
out.b = (halnf) t;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
out.r = (halnf) p;
|
||||
out.g = (halnf) q;
|
||||
out.b = (halnf) v;
|
||||
break;
|
||||
case 4:
|
||||
out.r = (halnf) t;
|
||||
out.g = (halnf) p;
|
||||
out.b = (halnf) v;
|
||||
break;
|
||||
case 5:
|
||||
default:
|
||||
out.r = (halnf) v;
|
||||
out.g = (halnf) p;
|
||||
out.b = (halnf) q;
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
struct rgbab {
|
||||
|
||||
uint4 RGBA;
|
||||
|
||||
rgbab() { RGBA = 0xFFFFFFFF; }
|
||||
rgbab(uint4 color) { RGBA = color; }
|
||||
rgbab(uint1 r, uint1 b, uint1 g, uint1 a) { set(r, b, g, a); }
|
||||
rgbab(const rgbab& in) { RGBA = in.RGBA; }
|
||||
|
||||
void set(uint4 color) { RGBA = color; }
|
||||
void set(uint1 r, uint1 b, uint1 g, uint1 a) {
|
||||
RGBA = (uint1)(a);
|
||||
RGBA <<= 8; RGBA |= (uint1)(r);
|
||||
RGBA <<= 8; RGBA |= (uint1)(g);
|
||||
RGBA <<= 8; RGBA |= (uint1)(b);
|
||||
}
|
||||
|
||||
operator rgbaf() {
|
||||
rgbaf out;
|
||||
out.r = uint1((RGBA & 0x00FF0000) >> 16) / 255.f;
|
||||
out.g = uint1((RGBA & 0x0000FF00) >> 8) / 255.f;
|
||||
out.b = uint1(RGBA & 0x000000FF) / 255.f;
|
||||
out.a = uint1((RGBA & 0xFF000000) >> 24) / 255.f;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
*/
|
||||
43
Math/private/MathCommon.cpp
Normal file
43
Math/private/MathCommon.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
#include "MathCommon.hpp"
|
||||
|
||||
#include "ContainersCommon.hpp"
|
||||
|
||||
static tp::ModuleManifest* sModuleDependencies[] = {
|
||||
&tp::gModuleContainers,
|
||||
nullptr
|
||||
};
|
||||
|
||||
tp::ModuleManifest tp::gModuleMath = ModuleManifest("Math", nullptr, nullptr, sModuleDependencies);
|
||||
|
||||
tp::alnf std_sin(tp::alnf radians);
|
||||
tp::alnf std_tan(tp::alnf radians);
|
||||
tp::alnf std_cos(tp::alnf radians);
|
||||
tp::alnf std_acos(tp::alnf val);
|
||||
tp::alnf std_sqrt(tp::alnf val);
|
||||
tp::alnf std_rad(tp::alnf val);
|
||||
tp::alnf std_deg(tp::alnf val);
|
||||
tp::alnf std_atan2(tp::alnf X, tp::alnf Y);
|
||||
tp::alnf std_atan(tp::alnf val);
|
||||
|
||||
tp::alnf tp::sin(const tp::alnf radians) { return std_sin((halnf) radians); }
|
||||
tp::alnf tp::tan(const tp::alnf radians) { return std_tan((halnf) radians); }
|
||||
tp::alnf tp::cos(const tp::alnf radians) { return std_cos((halnf) radians); }
|
||||
tp::alnf tp::acos(const tp::alnf val) { return std_acos((halnf) val); }
|
||||
tp::alnf tp::sqrt(const tp::alnf val) { return std_sqrt((halnf) val); }
|
||||
tp::alnf tp::rad(const tp::alnf val) { return val * (PI / 180.f); }
|
||||
tp::alnf tp::deg(const tp::alnf val) { return val * (180.f / PI); }
|
||||
tp::alnf tp::atan2(const tp::alnf X, const tp::alnf Y) { return std_atan2((halnf) X, (halnf) Y); }
|
||||
tp::alnf tp::atan(const tp::alnf val) { return std_atan((halnf) val); }
|
||||
|
||||
#include <cmath>
|
||||
|
||||
tp::alnf std_sin(const tp::alnf radians) { return sinf((tp::halnf)radians); }
|
||||
tp::alnf std_tan(const tp::alnf radians) { return tanf((tp::halnf)radians); }
|
||||
tp::alnf std_cos(const tp::alnf radians) { return cosf((tp::halnf)radians); }
|
||||
tp::alnf std_acos(const tp::alnf val) { return acos((tp::halnf)val); }
|
||||
tp::alnf std_sqrt(const tp::alnf val) { return sqrt((tp::halnf)val); }
|
||||
tp::alnf std_rad(const tp::alnf val) { return val * (PI / 180.f); }
|
||||
tp::alnf std_deg(const tp::alnf val) { return val * (180.f / PI); }
|
||||
tp::alnf std_atan2(const tp::alnf X, const tp::alnf Y) { return atan2((tp::halnf)X, (tp::halnf)Y); }
|
||||
tp::alnf std_atan(const tp::alnf val) { return atan((tp::halnf)val); }
|
||||
9
Math/private/Ray.cpp
Normal file
9
Math/private/Ray.cpp
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
#include "Ray.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
Ray::Ray(const Vec3F& aDir, const Vec3F& aPos) {
|
||||
this->dir = aDir.unitV();
|
||||
this->pos = aPos;
|
||||
}
|
||||
105
Math/private/Topology.cpp
Normal file
105
Math/private/Topology.cpp
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
|
||||
#include "Topology.hpp"
|
||||
|
||||
void* operator new(std::size_t, void* in) { return in; }
|
||||
|
||||
using namespace tp;
|
||||
|
||||
Vec3F TrigCache::gHitPos;
|
||||
|
||||
TrigCache::TrigCache() : mP1(0), mP2(0), mP3(0) {}
|
||||
|
||||
TrigCache::TrigCache(ualni v1, ualni v2, ualni v3) : mP1(v1), mP2(v2), mP3(v3) {}
|
||||
|
||||
TrigCache::TrigCache(const TrigCache& in) {
|
||||
mP1 = in.mP1;
|
||||
mP2 = in.mP2;
|
||||
mP3 = in.mP3;
|
||||
|
||||
mEdgeP1P2 = in.mEdgeP1P2;
|
||||
mEdgeP1P3 = in.mEdgeP1P3;
|
||||
|
||||
mOrigin = in.mOrigin;
|
||||
mNormal = in.mNormal;
|
||||
}
|
||||
|
||||
void TrigCache::updateCache(const Buffer<Vec3F>& points) {
|
||||
mOrigin = points[mP1];
|
||||
mEdgeP1P2 = points[mP2] - points[mP1];
|
||||
mEdgeP1P3 = points[mP3] - points[mP1];
|
||||
mNormal = (points[mP2] - points[mP1]).cross(points[mP3] - points[mP1]).unitV();
|
||||
}
|
||||
|
||||
bool TrigCache::castRay(const Ray& ray) const {
|
||||
static Vec3F h, s, q;
|
||||
static halnf a, f, u, v;
|
||||
static halnf t;
|
||||
|
||||
h = ray.dir.cross(mEdgeP1P3);
|
||||
a = mEdgeP1P2.dot(h);
|
||||
|
||||
if (a > -EPSILON && a < EPSILON) {
|
||||
return false;
|
||||
}
|
||||
|
||||
f = 1.f / a;
|
||||
s = ray.pos - mOrigin;
|
||||
u = f * s.dot(h);
|
||||
|
||||
if (u < 0.0 || u > 1.0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
q = s.cross(mEdgeP1P2);
|
||||
v = f * ray.dir.dot(q);
|
||||
|
||||
if (v < 0.f || u + v > 1.f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
t = f * mEdgeP1P3.dot(q);
|
||||
if (t > EPSILON) {
|
||||
gHitPos = ray.pos + ray.dir * t;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const Vec3F& TrigCache::getHitPos() { return gHitPos; }
|
||||
|
||||
const Vec3F& TrigCache::getNormal() const { return mNormal; }
|
||||
|
||||
void Topology::addTrig(const Vec3F& v1, const Vec3F& v2, const Vec3F& v3) {
|
||||
auto trigIdx = mPoints.size();
|
||||
|
||||
Buffer<Vec3F> newPoints(3);
|
||||
newPoints[0] = v1;
|
||||
newPoints[1] = v2;
|
||||
newPoints[2] = v3;
|
||||
mPoints.append(newPoints);
|
||||
|
||||
transformPoint(newPoints[0]);
|
||||
transformPoint(newPoints[1]);
|
||||
transformPoint(newPoints[2]);
|
||||
mPointsTransformed.append(newPoints);
|
||||
|
||||
TrigCache newTrig(trigIdx, trigIdx + 1, trigIdx + 2);
|
||||
newTrig.updateCache(mPointsTransformed);
|
||||
mTrigCaches.append(newTrig);
|
||||
}
|
||||
|
||||
void Topology::transformPoint(Vec3F& vert) {
|
||||
mBasis.transform(vert);
|
||||
vert += mOrigin;
|
||||
}
|
||||
|
||||
void Topology::updateTransformed() {
|
||||
mPointsTransformed = mPoints;
|
||||
for (auto idx : Range(mPointsTransformed.size())) {
|
||||
transformPoint(mPointsTransformed[idx]);
|
||||
}
|
||||
for (auto idx : Range(mTrigCaches.size())) {
|
||||
mTrigCaches[idx].updateCache(mPointsTransformed);
|
||||
}
|
||||
}
|
||||
72
Math/private/Trig.cpp
Normal file
72
Math/private/Trig.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
|
||||
#include "Trig.hpp"
|
||||
|
||||
#include "Ray.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
Trig::Trig() {
|
||||
MODULE_SANITY_CHECK(gModuleMath)
|
||||
p1.assign(0.f, 0.f, 0.f);
|
||||
p2.assign(0.f, 0.f, 0.f);
|
||||
p3.assign(0.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
Trig::Trig(const Vec3F& v0, const Vec3F& v1, const Vec3F& v2) {
|
||||
p1 = v0;
|
||||
p2 = v1;
|
||||
p3 = v2;
|
||||
}
|
||||
|
||||
void Trig::assign(const Vec3F& v0, const Vec3F& v1, const Vec3F& v2) {
|
||||
p1 = v0;
|
||||
p2 = v1;
|
||||
p3 = v2;
|
||||
}
|
||||
|
||||
Trig::~Trig() = default;
|
||||
|
||||
void Trig::normal(Vec3F& dir) const {
|
||||
dir = (p2 - p1).cross(p3 - p1);
|
||||
dir.normalize();
|
||||
}
|
||||
|
||||
Vec3F edge1, edge2, h, s, q;
|
||||
halnf a, f, u, v;
|
||||
halnf t;
|
||||
|
||||
bool Trig::rayHit(class Ray& ray, Vec3F& HitPos) const {
|
||||
|
||||
edge1 = p2 - p1;
|
||||
edge2 = p3 - p1;
|
||||
|
||||
h = ray.dir.cross(edge2);
|
||||
a = edge1.dot(h);
|
||||
|
||||
if (a > -EPSILON && a < EPSILON) {
|
||||
return false;
|
||||
}
|
||||
|
||||
f = 1.f / a;
|
||||
s = ray.pos - p1;
|
||||
u = f * s.dot(h);
|
||||
|
||||
if (u < 0.0 || u > 1.0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
q = s.cross(edge1);
|
||||
v = f * ray.dir.dot(q);
|
||||
|
||||
if (v < 0.f || u + v > 1.f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
t = f * edge2.dot(q);
|
||||
if (t > EPSILON) {
|
||||
HitPos = ray.pos + ray.dir * t;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
46
Math/public/Camera.hpp
Normal file
46
Math/public/Camera.hpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include "Mat.hpp"
|
||||
#include "Ray.hpp"
|
||||
|
||||
namespace tp {
|
||||
class Camera {
|
||||
Vec3F mPos, mTarget, mUp;
|
||||
halnf mFOV = (halnf) (PI) / 4;
|
||||
halnf mNear = 0.001f;
|
||||
halnf mFar = 100.f;
|
||||
halnf mRatio = 1.f;
|
||||
|
||||
public:
|
||||
Camera();
|
||||
~Camera() = default;
|
||||
|
||||
void setRatio(halnf ratio);
|
||||
void setFOV(halnf fov);
|
||||
|
||||
[[nodiscard]] Vec3F& getPos();
|
||||
[[nodiscard]] Vec3F getTarget() const;
|
||||
[[nodiscard]] Vec3F getForward() const;
|
||||
[[nodiscard]] Vec3F getUp() const;
|
||||
[[nodiscard]] halnf getRatio() const;
|
||||
[[nodiscard]] halnf getFOV() const;
|
||||
[[nodiscard]] halnf getFar() const;
|
||||
[[nodiscard]] halnf getNear() const;
|
||||
|
||||
public:
|
||||
void lookAtPoint(const Vec3F& aTarget, const Vec3F& aPos, Vec3F aUp);
|
||||
void rotate(halnf anglex, halnf angleY);
|
||||
void move(Vec2F aPos, Vec2F aPrevPos);
|
||||
void zoom(halnf ratio);
|
||||
void offset_target(halnf val);
|
||||
|
||||
public:
|
||||
[[nodiscard]] Mat4F calculateTransformationMatrix();
|
||||
[[nodiscard]] Mat<halnf, 4, 4> calculateProjectionMatrix() const;
|
||||
[[nodiscard]] Mat<halnf, 4, 4> calculateViewMatrix();
|
||||
[[nodiscard]] Vec3F project(Vec2F normalized);
|
||||
[[nodiscard]] Vec2F project(const Vec3F& world);
|
||||
[[nodiscard]] static Vec2F project(const tp::Vec3F& world, const tp::Mat4F& viewMat, const tp::Mat4F& projMat);
|
||||
|
||||
};
|
||||
}
|
||||
84
Math/public/Color.hpp
Normal file
84
Math/public/Color.hpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
#pragma once
|
||||
|
||||
#include "Vec.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
class RGB;
|
||||
class HSV;
|
||||
|
||||
class RGB {
|
||||
public:
|
||||
RGB();
|
||||
RGB(flt4 pr, flt4 pg, flt4 pb);
|
||||
RGB(flt4 val);
|
||||
|
||||
public:
|
||||
void set(flt4 pr, flt4 pg, flt4 pb);
|
||||
operator HSV() const;
|
||||
|
||||
public:
|
||||
halnf r, g, b;
|
||||
};
|
||||
|
||||
class HSV {
|
||||
public:
|
||||
HSV();
|
||||
HSV(flt4 ph, flt4 ps, flt4 pv);
|
||||
|
||||
public:
|
||||
void set(flt4 ph, flt4 ps, flt4 pv);
|
||||
operator RGB() const;
|
||||
|
||||
public:
|
||||
halnf h, s, v;
|
||||
};
|
||||
|
||||
class RGBA {
|
||||
public:
|
||||
RGBA() : r(0), g(0), b(0), a(0) {}
|
||||
RGBA(flt4 val) : rgbs(val), a(val) {}
|
||||
RGBA(const RGB& RGBs, flt4 val) : rgbs(RGBs), a(val) {}
|
||||
RGBA(flt4 pr, flt4 pg, flt4 pb, flt4 pa) : rgbs(pr, pg, pb), a(pa) {}
|
||||
|
||||
public:
|
||||
RGBA& operator=(const HSV& in) {
|
||||
rgbs = in;
|
||||
a = 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RGBA operator-(const RGBA& in) const {
|
||||
auto const nr = tp::clamp(r - in.r, 0.f, 1.f);
|
||||
auto const ng = tp::clamp(g - in.g, 0.f, 1.f);
|
||||
auto const nb = tp::clamp(b - in.b, 0.f, 1.f);
|
||||
auto const na = tp::clamp(a - in.a, 0.f, 1.f);
|
||||
return { nr, ng, nb, na };
|
||||
}
|
||||
|
||||
RGBA operator+(const RGBA& in) const {
|
||||
auto const nr = tp::clamp(r + in.r, 0.f, 1.f);
|
||||
auto const ng = tp::clamp(g + in.g, 0.f, 1.f);
|
||||
auto const nb = tp::clamp(b + in.b, 0.f, 1.f);
|
||||
auto const na = tp::clamp(a + in.a, 0.f, 1.f);
|
||||
return { nr, ng, nb, na };
|
||||
}
|
||||
|
||||
public:
|
||||
flt4 a;
|
||||
|
||||
union {
|
||||
RGB rgbs;
|
||||
struct {
|
||||
flt4 r;
|
||||
flt4 g;
|
||||
flt4 b;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
class HSVA {
|
||||
HSV rgbs;
|
||||
flt4 a = 1.f;
|
||||
};
|
||||
}
|
||||
34
Math/public/Intersections.hpp
Normal file
34
Math/public/Intersections.hpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include "Vec.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
template <typename Type>
|
||||
bool intersectLines2D(const Vec2<Type>& p1, const Vec2<Type>& p2, const Vec2<Type>& v1, const Vec2<Type>& v2, Vec2<Type>* out) {
|
||||
auto a1 = p2.x - p1.x;
|
||||
auto a2 = p2.y - p1.y;
|
||||
|
||||
auto b1 = v2.x - v1.x;
|
||||
auto b2 = v2.y - v1.y;
|
||||
|
||||
auto c1 = v1.x - p1.x;
|
||||
auto c2 = v1.y - p1.y;
|
||||
|
||||
auto det = a2 * b1 - a1 * b2;
|
||||
|
||||
auto t1 = ( -b2 * c1 + b1 * c2 ) / det;
|
||||
auto t2 = ( -a2 * c1 + a1 * c2 ) / det;
|
||||
|
||||
if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) {
|
||||
if (out != nullptr) {
|
||||
out->x = p1.x + (a1 * t1);
|
||||
out->y = p1.y + (a2 * t1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
768
Math/public/Mat.hpp
Normal file
768
Math/public/Mat.hpp
Normal file
|
|
@ -0,0 +1,768 @@
|
|||
#pragma once
|
||||
|
||||
#include "Vec.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
template <typename Type, const halni tNRows, const halni tNColoumns>
|
||||
class Mat {
|
||||
typedef Vec<Type, tNRows> MVec;
|
||||
|
||||
private:
|
||||
MVec mCol[tNColoumns];
|
||||
|
||||
public:
|
||||
Mat() = default;
|
||||
|
||||
explicit Mat(const Type& val) {
|
||||
operator=(val);
|
||||
}
|
||||
|
||||
Mat(const Mat& in) {
|
||||
operator=(in);
|
||||
}
|
||||
|
||||
MVec& operator[](alni i) {
|
||||
DEBUG_ASSERT(i < tNColoumns && i >= 0)
|
||||
return mCol[i];
|
||||
}
|
||||
|
||||
const MVec& operator[](alni i) const {
|
||||
DEBUG_ASSERT(i < tNColoumns && i >= 0)
|
||||
return mCol[i];
|
||||
}
|
||||
|
||||
Mat& operator=(const Mat& in) {
|
||||
if (&in == this) return *this;
|
||||
memcp(this, &in, sizeof(Mat<Type, tNRows, tNColoumns>));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator=(const Type& val) {
|
||||
clear(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void clear(const Type& val) {
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
(*this)[i][j] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setDiagonal(const Type& val) {
|
||||
halni len = min(tNColoumns, tNRows);
|
||||
for (halni i = 0; i < len; i++) {
|
||||
(*this)[i][i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
Mat& fillRandom() {
|
||||
DEBUG_ASSERT(0)
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
(*this)[i][j] = (Type) 0;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat operator-() {
|
||||
Mat out;
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
out[i][j] = -(*this)[i][j];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat& operator+=(const Mat& in) {
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
(*this)[i][j] += in[i][j];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator-=(const Mat& in) {
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
(*this)[i][j] -= in[i][j];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator+=(const Type& val) {
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
(*this)[i][j] += val;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator-=(const Type& val) {
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
(*this)[i][j] -= val;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator/=(const Type& val) {
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
(*this)[i][j] /= val;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator*=(const Type& val) {
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
(*this)[i][j] *= val;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat operator+(const Mat& in) {
|
||||
Mat out;
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
out[i][j] = (*this)[i][j] + in[i];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat operator-(const Mat& in) {
|
||||
Mat out;
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
out[i][j] = (*this)[i][j] - in[i];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat operator+(const Type& val) {
|
||||
Mat out;
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
out[i][j] = (*this)[i][j] + val;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat operator-(const Type& val) {
|
||||
Mat out;
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
out[i][j] = (*this)[i][j] - val;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat operator*(const Type& val) {
|
||||
Mat out;
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
out[i][j] = (*this)[i][j] * val;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat operator/(const Type& val) {
|
||||
Mat out;
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
out[i][j] = (*this)[i][j] / val;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Matrix Properties
|
||||
MVec transform(const MVec& in) const {
|
||||
static_assert(tNRows == tNColoumns);
|
||||
MVec out;
|
||||
for (halni i = 0; i < tNRows; i++) {
|
||||
Type tmp = 0;
|
||||
for (halni j = 0; j < tNColoumns; j++) {
|
||||
tmp += (*this)[i][j] * in[j];
|
||||
}
|
||||
out[i] = tmp;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat transform(const Mat& in) const {
|
||||
Mat out;
|
||||
out.clear(0);
|
||||
for (halni i = 0; i < tNRows; i++) {
|
||||
for (halni j = 0; j < tNRows; j++) {
|
||||
for (halni u = 0; u < tNRows; u++) {
|
||||
out[i][j] += (*this)[i][u] * in[u][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat& transpose() {
|
||||
static_assert( tNRows == tNColoumns);
|
||||
for (halni i = 0; i < tNColoumns; i++) {
|
||||
for (halni j = i + 1; j < tNColoumns; j++) {
|
||||
swap((*this)[i][j], (*this)[j][i]);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat operator*(const Mat& in) const {
|
||||
return transform(in);
|
||||
}
|
||||
|
||||
MVec operator*(const MVec& in) const {
|
||||
return transform(in);
|
||||
}
|
||||
|
||||
Mat<Type, tNRows - 1, tNRows - 1> minor(halni p, halni q) {
|
||||
Mat<Type, tNRows - 1, tNRows - 1> out;
|
||||
halni i = 0, j = 0;
|
||||
for (halni row = 0; row < tNRows; row++) {
|
||||
for (halni col = 0; col < tNRows; col++) {
|
||||
if (row != p && col != q) {
|
||||
out[i][j++] = (*this)[row][col];
|
||||
if (j == tNRows - 1) {
|
||||
j = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Type det() {
|
||||
static_assert( tNRows == tNColoumns);
|
||||
|
||||
Type out = 0;
|
||||
|
||||
if (tNRows == 1) {
|
||||
return (*this)[0][0];
|
||||
}
|
||||
if (tNRows == 2) {
|
||||
return ((*this)[0][0] * (*this)[1][1]) - ((*this)[1][0] * (*this)[0][1]);
|
||||
}
|
||||
|
||||
halni sign = 1;
|
||||
for (int i = 0; i < tNRows; i++) {
|
||||
out += sign * (*this)[0][i] * minor(0, i).det();
|
||||
sign = -sign;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat cofactors() {
|
||||
static_assert( tNRows == tNColoumns);
|
||||
Mat out;
|
||||
for (int i = 0; i < tNRows; i++) {
|
||||
for (int j = 0; j < tNRows; j++) {
|
||||
Type sign = (Type) ((i + j + 2) & 1 ? -1 : 1);
|
||||
out[i][j] = minor(j, i).det() * sign;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat inv() {
|
||||
Type detV = det();
|
||||
DEBUG_ASSERT(detV)
|
||||
return cofactors() /= detV;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
using Mat2 = Mat<Type, 2, 2>;
|
||||
using Mat2F = Mat2<halnf>;
|
||||
|
||||
template <typename Type>
|
||||
class Mat<Type, 2, 2> {
|
||||
typedef Vec<Type, 2> MVec;
|
||||
|
||||
MVec i;
|
||||
MVec j;
|
||||
|
||||
public:
|
||||
|
||||
Mat() = default;
|
||||
|
||||
explicit Mat(const Type& val) {
|
||||
operator=(val);
|
||||
}
|
||||
|
||||
Mat(const MVec& pi, const MVec& pj) {
|
||||
i.x = pi.x;
|
||||
i.y = pi.y;
|
||||
j.x = pj.x;
|
||||
j.y = pj.y;
|
||||
}
|
||||
|
||||
Mat(Type ix, Type iy, Type jx, Type jy) {
|
||||
i.x = ix;
|
||||
i.y = iy;
|
||||
j.x = jx;
|
||||
j.y = jy;
|
||||
}
|
||||
|
||||
Mat(const Mat& in) {
|
||||
operator=(in);
|
||||
}
|
||||
|
||||
MVec& operator[](alni idx) {
|
||||
DEBUG_ASSERT(idx < 2 && idx >= 0)
|
||||
return (&i)[idx];
|
||||
}
|
||||
|
||||
const MVec& operator[](alni idx) const {
|
||||
DEBUG_ASSERT(idx < 2 && idx >= 0)
|
||||
return (&i)[idx];
|
||||
}
|
||||
|
||||
Mat& operator=(const Mat& in) {
|
||||
memcp(this, &in, sizeof(Mat2<Type>));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator=(const Type& val) {
|
||||
clear(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void clear(const Type& val) {
|
||||
i.x = val;
|
||||
i.y = val;
|
||||
j.x = val;
|
||||
j.y = val;
|
||||
}
|
||||
|
||||
void setDiagonal(const Type& val) {
|
||||
i.x = val;
|
||||
j.y = val;
|
||||
}
|
||||
|
||||
Mat& fillRandom() {
|
||||
DEBUG_ASSERT(0)
|
||||
i.x = (Type) 0;
|
||||
i.y = (Type) 0;
|
||||
j.x = (Type) 0;
|
||||
j.y = (Type) 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat operator-() {
|
||||
return Mat(-i.x, -i.y, -j.x, -j.y);
|
||||
}
|
||||
|
||||
Mat& operator+=(const Mat& in) {
|
||||
i.x += in.i.x;
|
||||
i.y += in.i.y;
|
||||
j.x += in.j.x;
|
||||
j.y += in.j.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator-=(const Mat& in) {
|
||||
i.x -= in.i.x;
|
||||
i.y -= in.i.y;
|
||||
j.x -= in.j.x;
|
||||
j.y -= in.j.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator+=(Type val) {
|
||||
i.x += val;
|
||||
i.y += val;
|
||||
j.x += val;
|
||||
j.y += val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator-=(Type val) {
|
||||
i.x -= val;
|
||||
i.y -= val;
|
||||
j.x -= val;
|
||||
j.y -= val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator/=(Type val) {
|
||||
i.x /= val;
|
||||
i.y /= val;
|
||||
j.x /= val;
|
||||
j.y /= val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator*=(Type val) {
|
||||
i.x *= val;
|
||||
i.y *= val;
|
||||
j.x *= val;
|
||||
j.y *= val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat operator+(const Mat& in) {
|
||||
Mat out;
|
||||
out.i.x = i.x + in.i.x;
|
||||
out.i.y = i.y + in.i.y;
|
||||
out.j.x = j.x + in.j.x;
|
||||
out.j.y = j.y + in.j.y;
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat operator-(const Mat& in) {
|
||||
Mat out;
|
||||
out.i.x = i.x - in.i.x;
|
||||
out.i.y = i.y - in.i.y;
|
||||
out.j.x = j.x - in.j.x;
|
||||
out.j.y = j.y - in.j.y;
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat operator+(const Type& val) {
|
||||
Mat out;
|
||||
out.i.x = i.x + val;
|
||||
out.i.y = i.y + val;
|
||||
out.j.x = j.x + val;
|
||||
out.j.y = j.y + val;
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat operator-(const Type& val) {
|
||||
Mat out;
|
||||
out.i.x = i.x - val;
|
||||
out.i.y = i.y - val;
|
||||
out.j.x = j.x - val;
|
||||
out.j.y = j.y - val;
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat operator*(const Type& val) {
|
||||
Mat out;
|
||||
out.i.x = i.x * val;
|
||||
out.i.y = i.y * val;
|
||||
out.j.x = j.x * val;
|
||||
out.j.y = j.y * val;
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat operator/(const Type& val) {
|
||||
Mat out;
|
||||
out.i.x = i.x / val;
|
||||
out.i.y = i.y / val;
|
||||
out.j.x = j.x / val;
|
||||
out.j.y = j.y / val;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Matrix Properties
|
||||
MVec transform(const MVec& in) const {
|
||||
return MVec(i.x * in.x + i.y * in.y, j.x * in.y + j.y * in.x);
|
||||
}
|
||||
|
||||
Mat transform(const Mat& in) const {
|
||||
Mat out;
|
||||
out.i.x = i.x * in.i.x + j.x * in.i.y;
|
||||
out.i.y = i.y * in.i.x + j.y * in.i.y;
|
||||
out.j.x = i.x * in.j.x + j.x * in.j.y;
|
||||
out.j.y = i.y * in.j.x + j.y * in.j.y;
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat operator*(const Mat& in) {
|
||||
return transform(in);
|
||||
}
|
||||
|
||||
Mat& transpose() {
|
||||
swap(j.x, i.y);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Type det() {
|
||||
return i.x * j.y - i.y * j.x;
|
||||
}
|
||||
|
||||
Mat cofactors() {
|
||||
return Mat(j.y, -i.y, -j.x, i.x);
|
||||
}
|
||||
|
||||
Mat inv() {
|
||||
Type detV = det();
|
||||
DEBUG_ASSERT(detV != 0)
|
||||
return (cofactors() /= detV);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
using mat3 = Mat<Type, 3, 3>;
|
||||
using mat3f = mat3<halnf>;
|
||||
|
||||
template <typename Type>
|
||||
class Mat<Type, 3, 3> {
|
||||
typedef Vec3<Type> vec;
|
||||
|
||||
public:
|
||||
vec I;
|
||||
vec J;
|
||||
vec K;
|
||||
|
||||
public:
|
||||
Mat() = default;
|
||||
|
||||
explicit Mat(Type val) {
|
||||
I.assign(val, 0.f, 0.f);
|
||||
J.assign(0.f, val, 0.f);
|
||||
K.assign(0.f, 0.f, val);
|
||||
}
|
||||
|
||||
Mat(const vec& i, const vec& j, const vec& k) {
|
||||
I = i;
|
||||
J = j;
|
||||
K = k;
|
||||
}
|
||||
|
||||
Mat(const Mat& in) {
|
||||
this->I = in.I;
|
||||
this->J = in.J;
|
||||
this->K = in.K;
|
||||
}
|
||||
|
||||
void assign(const vec& i, const vec& j, const vec& k) {
|
||||
I = i;
|
||||
J = j;
|
||||
K = k;
|
||||
}
|
||||
|
||||
Mat& fillRandom() {
|
||||
I.randf();
|
||||
J.randf();
|
||||
K.randf();
|
||||
return *this;
|
||||
}
|
||||
|
||||
vec& operator[](alni i) {
|
||||
DEBUG_ASSERT(i < 3 && i >= 0)
|
||||
return (&I)[i];
|
||||
}
|
||||
|
||||
const vec& operator[](alni i) const {
|
||||
DEBUG_ASSERT(i < 3 && i >= 0)
|
||||
return (&I)[i];
|
||||
}
|
||||
|
||||
// create on stack
|
||||
Mat operator+(const Mat& in) { return Mat(I + in.I, J + in.J, K + in.K); }
|
||||
Mat operator-(const Mat& in) { return Mat(I - in.I, J - in.J, K - in.K); }
|
||||
Mat operator+(Type val) { return Mat(I + val, J + val, K + val); }
|
||||
Mat operator-(Type val) { return Mat(I - val, J - val, K - val); }
|
||||
Mat operator*(Type val) { return Mat(I * val, J * val, K * val); }
|
||||
Mat operator/(Type val) { return Mat(I / val, J / val, K / val); }
|
||||
|
||||
// write
|
||||
Mat& operator=(const Mat& in) {
|
||||
I = in.I;
|
||||
J = in.J;
|
||||
K = in.K;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator+=(const Mat& in) {
|
||||
I += in.I;
|
||||
J += in.J;
|
||||
K += in.K;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator-=(const Mat& in) {
|
||||
I -= in.I;
|
||||
J -= in.J;
|
||||
K -= in.K;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator+=(Type val) {
|
||||
I += val;
|
||||
J += val;
|
||||
K += val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator-=(Type val) {
|
||||
I -= val;
|
||||
J -= val;
|
||||
K -= val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator*=(Type val) {
|
||||
I *= val;
|
||||
J *= val;
|
||||
K *= val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat& operator/=(Type val) {
|
||||
I /= val;
|
||||
J /= val;
|
||||
K /= val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Matrix transformation
|
||||
vec transform(const vec& in) {
|
||||
return vec(
|
||||
I.x * in.x + I.y * in.y + I.z * in.z,
|
||||
J.x * in.x + J.y * in.y + J.z * in.z,
|
||||
K.x * in.x + K.y * in.y + K.z * in.z
|
||||
);
|
||||
}
|
||||
|
||||
Mat transform(const Mat& in) {
|
||||
return Mat(
|
||||
{(in.I.x * I.x + in.I.y * J.x + in.I.z * K.x), (in.I.x * I.y + in.I.y * J.y + in.I.z * K.y), (in.I.x * I.z + in.I.y * J.z + in.I.z * K.z)},
|
||||
{(in.J.x * I.x + in.J.y * J.x + in.J.z * K.x), (in.J.x * I.y + in.J.y * J.y + in.J.z * K.y), (in.J.x * I.z + in.J.y * J.z + in.J.z * K.z)},
|
||||
{(in.K.x * I.x + in.K.y * J.x + in.K.z * K.x), (in.K.x * I.y + in.K.y * J.y + in.K.z * K.y), (in.K.x * I.z + in.K.y * J.z + in.K.z * K.z)}
|
||||
);
|
||||
}
|
||||
|
||||
vec operator*(const vec& in) {
|
||||
return transform(in);
|
||||
}
|
||||
|
||||
Mat operator*(const Mat& in) {
|
||||
return transform(in);
|
||||
}
|
||||
|
||||
Mat<Type, 2, 2> minor(halni, halni) {
|
||||
Mat<Type, 2, 2> out;
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat& transpose() {
|
||||
swap(I.y, J.x);
|
||||
swap(I.z, K.x);
|
||||
swap(J.z, K.y);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Type det() {
|
||||
return (
|
||||
+I.x * (J.y * K.z - J.z * K.y)
|
||||
- I.y * (J.x * K.z - J.z * K.x)
|
||||
+ I.z * (J.x * K.y - J.y * K.x)
|
||||
);
|
||||
}
|
||||
|
||||
Mat cofactors() {
|
||||
return Mat(
|
||||
vec(+(J.y * K.z - J.z * K.y), -(I.y * K.z - I.z * K.y), +(I.y * J.z - I.z * J.y)),
|
||||
vec(-(J.x * K.z - J.z * K.x), +(I.x * K.z - I.z * K.x), -(I.x * J.z - I.z * J.x)),
|
||||
vec(+(J.x * K.y - J.y * K.x), -(I.x * K.y - I.y * K.x), +(I.x * J.y - I.y * J.x))
|
||||
);
|
||||
}
|
||||
|
||||
Mat inv() {
|
||||
return cofactors() /= det();
|
||||
}
|
||||
|
||||
Mat rotatorX(alnf angle) {
|
||||
alnf cosA = (alnf) cos(angle);
|
||||
alnf sinA = (alnf) sin(angle);
|
||||
return {
|
||||
{1, 0, 0},
|
||||
{0, cosA, -sinA},
|
||||
{0, sinA, cosA}
|
||||
};
|
||||
}
|
||||
|
||||
Mat rotatorY(alnf angle) {
|
||||
alnf cosA = (alnf) cos(angle);
|
||||
alnf sinA = (alnf) sin(angle);
|
||||
return {
|
||||
{cosA, 0, sinA},
|
||||
{0, 1, 0},
|
||||
{-sinA, 0, cosA}
|
||||
};
|
||||
}
|
||||
|
||||
Mat rotatorZ(alnf angle) {
|
||||
alnf cosA = (alnf) cos(angle);
|
||||
alnf sinA = (alnf) sin(angle);
|
||||
return {
|
||||
{cosA, -sinA, 0},
|
||||
{sinA, cosA, 0},
|
||||
{0, 0, 1}
|
||||
};
|
||||
}
|
||||
|
||||
static Mat rotatorDir(vec dir, alnf angle) {
|
||||
dir.normalize();
|
||||
|
||||
Mat out;
|
||||
alnf cosA = (alnf) cos(angle);
|
||||
alnf sinA = (alnf) sin(angle);
|
||||
alnf tmp = 1 - cosA;
|
||||
|
||||
out.I.x = (Type) (cosA + dir.x * dir.x * tmp);
|
||||
out.I.y = (Type) (dir.x * dir.y * tmp - dir.z * sinA);
|
||||
out.I.z = (Type) (dir.x * dir.z * tmp + dir.y * sinA);
|
||||
|
||||
out.J.x = (Type) (dir.y * dir.x * tmp + dir.z * sinA);
|
||||
out.J.y = (Type) (cosA + dir.y * dir.y * tmp);
|
||||
out.J.z = (Type) (dir.y * dir.z * tmp - dir.x * sinA);
|
||||
|
||||
out.K.x = (Type) (dir.z * dir.x * tmp - dir.y * sinA);
|
||||
out.K.y = (Type) (dir.z * dir.y * tmp + dir.x * sinA);
|
||||
out.K.z = (Type) (cosA + dir.z * dir.z * tmp);
|
||||
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type >
|
||||
using Mat4 = Mat<Type, 4, 4>;
|
||||
|
||||
using Mat4F = Mat4<halnf>;
|
||||
using Mat4I = Mat4<halni>;
|
||||
|
||||
template <typename Type >
|
||||
class Mat< Type, 0, 0 > {
|
||||
typedef Vec<Type, 1> MVec;
|
||||
MVec dummy;
|
||||
|
||||
public:
|
||||
MVec& operator[](alni) {
|
||||
return dummy;
|
||||
}
|
||||
|
||||
const MVec& operator[](alni) const {
|
||||
return dummy;
|
||||
}
|
||||
|
||||
Type det() {
|
||||
return Type();
|
||||
}
|
||||
};
|
||||
}
|
||||
28
Math/public/MathCommon.hpp
Normal file
28
Math/public/MathCommon.hpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "Utils.hpp"
|
||||
|
||||
#define EPSILON 0.0000001
|
||||
|
||||
#define PI double(3.1415926535897932384626433832795)
|
||||
#define PI2 (PI * 2)
|
||||
#define PI13 (PI / 3)
|
||||
#define PI23 (PI2 / 3)
|
||||
#define PI43 (2 * PI2 / 3)
|
||||
|
||||
#define SQRT2 1.4142135623730950488016887242
|
||||
#define EXP 2.7182818284590452353602874714
|
||||
|
||||
namespace tp {
|
||||
extern ModuleManifest gModuleMath;
|
||||
|
||||
alnf sin(alnf radians);
|
||||
alnf tan(alnf radians);
|
||||
alnf atan2(alnf X, alnf Y);
|
||||
alnf atan(alnf val);
|
||||
alnf cos(alnf radians);
|
||||
alnf acos(alnf val);
|
||||
alnf sqrt(alnf val);
|
||||
alnf rad(alnf val);
|
||||
alnf deg(alnf val);
|
||||
}
|
||||
20
Math/public/Ray.hpp
Normal file
20
Math/public/Ray.hpp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include "Vec.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
class Ray {
|
||||
public:
|
||||
Ray(const Vec3F& Dir, const Vec3F& Pos);
|
||||
Ray() = default;
|
||||
|
||||
public:
|
||||
Vec3F dir;
|
||||
Vec3F pos;
|
||||
|
||||
public:
|
||||
~Ray() = default;
|
||||
};
|
||||
|
||||
}
|
||||
274
Math/public/Rect.hpp
Normal file
274
Math/public/Rect.hpp
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Vec.hpp"
|
||||
|
||||
#include "Intersections.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
template <typename Type> class Rect;
|
||||
using RectF = Rect<halnf>;
|
||||
using RectI = Rect<halni>;
|
||||
|
||||
template <typename Type>
|
||||
class Rect {
|
||||
public:
|
||||
Rect() {}
|
||||
|
||||
explicit Rect(Type val) {
|
||||
this->pos = val;
|
||||
this->size = val;
|
||||
}
|
||||
|
||||
template <typename ConversionType>
|
||||
explicit Rect(const Rect<ConversionType>& rec) {
|
||||
this->pos = rec.pos;
|
||||
this->size = rec.size;
|
||||
}
|
||||
|
||||
Rect(const Vec2<Type>& pos, const Vec2<Type>& size) {
|
||||
this->pos = pos;
|
||||
this->size = size;
|
||||
}
|
||||
|
||||
Rect(Type aPosX, Type posy, Type aSizeX, Type aSizeY) {
|
||||
pos.assign(aPosX, posy);
|
||||
size.assign(aSizeX, aSizeY);
|
||||
}
|
||||
|
||||
// assign
|
||||
template <typename InType>
|
||||
Rect<Type>& assign(InType p1x, InType p1y, InType p2x, InType p2y) {
|
||||
pos.assign(p1x, p1y);
|
||||
size.assign(p2x, p2y);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// assign
|
||||
template <typename InType>
|
||||
Rect<Type>& assign(const Vec2<InType>& pos, const Vec2<InType>& size) {
|
||||
this->pos.assign(pos.x, pos.y);
|
||||
this->size.assign(size.x, size.y);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// conversion
|
||||
template <typename ConversionType>
|
||||
Rect<Type>& operator=(const Rect<ConversionType>& rect) {
|
||||
pos = rect.pos;
|
||||
size = rect.size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(Rect<Type>& rect) const {
|
||||
return (pos == rect.pos && size == rect.size);
|
||||
}
|
||||
|
||||
bool isEnclosedIn(const Rect<Type>& rect, bool aParent = false) const {
|
||||
if (aParent) {
|
||||
return (pos.x + size.x <= rect.size.x && pos.y + size.y <= rect.size.y &&
|
||||
pos.x >= 0 && pos.y >= 0);
|
||||
}
|
||||
*(Vec2<Type>*)(&pos) -= rect.pos;
|
||||
bool ret = this->isEnclosedIn(rect, true);
|
||||
*(Vec2<Type>*)(&pos) += rect.pos;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void calcIntersection(Rect<Type>& in, Rect<Type>& out) const {
|
||||
if (isOverlap(in)) {
|
||||
out = *this;
|
||||
for (char i = 0; i < 2; i++) {
|
||||
clamp(out.pos[i], in.pos[i], in.pos[i] + in.size[i]);
|
||||
Type p2 = pos[i] + size[i];
|
||||
clamp(p2, in.pos[i], in.pos[i] + in.size[i]);
|
||||
out.size[i] = p2 - out.pos[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
out.size.assign(0, 0);
|
||||
out.pos.assign(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// argument isInside
|
||||
bool isInside(const Vec2<Type>& p) const {
|
||||
return (p.each_compre(pos) && (pos + size).each_compre(p));
|
||||
}
|
||||
|
||||
bool isInside(Type x, Type y) const {
|
||||
return (pos.x < x&& pos.y < y&& pos.x + size.x > x&& pos.y + size.y > y);
|
||||
}
|
||||
|
||||
inline Vec2<Type> sizeVec() const {
|
||||
return Vec2<Type>(size.x, size.y);
|
||||
}
|
||||
|
||||
inline Vec2<Type> sizeVecW() const {
|
||||
return Vec2<Type>(size.x + pos.x, size.y + pos.y);
|
||||
}
|
||||
|
||||
void invertY(Type scr_y) {
|
||||
pos.y = scr_y - pos.y - size.y;
|
||||
}
|
||||
|
||||
void move(Type dx, Type dy) {
|
||||
pos.x += dx;
|
||||
pos.y += dy;
|
||||
}
|
||||
|
||||
Rect<Type>& scaleFromCenter(tp::halnf fac, bool add = false) {
|
||||
if (add) {
|
||||
pos += fac;
|
||||
size -= fac * 2;
|
||||
}
|
||||
else {
|
||||
auto new_size = size * fac;
|
||||
pos = pos - (new_size - size) / 2;
|
||||
size = new_size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec2<Type> p1() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
Vec2<Type> p3() {
|
||||
return pos + size;
|
||||
}
|
||||
|
||||
Vec2<Type> p2() {
|
||||
return { pos.x, pos.y + size.y };
|
||||
}
|
||||
|
||||
Vec2<Type> p4() {
|
||||
return { pos.x + size.x, pos.y };
|
||||
}
|
||||
|
||||
inline bool isAbove(const Rect<Type>& rect) const {
|
||||
return (pos.y + size.y < rect.pos.y);
|
||||
}
|
||||
|
||||
inline bool isBellow(const Rect<Type>& rect) const {
|
||||
return (rect.pos.y + rect.size.y < pos.y);
|
||||
}
|
||||
|
||||
inline bool isRight(const Rect<Type>& rect) const {
|
||||
return (pos.x + size.x < rect.pos.x);
|
||||
}
|
||||
|
||||
inline bool isLeft(const Rect<Type>& rect) const {
|
||||
return (rect.pos.x + rect.size.x < pos.x);
|
||||
}
|
||||
|
||||
inline bool isIntersectsY(const Rect<Type>& in) const {
|
||||
if (INRANGE(in.pos.x, pos.x, pos.x + size.x)) return true;
|
||||
if (INRANGE(pos.x, in.pos.x, in.pos.x + in.size.x)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool isIntersectX(const Rect<Type>& rect) const {
|
||||
if (INRANGE(rect.pos.y, pos.y, pos.y + size.y)) return true;
|
||||
if (INRANGE(pos.y, rect.pos.y, rect.pos.y + rect.size.y)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isOverlap(const Rect<Type>& rect) const {
|
||||
return (isIntersectX(rect) && isIntersectsY(rect));
|
||||
}
|
||||
|
||||
void clamp(const Rect<Type>& bounds) {
|
||||
Vec2<Type> p3(pos + size);
|
||||
Vec2<Type> max = bounds.pos + bounds.size;
|
||||
|
||||
pos.clamp(bounds.pos, max);
|
||||
p3.clamp(bounds.pos, max);
|
||||
|
||||
size = p3 - pos;
|
||||
}
|
||||
|
||||
// if only one point isInside
|
||||
bool clampOutside(Vec2<Type>& v1, Vec2<Type>& v2) {
|
||||
bool const in1 = isInside(v1);
|
||||
bool const in2 = isInside(v2);
|
||||
if (!in1 && !in2) return false;
|
||||
|
||||
if (in1) {
|
||||
if (!intersectLines2D(p2(), p3(), v1, v2, &v1)) {
|
||||
if (!intersectLines2D(p1(), p4(), v1, v2, &v1)) {
|
||||
if (!intersectLines2D(p1(), p2(), v1, v2, &v1)) {
|
||||
intersectLines2D(p3(), p4(), v1, v2, &v1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!intersectLines2D(p2(), p3(), v1, v2, &v2)) {
|
||||
if (!intersectLines2D(p1(), p4(), v1, v2, &v2)) {
|
||||
if (!intersectLines2D(p1(), p2(), v1, v2, &v2)) {
|
||||
intersectLines2D(p3(), p4(), v1, v2, &v2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uhalni clampInside(Vec2<Type>& v1, Vec2<Type>& v2) {
|
||||
bool const in1 = isInside(v1);
|
||||
bool const in2 = isInside(v2);
|
||||
|
||||
if (in1 && in2) return 2;
|
||||
|
||||
Vec2<Type> v1copy = v1;
|
||||
Vec2<Type> v2copy = v2;
|
||||
|
||||
if (in1 || in2) {
|
||||
if (!intersectLines2D(p2(), p3(), v1copy, v2copy, &v2)) {
|
||||
if (!intersectLines2D(p1(), p4(), v1copy, v2copy, &v2)) {
|
||||
if (!intersectLines2D(p1(), p2(), v1copy, v2copy, &v2)) {
|
||||
intersectLines2D(p3(), p4(), v1copy, v2copy, &v2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUG_ASSERT(0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename ConversionType>
|
||||
Rect<Type> operator*(ConversionType val) {
|
||||
Rect<Type> out;
|
||||
out.pos = pos * val;
|
||||
out.size = size * val;
|
||||
return out;
|
||||
}
|
||||
|
||||
Vec2<Type> center() {
|
||||
return pos + size / 2.f;
|
||||
}
|
||||
|
||||
public:
|
||||
union {
|
||||
Vec2<Type> v1;
|
||||
Vec2<Type> pos;
|
||||
struct {
|
||||
Type x;
|
||||
Type y;
|
||||
};
|
||||
};
|
||||
|
||||
union {
|
||||
Vec2<Type> v2;
|
||||
Vec2<Type> size;
|
||||
struct {
|
||||
Type z;
|
||||
Type w;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
48
Math/public/Topology.hpp
Normal file
48
Math/public/Topology.hpp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
#include "Camera.hpp"
|
||||
#include "Buffer.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
class TrigCache {
|
||||
static Vec3F gHitPos;
|
||||
|
||||
public:
|
||||
ualni mP1, mP2, mP3;
|
||||
Vec3F mEdgeP1P2, mEdgeP1P3;
|
||||
Vec3F mNormal;
|
||||
Vec3F mOrigin;
|
||||
|
||||
public:
|
||||
TrigCache();
|
||||
TrigCache(const TrigCache& in);
|
||||
TrigCache(ualni v1, ualni v2, ualni v3);
|
||||
|
||||
public:
|
||||
static const Vec3F& getHitPos() ;
|
||||
[[nodiscard]] const Vec3F& getNormal() const;
|
||||
|
||||
public:
|
||||
void updateCache(const Buffer<Vec3F>& points);
|
||||
[[nodiscard]] bool castRay(const Ray& ray) const;
|
||||
};
|
||||
|
||||
class Topology {
|
||||
mat3f mBasis;
|
||||
Vec3F mOrigin;
|
||||
|
||||
Buffer<Vec3F> mPoints;
|
||||
Buffer<Vec3F> mPointsTransformed;
|
||||
Buffer<TrigCache> mTrigCaches;
|
||||
|
||||
public:
|
||||
Topology() = default;
|
||||
~Topology() = default;
|
||||
|
||||
public:
|
||||
void addTrig(const Vec3F& v1, const Vec3F& v2, const Vec3F& v3);
|
||||
void transformPoint(Vec3F& vert);
|
||||
void updateTransformed();
|
||||
};
|
||||
}
|
||||
25
Math/public/Trig.hpp
Normal file
25
Math/public/Trig.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "Vec.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
class Trig {
|
||||
public:
|
||||
Trig();
|
||||
Trig(const Vec3F& v0, const Vec3F& v1, const Vec3F& v2);
|
||||
|
||||
public:
|
||||
Vec3F p1;
|
||||
Vec3F p2;
|
||||
Vec3F p3;
|
||||
|
||||
public:
|
||||
void assign(const Vec3F& v0, const Vec3F& v1, const Vec3F& v2);
|
||||
void normal(Vec3F& dir) const;
|
||||
bool rayHit(class Ray& ray, Vec3F& HitPos) const;
|
||||
|
||||
public:
|
||||
~Trig();
|
||||
};
|
||||
}
|
||||
649
Math/public/Vec.hpp
Normal file
649
Math/public/Vec.hpp
Normal file
|
|
@ -0,0 +1,649 @@
|
|||
#pragma once
|
||||
|
||||
#include "MathCommon.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
template <typename Type, const ualni tSize>
|
||||
class Vec {
|
||||
typedef SelCopyArg<Type> TypeArg;
|
||||
|
||||
private:
|
||||
Type mBuff[tSize];
|
||||
|
||||
inline const Type& get(ualni i) const { return mBuff[i]; }
|
||||
inline Type& get(ualni i) { return mBuff[i]; }
|
||||
inline Type& set(ualni i, TypeArg arg) { return mBuff[i] = arg; }
|
||||
|
||||
public:
|
||||
|
||||
Vec() {
|
||||
MODULE_SANITY_CHECK(gModuleMath)
|
||||
}
|
||||
|
||||
Vec(TypeArg val) {
|
||||
assign(val);
|
||||
}
|
||||
|
||||
Vec(TypeArg val1, TypeArg val2, TypeArg val3, TypeArg val4) {
|
||||
static_assert(tSize == 4);
|
||||
mBuff[0] = val1;
|
||||
mBuff[1] = val2;
|
||||
mBuff[2] = val3;
|
||||
mBuff[3] = val4;
|
||||
}
|
||||
|
||||
Vec(TypeArg val1, TypeArg val2, TypeArg val3, TypeArg val4, TypeArg val5) {
|
||||
static_assert(tSize == 5);
|
||||
mBuff[0] = val1;
|
||||
mBuff[1] = val2;
|
||||
mBuff[2] = val3;
|
||||
mBuff[3] = val4;
|
||||
mBuff[4] = val5;
|
||||
}
|
||||
|
||||
Vec(TypeArg val1, TypeArg val2, TypeArg val3, TypeArg val4, TypeArg val5, TypeArg val6) {
|
||||
static_assert(tSize == 6);
|
||||
mBuff[0] = val1;
|
||||
mBuff[1] = val2;
|
||||
mBuff[2] = val3;
|
||||
mBuff[3] = val4;
|
||||
mBuff[4] = val5;
|
||||
mBuff[5] = val6;
|
||||
}
|
||||
|
||||
Vec(const Vec& in) {
|
||||
memcp(mBuff, in.mBuff, sizeof(Type) * tSize);
|
||||
}
|
||||
|
||||
Type& operator[](ualni i) {
|
||||
DEBUG_ASSERT(i < tSize && i >= 0)
|
||||
return mBuff[i];
|
||||
}
|
||||
|
||||
const Type& operator[](ualni i) const {
|
||||
DEBUG_ASSERT(i < tSize && i >= 0)
|
||||
return mBuff[i];
|
||||
}
|
||||
|
||||
Vec operator-() {
|
||||
Vec out;
|
||||
for (halni i = 0; i < tSize; i++) {
|
||||
out.get(i) = -get(i);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// write
|
||||
Vec& operator+=(const Vec& val) {
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
get(i) += val[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec& operator-=(const Vec& val) {
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
get(i) -= val[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec& operator+=(Type val) {
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
get(i) += val;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec& operator-=(Type val) {
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
get(i) -= val;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec& operator*=(Type val) {
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
get(i) *= val;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec& operator/=(Type val) {
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
get(i) /= val;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void assign(Type val) {
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
get(i) = val;
|
||||
}
|
||||
}
|
||||
|
||||
// create on stack
|
||||
Vec operator+(const Vec& in) const {
|
||||
Vec out;
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
out[i] = in[i] + get(i);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Vec operator-(const Vec& in) const {
|
||||
Vec out;
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
out[i] = in[i] - get(i);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Vec operator+(Type val) const {
|
||||
Vec out;
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
out[i] = get(i) + val;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Vec operator-(Type val) const {
|
||||
Vec out;
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
out[i] = get(i) - val;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Vec operator*(Type val) const {
|
||||
Vec out;
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
out[i] = get(i) * val;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Vec operator/(Type val) const {
|
||||
Vec out;
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
out[i] = get(i) / val;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Vector Properties
|
||||
Type dot(const Vec& in) const {
|
||||
Type out = 0;
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
out += get(i) * in.get(i);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Type operator*(const Vec& in) const {
|
||||
return dot(in);
|
||||
}
|
||||
|
||||
alnf length2() const {
|
||||
alnf sum = 0;
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
Type val = get(i);
|
||||
sum += val * val;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
alnf length() const {
|
||||
return sqrt(length2());
|
||||
}
|
||||
|
||||
Vec& normalize() {
|
||||
operator/=((Type) length());
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec unitV() {
|
||||
return Vec(*this).normalize();
|
||||
}
|
||||
|
||||
// Comparisons
|
||||
bool operator>(const Vec& in) const { return this->length2() > in.length2(); }
|
||||
bool operator<(const Vec& in) const { return this->length2() < in.length2(); }
|
||||
bool operator>=(const Vec& in) const { return this->length2() >= in.length2(); }
|
||||
bool operator<=(const Vec& in) const { return this->length2() <= in.length2(); }
|
||||
|
||||
bool operator==(const Vec& in) const {
|
||||
for (ualni i = 0; i < tSize; i++) {
|
||||
if (get(i) != in.get(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const Vec& in) const {
|
||||
return !operator==(in);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
using Vec2 = Vec<Type, 2>;
|
||||
|
||||
using Vec2F = Vec<halnf, 2>;
|
||||
using Vec2I = Vec<halni, 2>;
|
||||
|
||||
template <typename Type>
|
||||
class Vec<Type, 2> {
|
||||
|
||||
public:
|
||||
Type x;
|
||||
Type y;
|
||||
|
||||
Vec() : x(0), y(0) {}
|
||||
|
||||
// Initialization
|
||||
template <typename TypeIn>
|
||||
Vec(TypeIn aX, TypeIn aY) {
|
||||
x = (Type) aX;
|
||||
y = (Type) aY;
|
||||
}
|
||||
|
||||
template <typename TypeIn>
|
||||
Vec(TypeIn Vec[2]) {
|
||||
x = (Type) Vec[0];
|
||||
y = (Type) Vec[1];
|
||||
}
|
||||
|
||||
template <typename TypeIn>
|
||||
Vec(TypeIn val) {
|
||||
x = y = (Type) val;
|
||||
}
|
||||
|
||||
template <typename TypeIn>
|
||||
Vec(Vec<TypeIn, 2>& Vec) {
|
||||
x = (Type) Vec.x;
|
||||
y = (Type) Vec.y;
|
||||
}
|
||||
|
||||
template <typename TypeIn>
|
||||
void assign(TypeIn aX, TypeIn aY) {
|
||||
x = (Type) aX;
|
||||
y = (Type) aY;
|
||||
}
|
||||
|
||||
template <typename TypeIn>
|
||||
void assign(const Vec<TypeIn, 2>& in) {
|
||||
x = (Type) in.x;
|
||||
y = (Type) in.y;
|
||||
}
|
||||
|
||||
template <typename TypeIn>
|
||||
void assign(TypeIn in[2]) {
|
||||
x = (Type) in[0];
|
||||
y = (Type) in[1];
|
||||
}
|
||||
|
||||
template <typename TypeIn>
|
||||
Vec& operator=(TypeIn val) {
|
||||
x = y = (Type) val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Conversion
|
||||
template <typename TypeIn>
|
||||
Vec& operator=(const Vec<TypeIn, 2>& in) {
|
||||
x = (Type) in.x;
|
||||
y = (Type) in.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// create on stack
|
||||
Vec2<Type> operator+(const Vec2<Type>& in) const { return Vec2<Type>(x + in.x, y + in.y); }
|
||||
Vec2<Type> operator-(const Vec2<Type>& in) const { return Vec2<Type>(x - in.x, y - in.y); }
|
||||
Vec2<Type> operator+(Type val) const { return Vec2<Type>(x + val, y + val); }
|
||||
Vec2<Type> operator-(Type val) const { return Vec2<Type>(x - val, y - val); }
|
||||
Vec2<Type> operator*(Type val) const { return Vec2<Type>(x * val, y * val); }
|
||||
Vec2<Type> operator/(Type val) const { return Vec2<Type>(x / val, y / val); }
|
||||
|
||||
// write
|
||||
void operator-=(Type val) {
|
||||
x -= val;
|
||||
y -= val;
|
||||
}
|
||||
|
||||
void operator+=(Type val) {
|
||||
x += val;
|
||||
y += val;
|
||||
}
|
||||
|
||||
void operator-=(const Vec2<Type>& Vec) {
|
||||
x -= Vec.x;
|
||||
y -= Vec.y;
|
||||
}
|
||||
|
||||
void operator+=(const Vec2<Type>& Vec) {
|
||||
x += Vec.x;
|
||||
y += Vec.y;
|
||||
}
|
||||
|
||||
void operator*=(Type val) {
|
||||
x *= val;
|
||||
y *= val;
|
||||
}
|
||||
|
||||
void operator/=(Type val) {
|
||||
x /= val;
|
||||
y /= val;
|
||||
}
|
||||
|
||||
void operator/=(const Vec2<Type>& in) {
|
||||
x /= in.x;
|
||||
y /= in.y;
|
||||
}
|
||||
|
||||
void operator*=(const Vec2<Type>& in) {
|
||||
x *= in.x;
|
||||
y *= in.y;
|
||||
}
|
||||
|
||||
bool compareEach(const Vec& in) const { return (x > in.x && y > in.y); }
|
||||
|
||||
bool operator>(const Vec& in) const { return length2() > in.length2(); }
|
||||
bool operator<(const Vec& in) const { return length2() < in.length2(); }
|
||||
bool operator>=(const Vec& in) const { return length2() >= in.length2(); }
|
||||
bool operator<=(const Vec& in) const { return length2() <= in.length2(); }
|
||||
bool operator==(const Vec& in) const { return (x == in.x && y == in.y); }
|
||||
bool operator!=(const Vec& in) const { return (x != in.x || y != in.y); }
|
||||
|
||||
Type& operator[](bool axes) { return (&x)[axes]; }
|
||||
|
||||
const Type& operator[](bool axes) const { return (&x)[axes]; }
|
||||
|
||||
// Vector Properties
|
||||
alnf operator*(const Vec& in) const {
|
||||
return dot(in);
|
||||
}
|
||||
|
||||
alnf dot(const Vec& in) const {
|
||||
return (x * in.x + y * in.y);
|
||||
}
|
||||
|
||||
Vec unitV() const {
|
||||
return Vec(*this / (Type) this->length());
|
||||
}
|
||||
|
||||
void normalize() {
|
||||
*this /= (Type) length();
|
||||
}
|
||||
|
||||
Vec normal() {
|
||||
return { -y, x };
|
||||
}
|
||||
|
||||
alnf length2() const {
|
||||
return (x * x + y * y);
|
||||
}
|
||||
|
||||
alnf length() const {
|
||||
Type const tmp = (Type) (x * x + y * y);
|
||||
return sqrt(tmp);
|
||||
}
|
||||
|
||||
// Vector Transformation
|
||||
void Rot(float cosA, float sinA) {
|
||||
Type tmp = x;
|
||||
x = x * cosA - y * sinA;
|
||||
y = tmp * sinA + y * cosA;
|
||||
}
|
||||
|
||||
void clamp(const Vec& min, const Vec& max) {
|
||||
tp::clamp(x, min.x, max.x);
|
||||
tp::clamp(y, min.y, max.y);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
using Vec3 = Vec<Type, 3>;
|
||||
|
||||
using Vec3F = Vec3<halnf>;
|
||||
using Vec3I = Vec3<halni>;
|
||||
|
||||
template <typename Type>
|
||||
class Vec<Type, 3> {
|
||||
|
||||
public:
|
||||
|
||||
Type x;
|
||||
Type y;
|
||||
Type z;
|
||||
|
||||
// Initialization
|
||||
Vec() {}
|
||||
|
||||
Vec(const Vec<Type, 4>& in) {
|
||||
x = in[0];
|
||||
y = in[1];
|
||||
z = in[2];
|
||||
}
|
||||
|
||||
Vec(Type aX, Type aY, Type aZ) {
|
||||
x = aX;
|
||||
y = aY;
|
||||
z = aZ;
|
||||
}
|
||||
|
||||
Vec(Type Vec[3]) {
|
||||
x = Vec[0];
|
||||
y = Vec[1];
|
||||
z = Vec[2];
|
||||
}
|
||||
|
||||
Vec(Type x) {
|
||||
assign(x);
|
||||
}
|
||||
|
||||
Vec(const Vec& Vec) {
|
||||
x = Vec.x;
|
||||
y = Vec.y;
|
||||
z = Vec.z;
|
||||
}
|
||||
|
||||
void assign(Type aX, Type aY, Type aZ) {
|
||||
x = aX;
|
||||
y = aY;
|
||||
z = aZ;
|
||||
}
|
||||
|
||||
void assign(const Vec& in) {
|
||||
x = in.x;
|
||||
y = in.y;
|
||||
z = in.z;
|
||||
}
|
||||
|
||||
void assign(Type val) {
|
||||
x = val;
|
||||
y = val;
|
||||
z = val;
|
||||
}
|
||||
|
||||
Vec& operator=(const Vec& in) {
|
||||
x = in.x;
|
||||
y = in.y;
|
||||
z = in.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec& operator=(const Type* in) {
|
||||
x = in[0];
|
||||
y = in[1];
|
||||
z = in[2];
|
||||
return *this;
|
||||
}
|
||||
|
||||
Type& operator[](alni i) {
|
||||
DEBUG_ASSERT(i < 3 && i >= 0)
|
||||
return (&x)[i];
|
||||
}
|
||||
|
||||
const Type& operator[](alni i) const {
|
||||
DEBUG_ASSERT(i < 3 && i >= 0)
|
||||
return (&x)[i];
|
||||
}
|
||||
|
||||
// create on stack
|
||||
Vec operator+(const Vec& in) const {
|
||||
return Vec(x + in.x, y + in.y, z + in.z);
|
||||
}
|
||||
|
||||
Vec operator-(const Vec& in) const {
|
||||
return Vec(x - in.x, y - in.y, z - in.z);
|
||||
}
|
||||
|
||||
Vec operator+(Type val) const {
|
||||
return Vec(x + val, y + val, z + val);
|
||||
}
|
||||
|
||||
Vec operator-(Type val) const {
|
||||
return Vec(x - val, y - val, z - val);
|
||||
}
|
||||
|
||||
Vec operator*(Type val) const {
|
||||
return Vec(x * val, y * val, z * val);
|
||||
}
|
||||
|
||||
Vec operator/(Type val) const {
|
||||
return Vec(x / val, y / val, z / val);
|
||||
}
|
||||
|
||||
|
||||
// compare
|
||||
bool operator>(const Vec& Vec) const {
|
||||
return length2() > Vec.length2();
|
||||
}
|
||||
|
||||
bool operator<(const Vec& Vec) const {
|
||||
return length2() < Vec.length2();
|
||||
}
|
||||
|
||||
bool operator>=(const Vec& Vec) const {
|
||||
return length2() >= Vec.length2();
|
||||
}
|
||||
|
||||
bool operator<=(const Vec& Vec) const {
|
||||
return length2() <= Vec.length2();
|
||||
}
|
||||
|
||||
bool operator==(const Vec& Vec) const {
|
||||
return (x == Vec.x && y == Vec.y && z == Vec.z);
|
||||
}
|
||||
|
||||
// write
|
||||
Vec operator-() {
|
||||
return Vec(-x, -y, -z);
|
||||
}
|
||||
|
||||
void operator -= (Type val) {
|
||||
x -= val;
|
||||
y -= val;
|
||||
z -= val;
|
||||
}
|
||||
|
||||
void operator += (Type val) {
|
||||
x += val;
|
||||
y += val;
|
||||
z += val;
|
||||
}
|
||||
|
||||
void operator -= (const Vec& in) {
|
||||
x -= in.x;
|
||||
y -= in.y;
|
||||
z -= in.z;
|
||||
}
|
||||
|
||||
void operator += (const Vec& in) {
|
||||
x += in.x;
|
||||
y += in.y;
|
||||
z += in.z;
|
||||
}
|
||||
|
||||
void operator *= (Type val) {
|
||||
x *= val;
|
||||
y *= val;
|
||||
z *= val;
|
||||
}
|
||||
|
||||
void operator /= (Type val) {
|
||||
x /= val;
|
||||
y /= val;
|
||||
z /= val;
|
||||
}
|
||||
|
||||
// Vector Properties
|
||||
Type dot(const Vec& in) const {
|
||||
return (x * in.x + y * in.y + z * in.z);
|
||||
}
|
||||
|
||||
alnf length() const {
|
||||
return sqrt((halnf) (x * x + y * y + z * z));
|
||||
}
|
||||
|
||||
Type length2() const {
|
||||
return (x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
Vec unitV() const {
|
||||
return *this / (Type) this->length();
|
||||
}
|
||||
|
||||
Vec& normalize() {
|
||||
*this /= (Type) this->length();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec cross(const Vec& in) const {
|
||||
return Vec(
|
||||
y * in.z - z * in.y,
|
||||
z * in.x - x * in.z,
|
||||
x * in.y - y * in.x
|
||||
);
|
||||
}
|
||||
|
||||
Vec operator*(const Vec& in) const {
|
||||
return cross(in);
|
||||
}
|
||||
|
||||
// Vector Transformation
|
||||
void rotZ(alnf cosA, alnf sinA) {
|
||||
Type tmp = x;
|
||||
x = (Type) (x * cosA - y * sinA);
|
||||
y = (Type) (tmp * sinA + y * cosA);
|
||||
}
|
||||
|
||||
void rotY(float cosA, float sinA) {
|
||||
Type tmp = x;
|
||||
x = (Type) (x * cosA - z * sinA);
|
||||
z = (Type) (tmp * sinA + z * cosA);
|
||||
}
|
||||
|
||||
void rotX(float cosA, float sinA) {
|
||||
Type tmp = y;
|
||||
y = (Type) (y * cosA - z * sinA);
|
||||
z = (Type) (tmp * sinA + z * cosA);
|
||||
}
|
||||
|
||||
halnf angelX() const {
|
||||
return (halnf) atan2(y, z);
|
||||
}
|
||||
|
||||
halnf angelY() const {
|
||||
return (halnf) atan2(x, z);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
using Vec4 = Vec<Type, 4>;
|
||||
|
||||
using Vec4F = Vec4<halnf>;
|
||||
using Vec4I = Vec4<halni>;
|
||||
}
|
||||
14
Math/tests/TestCommon.cpp
Normal file
14
Math/tests/TestCommon.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
#include "Testing.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace tp;
|
||||
|
||||
TEST_DEF_STATIC(Simple) {
|
||||
|
||||
}
|
||||
|
||||
TEST_DEF(Math) {
|
||||
testSimple();
|
||||
}
|
||||
26
Math/tests/Tests.cpp
Normal file
26
Math/tests/Tests.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
#include "Testing.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
static bool init(const tp::ModuleManifest* self) {
|
||||
tp::gTesting.setRootName(self->getName());
|
||||
return true;
|
||||
}
|
||||
|
||||
void testMath();
|
||||
|
||||
int main() {
|
||||
|
||||
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, nullptr };
|
||||
tp::ModuleManifest testModule("ContainersTest", init, nullptr, deps);
|
||||
|
||||
if (!testModule.initialize()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
testMath();
|
||||
|
||||
testModule.deinitialize();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue