Skip to content

Instantly share code, notes, and snippets.

@fritschy
Last active March 7, 2017 16:09
Show Gist options
  • Save fritschy/447c2c08e924c7780c951389fb90c4a9 to your computer and use it in GitHub Desktop.
Save fritschy/447c2c08e924c7780c951389fb90c4a9 to your computer and use it in GitHub Desktop.
C++ wrapper around some of graphene @ https://github.com/ebassi/graphene
#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