Last active
March 7, 2017 16:09
-
-
Save fritschy/447c2c08e924c7780c951389fb90c4a9 to your computer and use it in GitHub Desktop.
C++ wrapper around some of graphene @ https://github.com/ebassi/graphene
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef FULLERENE_HPP | |
#define FULLERENE_HPP | |
#include <float.h> | |
#include <inttypes.h> | |
#include <stddef.h> | |
#include <graphene.h> | |
namespace C { | |
struct Uninitialize {}; | |
static Uninitialize uninitialize; | |
// vec common impl {{{ | |
#define MAKE_COMMON_VEC_IMPL(T) \ | |
T &operator+=(T &self, T const &other) { \ | |
graphene_##T##_add(&self.v, &other.v, &self.v); \ | |
return self; \ | |
} \ | |
\ | |
T &operator-=(T &self, T const &other) { \ | |
graphene_##T##_subtract(&self.v, &other.v, &self.v); \ | |
return self; \ | |
} \ | |
\ | |
T &operator/=(T &self, T const &other) { \ | |
graphene_##T##_divide(&self.v, &other.v, &self.v); \ | |
return self; \ | |
} \ | |
\ | |
T &operator*=(T &self, T const &other) { \ | |
graphene_##T##_multiply(&self.v, &other.v, &self.v); \ | |
return self; \ | |
} \ | |
\ | |
T operator+(T const &self, T const &other) { \ | |
T v(uninitialize); \ | |
graphene_##T##_add(&self.v, &other.v, &v.v); \ | |
return v; \ | |
} \ | |
\ | |
T operator-(T const &self, T const &other) { \ | |
T v(uninitialize); \ | |
graphene_##T##_subtract(&self.v, &other.v, &v.v); \ | |
return v; \ | |
} \ | |
\ | |
T operator/(T const &self, T const &other) { \ | |
T v(uninitialize); \ | |
graphene_##T##_divide(&self.v, &other.v, &v.v); \ | |
return v; \ | |
} \ | |
\ | |
T operator*(T const &self, T const &other) { \ | |
T v(uninitialize); \ | |
graphene_##T##_multiply(&self.v, &other.v, &v.v); \ | |
return v; \ | |
} \ | |
\ | |
float dot(T const &a, T const &b) { \ | |
return graphene_##T##_dot(&a.v, &b.v); \ | |
} \ | |
\ | |
T dot2(T const &a, T const &b) { \ | |
T ret; \ | |
ret.s = graphene_simd4f_dot2(a.s, b.s); \ | |
return ret; \ | |
} \ | |
\ | |
T dot3(T const &a, T const &b) { \ | |
T ret; \ | |
ret.s = graphene_simd4f_dot3(a.s, b.s); \ | |
return ret; \ | |
} \ | |
\ | |
T dot4(T const &a, T const &b) { \ | |
T ret; \ | |
ret.s = graphene_simd4f_dot4(a.s, b.s); \ | |
return ret; \ | |
} \ | |
\ | |
float length(T const &v) { return graphene_##T##_length(&v.v); } \ | |
\ | |
T length2(T const &a) { \ | |
T ret; \ | |
ret.s = graphene_simd4f_length2(a.s); \ | |
return ret; \ | |
} \ | |
\ | |
T length3(T const &a) { \ | |
T ret; \ | |
ret.s = graphene_simd4f_length3(a.s); \ | |
return ret; \ | |
} \ | |
\ | |
T length4(T const &a) { \ | |
T ret; \ | |
ret.s = graphene_simd4f_length4(a.s); \ | |
return ret; \ | |
} \ | |
\ | |
T normalize(T const &v) { \ | |
T r(uninitialize); \ | |
graphene_##T##_normalize(&v.v, &r.v); \ | |
return r; \ | |
} \ | |
\ | |
T normalize2(T const &a) { \ | |
T ret; \ | |
ret.s = graphene_simd4f_normalize2(a.s); \ | |
return ret; \ | |
} \ | |
\ | |
T normalize3(T const &a) { \ | |
T ret; \ | |
ret.s = graphene_simd4f_normalize3(a.s); \ | |
return ret; \ | |
} \ | |
\ | |
T clamp(T const &v, T const &lo, T const &hi) { \ | |
T ret; \ | |
ret.s = graphene_simd4f_clamp(v.s, lo.s, hi.s); \ | |
return ret; \ | |
} \ | |
\ | |
T clamp(T const &v, float lo, float hi) { \ | |
T ret; \ | |
ret.s = graphene_simd4f_clamp_scalar(v.s, lo, hi); \ | |
return ret; \ | |
} \ | |
\ | |
T normalize4(T const &a) { \ | |
T ret; \ | |
ret.s = graphene_simd4f_normalize4(a.s); \ | |
return ret; \ | |
} \ | |
\ | |
T &operator*=(T &self, float other) { \ | |
graphene_##T##_scale(&self.v, other, &self.v); \ | |
return self; \ | |
} \ | |
\ | |
T operator*(T const &self, float other) { \ | |
T r(uninitialize); \ | |
graphene_##T##_scale(&self.v, other, &r.v); \ | |
return r; \ | |
} \ | |
\ | |
T operator*(float other, T const &self) { \ | |
T r(uninitialize); \ | |
graphene_##T##_scale(&self.v, other, &r.v); \ | |
return r; \ | |
} \ | |
\ | |
T &operator/=(T &self, float other) { \ | |
graphene_##T##_scale(&self.v, 1.f / other, &self.v); \ | |
return self; \ | |
} \ | |
\ | |
T operator/(T const &self, float other) { \ | |
T r(uninitialize); \ | |
graphene_##T##_scale(&self.v, 1.f / other, &r.v); \ | |
return r; \ | |
} \ | |
\ | |
T operator/(float other, T const &self) { \ | |
auto r = T(other); \ | |
graphene_##T##_divide(&r.v, &self.v, &r.v); \ | |
return r; \ | |
} \ | |
\ | |
T operator-(T const &self) { \ | |
T r(uninitialize); \ | |
graphene_##T##_negate(&self.v, &r.v); \ | |
return r; \ | |
} \ | |
\ | |
bool near(T const &a, T const &b, float epsilon) { \ | |
return graphene_##T##_near(&a.v, &b.v, epsilon); \ | |
} \ | |
\ | |
bool operator==(T const &a, T const &b) { \ | |
return graphene_##T##_equal(&a.v, &b.v); \ | |
} \ | |
\ | |
bool operator!=(T const &a, T const &b) { \ | |
return !graphene_##T##_equal(&a.v, &b.v); \ | |
} \ | |
\ | |
T min(T const &self, T const &other) { \ | |
T ret(uninitialize); \ | |
graphene_##T##_min(&self.v, &other.v, &ret.v); \ | |
return ret; \ | |
} \ | |
\ | |
T max(T const &self, T const &other) { \ | |
T ret(uninitialize); \ | |
graphene_##T##_max(&self.v, &other.v, &ret.v); \ | |
return ret; \ | |
} \ | |
\ | |
T sqrt(T const &v) { \ | |
T ret(uninitialize); \ | |
ret.s = graphene_simd4f_sqrt(v.s); \ | |
return ret; \ | |
} \ | |
\ | |
T rsqrt(T const &v) { \ | |
T ret(uninitialize); \ | |
ret.s = graphene_simd4f_rsqrt(v.s); \ | |
return ret; \ | |
} \ | |
\ | |
T reciprocal(T const &v) { \ | |
T ret(uninitialize); \ | |
ret.s = graphene_simd4f_reciprocal(v.s); \ | |
return ret; \ | |
} | |
// }}} | |
struct vec2 /// {{{ | |
{ | |
struct storage { | |
float x; | |
float y; | |
}; | |
union { | |
graphene_vec2_t v; | |
graphene_simd4f_t s; | |
// I don't think I should be doing this ... | |
struct { | |
float x; | |
float y; | |
}; | |
float m[2]; | |
}; | |
#ifdef FULLERENE_UNINITIALIZE_BY_DEFAULT | |
vec2() {} | |
#else | |
vec2() { x = y = 0.f; } | |
#endif | |
explicit vec2(Uninitialize) {} | |
explicit vec2(float v_) { graphene_vec2_init(&v, v_, v_); } | |
explicit vec2(float const *p) { graphene_vec2_init_from_float(&v, p); } | |
explicit vec2(graphene_vec2_t const &v_) : v(v_) {} | |
vec2(storage const &s) { graphene_vec2_init(&v, s.x, s.y); } | |
vec2(float x_, float y_) { graphene_vec2_init(&v, x_, y_); } | |
vec2(vec2 const &v_) { graphene_vec2_init_from_vec2(&v, &v_.v); } | |
vec2 &operator=(const vec2 &v_) { | |
graphene_vec2_init_from_vec2(&v, &v_.v); | |
return *this; | |
} | |
float operator[](int i) const { return m[i]; } | |
float &operator[](int i) { return m[i]; } | |
static vec2 one() { return vec2(1.f); } | |
static vec2 zero() { return vec2(0.f); } | |
static vec2 x_axis() { return vec2(1.f, 0.f); } | |
static vec2 y_axis() { return vec2(0.f, 1.f); } | |
}; | |
// }}} | |
struct vec3 /// {{{ | |
{ | |
struct storage { | |
float x; | |
float y; | |
float z; | |
}; | |
union { | |
graphene_vec3_t v; | |
graphene_vec2_t v2; | |
graphene_simd4f_t s; | |
// I don't think I should be doing this ... | |
struct { | |
float x; | |
float y; | |
float z; | |
}; | |
float m[3]; | |
graphene_point3d_t p3; | |
}; | |
#ifdef FULLERENE_UNINITIALIZE_BY_DEFAULT | |
vec3() {} | |
#else | |
vec3() { x = y = z = 0.f; } | |
#endif | |
explicit vec3(Uninitialize) {} | |
explicit vec3(float v_) { graphene_vec3_init(&v, v_, v_, v_); } | |
explicit vec3(float const *p) { graphene_vec3_init_from_float(&v, p); } | |
explicit vec3(graphene_vec3_t const &v_) : v(v_) {} | |
vec3(storage const &s) { graphene_vec3_init(&v, s.x, s.y, s.z); } | |
vec3(float x_, float y_, float z_) { graphene_vec3_init(&v, x_, y_, z_); } | |
vec3(vec3 const &v_) { graphene_vec3_init_from_vec3(&v, &v_.v); } | |
vec3(vec2 const &v_, float z_) { graphene_vec3_init(&v, v_.x, v_.y, z_); } | |
vec3 &operator=(const vec3 &v_) { | |
graphene_vec3_init_from_vec3(&v, &v_.v); | |
return *this; | |
} | |
float operator[](int i) const { return m[i]; } | |
float &operator[](int i) { return m[i]; } | |
static vec3 one() { return vec3(1.f); } | |
static vec3 zero() { return vec3(0.f); } | |
static vec3 x_axis() { return vec3(1.f, 0.f, 0.f); } | |
static vec3 y_axis() { return vec3(0.f, 1.f, 0.f); } | |
static vec3 z_axis() { return vec3(0.f, 0.f, 1.f); } | |
vec2 xy() const { return vec2(v2); } | |
vec3 xy0() const { return vec3(x, y, 0); } | |
vec3 xy1() const { return vec3(x, y, 1); } | |
}; | |
vec3 cross(vec3 const &a, vec3 const &b) { | |
vec3 r(uninitialize); | |
graphene_vec3_cross(&a.v, &b.v, &r.v); | |
return r; | |
} | |
// }}} | |
struct vec4 /// {{{ | |
{ | |
struct storage { | |
float x; | |
float y; | |
float z; | |
float w; | |
}; | |
union { | |
graphene_vec4_t v; | |
graphene_vec3_t v3; | |
graphene_vec2_t v2; | |
graphene_simd4f_t s; | |
// I don't think I should be doing this ... | |
struct { | |
float x; | |
float y; | |
float z; | |
float w; | |
}; | |
float m[4]; | |
}; | |
#ifdef FULLERENE_UNINITIALIZE_BY_DEFAULT | |
vec4() {} | |
#else | |
vec4() { x = y = z = w = 0.f; } | |
#endif | |
explicit vec4(Uninitialize) {} | |
explicit vec4(float v_) { graphene_vec4_init(&v, v_, v_, v_, v_); } | |
explicit vec4(float const *p) { graphene_vec4_init_from_float(&v, p); } | |
explicit vec4(graphene_vec4_t const &v_) : v(v_) {} | |
vec4(storage const &s) { graphene_vec4_init(&v, s.x, s.y, s.z, s.w); } | |
vec4(float x_, float y_, float z_, float w_) { | |
graphene_vec4_init(&v, x_, y_, z_, w_); | |
} | |
vec4(vec4 const &v_) { graphene_vec4_init_from_vec4(&v, &v_.v); } | |
vec4(vec3 const &v_, float w_) { | |
graphene_vec4_init(&v, v_.x, v_.y, v_.z, w_); | |
} | |
vec4(vec2 const &v_, float z_, float w_) { | |
graphene_vec4_init(&v, v_.x, v_.y, z_, w_); | |
} | |
vec4 &operator=(const vec4 &v_) { | |
graphene_vec4_init_from_vec4(&v, &v_.v); | |
return *this; | |
} | |
float operator[](int i) const { return m[i]; } | |
float &operator[](int i) { return m[i]; } | |
static vec4 one() { return vec4(1.f); } | |
static vec4 zero() { return vec4(0.f); } | |
static vec4 x_axis() { return vec4(1.f, 0.f, 0.f, 0.f); } | |
static vec4 y_axis() { return vec4(0.f, 1.f, 0.f, 0.f); } | |
static vec4 z_axis() { return vec4(0.f, 0.f, 1.f, 0.f); } | |
static vec4 w_axis() { return vec4(0.f, 0.f, 0.f, 1.f); } | |
vec2 xy() const { return vec2(v2); } | |
vec3 xyz() const { return vec3(v3); } | |
}; | |
// }}} | |
MAKE_COMMON_VEC_IMPL(vec2) | |
MAKE_COMMON_VEC_IMPL(vec3) | |
MAKE_COMMON_VEC_IMPL(vec4) | |
vec2::storage storage_cast(vec2 const &v) { return vec2::storage{v.x, v.y}; } | |
vec3::storage storage_cast(vec3 const &v) { | |
return vec3::storage{v.x, v.y, v.z}; | |
} | |
vec4::storage storage_cast(vec4 const &v) { | |
return vec4::storage{v.x, v.y, v.z, v.w}; | |
} | |
template <typename T> | |
float const *value_ptr(T const &v) { | |
return &v.x; | |
} | |
template <typename T> | |
float *value_ptr(T &v) { | |
return &v.x; | |
} | |
struct box // {{{ | |
{ | |
graphene_box_t b; | |
box(); | |
explicit box(Uninitialize); | |
box(vec3 const &min, vec3 const &max); | |
box(box const &b_); | |
box(uint32_t count, vec3 *points); | |
box &operator=(box const &other); | |
vec3 min() const; | |
vec3 max() const; | |
static box empty() { return box(vec3(FLT_MAX), vec3(FLT_MIN)); } | |
static box infinity() { return box(vec3(FLT_MIN - 1), vec3(FLT_MAX + 1)); } | |
}; | |
inline box &operator+=(box &self, box const &other) { | |
graphene_box_union(&self.b, &other.b, &self.b); | |
return self; | |
} | |
inline vec3 size(box const &b) { | |
vec3 v; | |
graphene_box_get_size(&b.b, &v.v); | |
return v; | |
} | |
inline vec3 center(box const &b) { | |
vec3 v; | |
graphene_point3d_t p; | |
graphene_box_get_center(&b.b, &p); | |
graphene_point3d_to_vec3(&p, &v.v); | |
return v; | |
} | |
#ifdef FULLERENE_UNINITIALIZE_BY_DEFAULT | |
inline box::box() {} | |
#else | |
inline box::box() { b = empty().b; } | |
#endif | |
inline box::box(Uninitialize) {} | |
inline box::box(vec3 const &min, vec3 const &max) { | |
graphene_box_init_from_vec3(&b, &min.v, &max.v); | |
} | |
inline box::box(box const &b_) : b(b_.b) {} | |
inline box::box(uint32_t count, vec3 *points) { | |
b = empty().b; | |
for (uint32_t i = 0; i < count; i++) { | |
graphene_box_expand_vec3(&b, &points[i].v, &b); | |
} | |
} | |
inline box &box::operator=(box const &other) { | |
b = other.b; | |
return *this; | |
} | |
inline vec3 box::min() const { | |
vec3 v; | |
graphene_point3d_t p; | |
graphene_box_get_min(&b, &p); | |
graphene_point3d_to_vec3(&p, &v.v); | |
return v; | |
} | |
inline vec3 box::max() const { | |
vec3 v; | |
graphene_point3d_t p; | |
graphene_box_get_max(&b, &p); | |
graphene_point3d_to_vec3(&p, &v.v); | |
return v; | |
} | |
inline bool intersect(box const &b, vec3 const &ro, vec3 const &rrd, | |
float *tnear, float *tfar) { | |
// see: http://ompf.org/forum/viewtopic.php?f=4&t=965&p=9519&hilit=bvh#p9486 | |
auto t1 = (b.min() - ro) * rrd; | |
auto t2 = (b.max() - ro) * rrd; | |
auto near = min(t1, t2); | |
auto far = max(t2, t2); | |
auto tmin = fmaxf(fmaxf(near.x, near.y), near.z); | |
auto tmax = fminf(fminf(far.x, far.y), far.z); | |
*tnear = tmin; | |
*tfar = tmax; | |
#if 0 | |
return (tmax >= tmin) & (tmax >= 0); | |
#else | |
union fu { | |
float f; | |
uint32_t u; | |
int32_t i; | |
}; | |
fu x; | |
x.f = tmax - tmin; | |
fu y; | |
y.f = tmax; | |
return ~((x.i | y.i) >> 31); | |
#endif | |
} | |
// }}} | |
struct mat4 /// {{{ | |
{ | |
graphene_matrix_t m; | |
explicit mat4(Uninitialize) {} | |
mat4(); | |
mat4(vec4 const &r0, vec4 const &r1, vec4 const &r2, vec4 const &r3); | |
explicit mat4(float const *p); | |
mat4(mat4 const &m_); | |
mat4 &operator=(mat4 const &m_); | |
float operator()(unsigned i, unsigned j) const { | |
return graphene_matrix_get_value(&m, i, j); | |
} | |
static mat4 identity() { | |
mat4 m; | |
graphene_matrix_init_identity(&m.m); | |
return m; | |
} | |
}; | |
mat4::mat4() { | |
#ifndef FULLERENE_UNINITIALIZE_BY_DEFAULT | |
graphene_matrix_init_identity(&m); | |
#endif | |
} | |
mat4::mat4(vec4 const &r0, vec4 const &r1, vec4 const &r2, vec4 const &r3) { | |
graphene_matrix_init_from_vec4(&m, &r0.v, &r1.v, &r2.v, &r3.v); | |
} | |
mat4::mat4(float const *p) { graphene_matrix_init_from_float(&m, p); } | |
mat4::mat4(mat4 const &m_) : m(m_.m) {} | |
mat4 &mat4::operator=(mat4 const &m_) { | |
m = m_.m; | |
return *this; | |
} | |
mat4 operator*(mat4 const &a, mat4 const &b) { | |
mat4 r; | |
graphene_matrix_multiply(&a.m, &b.m, &r.m); | |
return r; | |
} | |
vec3 operator*(mat4 const &m, vec3 const &v) { | |
vec3 r; | |
graphene_matrix_transform_vec3(&m.m, &v.v, &r.v); | |
return r; | |
} | |
vec4 operator*(mat4 const &m, vec4 const &v) { | |
vec4 r; | |
graphene_matrix_transform_vec4(&m.m, &v.v, &r.v); | |
return r; | |
} | |
mat4 translate(mat4 const &m, vec3 const &v) { | |
mat4 r; | |
graphene_matrix_init_translate(&r.m, &v.p3); | |
return m * r; | |
} | |
mat4 rotate(mat4 const &m, float angle, vec3 const &axis) { | |
mat4 r; | |
graphene_matrix_init_rotate(&r.m, angle / (4 * atanf(1)) * 180.f, &axis.v); | |
return m * r; | |
} | |
mat4 scale(mat4 const &m, float fx, float fy, float fz) { | |
mat4 r; | |
graphene_matrix_init_scale(&r.m, fx, fy, fz); | |
return m * r; | |
} | |
mat4 transpose(mat4 const &m) { | |
mat4 r; | |
graphene_matrix_transpose(&m.m, &r.m); | |
return r; | |
} | |
mat4 inverse(mat4 const &m) { | |
mat4 r; | |
graphene_matrix_inverse(&m.m, &r.m); | |
return r; | |
} | |
// }}} | |
template <typename T> | |
T mix(T const &a, T const &b, T const &t) { | |
return a + t * (b - a); | |
} | |
template <typename T> | |
T mix(T const &a, T const &b, float t) { | |
return a + t * (b - a); | |
} | |
template <typename T> | |
T reflect(T const &i, T const &n) { | |
return i - n * dot(n, i) * 2; | |
} | |
template <typename T> | |
T fast_pow(T x, int n) { | |
if (n < 0) { | |
x = 1.f / x; | |
n = -n; | |
} | |
if (n == 0) | |
return T(1); | |
T y(1.f); | |
while (n > 1) { | |
if (!(n & 1)) { | |
x *= x; | |
n /= 2; | |
} else { | |
y *= x; | |
x *= x; | |
n = (n - 1) / 2; | |
} | |
} | |
return x * y; | |
} | |
float clamp(float v, float lo, float hi) { | |
return fmaxf(fminf(v, hi), lo); | |
} | |
} // C | |
#endif // !FULLERENE_HPP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment