#ifndef VECMATH_H
#define VECMATH_H
#include <cmath>
#include <cstdlib>
#include <stdexcept>
namespace bex {
public:
Vec2(
float _x,
float _y) :
ILBVec2(_x, _y) {}
Vec2() {}
};
public:
Vec3(
float _x,
float _y,
float _z) :
ILBVec3(_x, _y, _z) {}
Vec3() :
ILBVec3(0.0f, 0.0f, 0.0f) {}
const Vec3& operator+=(const Vec3& v) {
this->x += v.x;
this->y += v.y;
this->z += v.z;
return *this;
}
};
inline Vec3 cross(const Vec3& v1, const Vec3& v2) {
return Vec3(v1.y*v2.z - v1.z*v2.y,
v1.z*v2.x - v1.x*v2.z,
v1.x*v2.y - v1.y*v2.x);
}
inline float dot(const Vec3& v1, const Vec3& v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
inline Vec3 operator+(const Vec3& v1, const Vec3& v2) {
return Vec3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}
inline Vec3 operator-(const Vec3& v1, const Vec3& v2) {
return Vec3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}
inline Vec3 operator*(const Vec3& v, float f) {
return Vec3(v.x * f,
v.y * f,
v.z * f);
}
inline Vec3 operator-(const Vec3& v) {
return Vec3(-v.x,
-v.y,
-v.z);
}
inline Vec3 normalize(const Vec3& v1) {
float lenRec = 1.0f / sqrtf(dot(v1, v1));
return v1 * lenRec;
}
public:
void setColumn(const Vec3& v, int col) {
if(col < 0 || col > 3) {
throw std::runtime_error("Invalid matrix column");
}
m[col] = v.x;
m[col + 4] = v.y;
m[col + 8] = v.z;
}
void setRow(const Vec3& v, int row) {
if(row < 0 || row > 3) {
throw std::runtime_error("Invalid matrix row");
}
m[row * 4] = v.x;
m[row * 4 + 1] = v.y;
m[row * 4 + 2] = v.z;
}
};
inline Matrix4x4 identity() {
Matrix4x4 result;
for(int i = 0; i < 16; ++i) {
if((i&3) == (i / 4)) {
result.m[i] = 1.0f;
} else {
result.m[i] = 0.0f;
}
}
return result;
}
inline Matrix4x4 translation(const Vec3& pos) {
Matrix4x4 result = identity();
result.m[3] = pos.x;
result.m[7] = pos.y;
result.m[11] = pos.z;
return result;
}
inline Matrix4x4 scale(const Vec3& scale) {
Matrix4x4 result = identity();
result.m[0] = scale.x;
result.m[5] = scale.y;
result.m[10] = scale.z;
return result;
}
inline Matrix4x4 operator*(const Matrix4x4& m1, const Matrix4x4& m2) {
Matrix4x4 result;
for(int i = 0; i < 4; ++i) {
for(int j = 0; j < 4; ++j) {
result.m[i * 4 + j] = 0.0f;
for(int k = 0; k < 4; ++k) {
result.m[i * 4 + j] += m1.m[i * 4 + k] * m2.m[k * 4 + j];
}
}
}
return result;
}
inline Vec3 mulPoint(const Matrix4x4& m, const Vec3& p) {
return Vec3(m.m[0 + 0] * p.x + m.m[0 + 1] * p.y + m.m[0 + 2] * p.z + m.m[0 + 3],
m.m[4 + 0] * p.x + m.m[4 + 1] * p.y + m.m[4 + 2] * p.z + m.m[4 + 3],
m.m[8 + 0] * p.x + m.m[8 + 1] * p.y + m.m[8 + 2] * p.z + m.m[8 + 3]);
}
inline Vec3 mulVec(const Matrix4x4& m, const Vec3& v) {
return Vec3(m.m[0 + 0] * v.x + m.m[0 + 1] * v.y + m.m[0 + 2] * v.z,
m.m[4 + 0] * v.x + m.m[4 + 1] * v.y + m.m[4 + 2] * v.z,
m.m[8 + 0] * v.x + m.m[8 + 1] * v.y + m.m[8 + 2] * v.z);
}
inline Matrix4x4 transpose(const Matrix4x4& m) {
Matrix4x4 result;
for(int y = 0; y < 4; ++y){
for(int x = 0; x < 4; ++x){
result.m[y * 4 + x] = m.m[x * 4 + y];
}
}
return result;
}
inline Matrix4x4 scaleTranslation(const Vec3& _scale, const Vec3& _trans) {
return translation(_trans) * scale(_scale);
}
Vec3 smallestComponent(const Vec3& v) {
float x = fabs(v.x);
float y = fabs(v.y);
float z = fabs(v.z);
if(x < y && x < z) {
return Vec3(1.0f, 0.0f, 0.0f);
} else if (y < z) {
return Vec3(0.0f, 1.0f, 0.0f);
} else {
return Vec3(0.0f, 0.0f, 1.0f);
}
}
inline Vec3 findOrtho(const Vec3& v) {
return cross(smallestComponent(v), v);
}
inline Matrix4x4 directionalLightOrientation(Vec3 dir, const Vec3& upHint) {
float proj = dot(dir, upHint);
if(fabs(proj * proj - (dot(dir, dir) * dot(upHint, upHint))) < .001f) {
throw std::runtime_error("Up vector and forward vector parallel or close to parallel");
}
Vec3 x = normalize(cross(dir, upHint));
Vec3 z = normalize(cross(dir, x));
dir = normalize(dir);
Matrix4x4 result = identity();
result.setColumn(x, 0);
result.setColumn(-dir, 1);
result.setColumn(z, 2);
return result;
}
inline Matrix4x4 directionalLightOrientation(Vec3 dir) {
Vec3 up = findOrtho(dir);
return directionalLightOrientation(dir, up);
}
inline Matrix4x4 cameraOrientation(Vec3 forward, const Vec3& upHint) {
float proj = dot(forward, upHint);
if(fabs(proj * proj - (dot(forward, forward) * dot(upHint, upHint))) < .001f) {
throw std::runtime_error("Up vector and forward vector parallel or close to parallel");
}
Vec3 right = normalize(cross(upHint, forward));
Vec3 up = normalize(cross(forward, right));
forward = normalize(forward);
Matrix4x4 result = identity();
result.setColumn(-right, 0);
result.setColumn(up, 1);
result.setColumn(-forward, 2);
return result;
}
inline Matrix4x4 setCameraMatrix(const Vec3& pos, const Vec3& forward, const Vec3& upHint) {
Matrix4x4 trans = translation(pos);
Matrix4x4 orient = cameraOrientation(forward, upHint);
return trans * orient;
}
inline Matrix4x4 setSpotlightMatrix(const Vec3& pos, const Vec3& forward, const Vec3& upHint) {
Matrix4x4 trans = translation(pos);
Matrix4x4 orient = directionalLightOrientation(forward, upHint);
return trans * orient;
}
inline Matrix4x4 setSpotlightMatrix(const Vec3& pos, const Vec3& forward) {
Vec3 up = findOrtho(forward);
return setSpotlightMatrix(pos, forward, up);
}
inline Matrix4x4 setAreaLightMatrix(const Vec3& pos, const Vec3& forward, const Vec3& upHint, const Vec2& scaling) {
Matrix4x4 scalemtx = scale(Vec3(scaling.x, 1.0f, scaling.y));
return setSpotlightMatrix(pos, forward, upHint) * scalemtx;
}
public:
ColorRGB(
float _r,
float _g,
float _b) :
ILBLinearRGB(_r, _g, _b) {}
};
public:
ColorRGBA(
float _r,
float _g,
float _b,
float _a) :
ILBLinearRGBA(_r, _g, _b, _a) {}
ColorRGB toColorRGB() {
return ColorRGB(r, g, b);
}
};
inline float frand() {
unsigned int r = rand();
return (float)r / (float)RAND_MAX;
}
ColorRGBA randomRGBA(float amp) {
return ColorRGBA(frand() * amp, frand() * amp, frand() * amp, frand() * amp);
}
}
#endif // VECMATH_H