crt/object.cpp
#include "object.hpp"
#ifndef STATIC_LIGHT_RES
#define STATIC_LIGHT_RES 1.0
#endif
Object::Object(Texture* t, bool s, const vertex_t bmin, const vertex_t bmax):
lightmap(NULL),
tex(t),
sided(s),
bound_min(bmin),
bound_max(bmax),
bound_center(bmin.x+((bmax.x-bmin.x)/2.0),bmin.y+((bmax.y-bmin.y)/2.0),bmin.z+((bmax.z-bmin.z)/2.0)),
bound_cdiag(bound_max - bound_center) {
}
Object::~Object() {
if (tex) {
delete tex;
}
if (lightmap) {
delete lightmap;
}
}
void Object::set_lightmap(LightMap* l) const {
assert(!lightmap); // "const"
lightmap = l;
}
bool Object::quadfunc(const coord_t& a, const coord_t& b, const coord_t& c, coord_t& t) { // returns smallest result, if any
if (unlikely(a == 0.0)) { // not actual quadratic: b*t + c == 0
if (unlikely(b == 0.0)) {
return false;
} else {
t = -c / b;
return true;
}
}
coord_t discr = pow2(b) - (4.0 * a * c);
if (discr < 0.0) {
return false;
} else if (discr == 0.0) {
t = -0.5 * b / a;
} else {
const coord_t q = (b > 0)? (-0.5 * (b + sqrt(discr))): (-0.5 * (b - sqrt(discr)));
const coord_t t1 = q / a;
const coord_t t2 = c / q;
t = MIN(t1, t2);
}
return true;
}
void Object::lincomb(const vertex_t& P, coord_t& a, const vertex_t& A, coord_t& b, const vertex_t& B) {
/*
* P.x = a * A.x + b * B.x
* P.y = a * A.y + b * B.y
* P.z = a * A.z + b * B.z
*/
/*
* a = (Px - (b * Bx)) / Ax
* b = (Py - (a * Ay)) / By
* a = (Px - (((Py - (a * Ay)) / By) * Bx)) / Ax
* a = (Px/Ax - Py*Bx/By*Ax) / (1 - (Ay*Bx/By*Ax))
*/
coord_t ac, ab, ap;
coord_t bc, ba, bp;
if (A.x != 0.0 && B.y != 0.0) { // We must not choose the same row for A and B (e.g. for 0,1,1 and 0,1,0): TODO: programmatic approach?
ac = A.x; ab = B.x; ap = P.x;
bc = B.y; ba = A.y; bp = P.y;
} else if (A.x != 0.0 && B.z != 0.0) {
ac = A.x; ab = B.x; ap = P.x;
bc = B.z; ba = A.z; bp = P.z;
} else if (A.y != 0.0 && B.x != 0.0) {
ac = A.y; ab = B.y; ap = P.y;
bc = B.x; ba = A.x; bp = P.x;
} else if (A.y != 0.0 && B.z != 0.0) {
ac = A.y; ab = B.y; ap = P.y;
bc = B.z; ba = A.z; bp = P.z;
} else if (A.z != 0.0 && B.x != 0.0) {
ac = A.z; ab = B.z; ap = P.z;
bc = B.x; ba = A.x; bp = P.x;
} else { //if (A.z != 0.0 && B.y != 0.0) {
ac = A.z; ab = B.z; ap = P.z;
bc = B.y; ba = A.y; bp = P.y;
}
assert(ac != 0.0 && bc != 0.0); // vectors are independent (and thus != 0^3)
const coord_t acbc = ac*bc;
const coord_t F = (ap/ac) - ((ab*bp) / acbc);
const coord_t G = 1.0 - ((ab*ba) / acbc);
a = F / G;
b = (bp - (a*ba)) / bc;
}
bool Object::intersect_box(const vertex_t& amin, const vertex_t& amax, const vertex_t& bmin, const vertex_t& bmax) {
// el cheapo: intersetcs our box with the full ray's box? TODO: some better solution?
return amin.x <= bmax.x &&
amax.x >= bmin.x &&
amin.y <= bmax.y &&
amax.y >= bmin.y &&
amin.z <= bmax.z &&
amax.z >= bmin.z;
}
bool Object::intersect_box(const vertex_t& rmin, const vertex_t& rmax) const {
return intersect_box(rmin, rmax, bound_min, bound_max);
}
bool Object::intersect_box(const vertex_t& rmin, const vertex_t& rmax, coord_t margin) const {
return intersect_box(
rmin, rmax,
vertex_t(bound_min.x - margin, bound_min.y - margin, bound_min.z - margin),
vertex_t(bound_max.x + margin, bound_max.y + margin, bound_max.z + margin)
);
}
vertex_t Object::from_uv(coord_t u, coord_t v) const {
vertex_t rv, nrm;
from_uv(u, v, rv, nrm);
return rv;
}
void Object::max_dim(unsigned& w, unsigned& h) const {
if (!tex->max_dim(w, h)) {
coord_t max_u, max_v;
max_uv(max_u, max_v);
if (max_u < STATIC_LIGHT_RES || max_v < STATIC_LIGHT_RES) {
w = 0;
h = 0;
return;
}
w = floor(max_u / STATIC_LIGHT_RES);
h = floor(max_v / STATIC_LIGHT_RES);
assert(max_u >= 1 && max_v >= 1);
}
}