examples/code/common/vecmath.h

examples/code/common/vecmath.h
/*
Copyright 2014 Autodesk, Inc. All rights reserved.
Use of this software is subject to the terms of the Autodesk license agreement
provided at the time of installation or download, or which otherwise
accompanies this software in either electronic or hard copy form.
*/
#ifndef VECMATH_H
#define VECMATH_H
#include <cmath>
#include <cstdlib>
#include <stdexcept>
namespace bex {
class Vec2 : public ILBVec2 {
public:
Vec2(float _x, float _y) : ILBVec2(_x, _y) {}
Vec2() {}
};
class Vec3 : public ILBVec3 {
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;
}
class Matrix4x4 : public ILBMatrix4x4 {
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) {
// Check if we are on the diagonal
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);
// Epsilon check to avoid having up vectors parallel with the forward vector
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);
// Epsilon check to avoid having up vectors parallel with the forward vector
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;
}
class ColorRGB : public ILBLinearRGB {
public:
ColorRGB(float _r, float _g, float _b) : ILBLinearRGB(_r, _g, _b) {}
};
class ColorRGBA : public ILBLinearRGBA {
public:
ColorRGBA() : ILBLinearRGBA(0.0f, 0.0f, 0.0f, 1.0f) {}
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);
}
} // namespace bex
#endif // VECMATH_H