#pragma once #include typedef float choice_t; #define do_op(o, r, i) \ inline void operator o##= (const r & rhs) { for(unsigned n=0; n<(i); n++) c[n] o##= rhs.c[n]; } \ inline void operator o##= (choice_t d) { for(unsigned n=0; n<(i); n++) c[n] o##= d; } \ inline r operator o (const r & rhs) const { r tmp(*this); tmp o##= rhs; return tmp; } \ inline r operator o (choice_t d) const { r tmp(*this); tmp o##= d; return tmp; } #define do_ops(c, i) \ do_op(*, c, i); \ do_op(/, c, i); \ do_op(+, c, i); \ do_op(-, c, i); struct v3 { union { choice_t c[4]; struct { choice_t x, y, z, w; }; }; v3(choice_t x, choice_t y, choice_t z) : c{x,y,z} {} v3(choice_t f) : v3(f,f,f) {} v3() : v3(0,0,0) {} do_ops(v3, 3); inline v3 operator-(void) const { return {-x, -y, -z}; } inline choice_t operator^(const v3& rhs) const { return x * rhs.x + y * rhs.y + z * rhs.z; } /* Return normalised (unit) vector. */ inline v3 norm() const { return *this / len(); } inline choice_t len() const { return sqrtf(x*x + y*y + z*z); } inline choice_t lensquared() const { return x*x + y*y + z*z; } /* Return vector reflected around `n'. Expects `this' and `n' to be unit. */ inline v3 ref(const v3& n) const { return n * ((*this ^ n) * 2) - *this;} /* Cross product. */ inline v3 cross(const v3& b) const { return { y*b.z - z*b.y, x*b.z - z*b.x, x*b.y - y*b.x }; } inline v3 refract(const v3& n, choice_t ior_ratio) const { return n * sqrtf(1 - powf(ior_ratio, 2) * (1 - powf(*this ^ n, 2))) + (*this - n * (*this ^ n)) * ior_ratio; } inline v3 refract(const v3& n, choice_t ior_incident, choice_t ior_refract) const { return refract(n, ior_incident / ior_refract); } inline v3 clamp(const v3& from, const v3& to) const { return { fmin(fmax(x, from.x), to.x), fmin(fmax(y, from.y), to.y), fmin(fmax(z, from.z), to.z) }; } inline v3 exp() const { return { ::exp(x), ::exp(y), ::exp(z) }; } inline v3 htan(choice_t exposure = 0) const { return { powf((tanh(x + exposure) + 1) / 2, 2.2), powf((tanh(y + exposure) + 1) / 2, 2.2), powf((tanh(z + exposure) + 1) / 2, 2.2) }; return { tanh(x + exposure), tanh(y + exposure), tanh(z + exposure) }; } }; #undef do_ops #undef do_op #define V3_FMT "v3(%.2f, %.2f, %.2f)" #define V3_ARG(v) (v).x, (v).y, (v).z struct Matrix { v3 m[4]; void init_rotate(const v3& angle) { choice_t Cx = cos(angle.c[0]), Cy = cos(angle.c[1]), Cz = cos(angle.c[2]); choice_t Sx = sin(angle.c[0]), Sy = sin(angle.c[1]), Sz = sin(angle.c[2]); choice_t sxsz = Sx*Sz, cxsz = Cx*Sz; choice_t cxcz = Cx*Cz, sxcz = Sx*Cz; Matrix result = {{ { Cy*Cz, Cy*Sz, -Sy }, { sxcz*Sy - cxsz, sxsz*Sy + cxcz, Sx*Cy }, { cxcz*Sy + sxsz, cxsz*Sy - sxcz, Cx*Cy } }}; *this = result; } v3 transform(const v3& vec) const { return { m[0] ^ vec, m[1] ^ vec, m[2] ^ vec }; } };