#include "object.hpp"
#include <assert.h>
#include <cmath>
/**
* @file
* @brief Ray-intersections for most simple one-sided axis-aligned planes.
*/
Object::Object(box_t box, const Texture* tex) : bounding(box), texture(tex) {}
SidedAxisPlane::SidedAxisPlane(vertex_t pos, vertex_t dir, bool positive, const Texture* tex)
: Object(box_t{pos, pos + dir}, tex), pos(pos), dir(dir), positive(positive) {
assert(bounding.lo.x == bounding.hi.x || bounding.lo.y == bounding.hi.y || bounding.lo.z == bounding.hi.z);
if (dir.x == 0.0) {
os = {0, 1, 2};
} else if (dir.y == 0.0) {
os = {1, 0, 2};
} else if (dir.z == 0.0) {
os = {2, 0, 1};
} else {
assert(false);
}
nrm.v[os.n] = positive ? 1.0 : -1.0;
}
bool SidedAxisPlane::intersect(const ray_t& ray, vertex_t& hit) const {
assert(ray.dir.v[os.n] != 0.0F); // pre-checked: parallel and div by zero
const fcoord_t t = vertex_t::scale_factor(pos.v[os.n], ray.pos.v[os.n], ray.dir.v[os.n]);
if (t < 0.0F || t > 1.0F) {
return false;
}
const vertex_t h{ray.dir * t + ray.pos};
if (h.v[os.a] < bounding.lo.v[os.a] || h.v[os.a] > bounding.hi.v[os.a] || h.v[os.b] < bounding.lo.v[os.b] ||
h.v[os.b] > bounding.hi.v[os.b]) {
return false;
}
hit = h;
#if 1
hit.v[os.n] = pos.v[os.n];
#endif
return true;
}
bool SidedAxisPlane::intersect(const ray_t& ray) const {
static vertex_t hit;
return can_intersect(ray) && intersect(ray, hit);
}
bool SidedAxisPlane::intersect(const ray_t& ray, vertex_t& hit, vertex_t& hit_nrm) const {
if (can_intersect(ray) && intersect(ray, hit)) {
hit_nrm = nrm;
return true;
}
return false;
}
bool SidedAxisPlane::intersect(const ray_t& ray, vertex_t& hit, vertex_t& hit_nrm, const Texture*& tex,
uv_t& uv) const {
if (can_intersect(ray) && intersect(ray, hit)) {
hit_nrm = nrm;
tex = texture;
uv.u = (hit.v[os.a] - pos.v[os.a]) / dir.v[os.a];
uv.v = (hit.v[os.b] - pos.v[os.b]) / dir.v[os.b];
return true;
}
return false;
}
/** @brief camera position on visible side - in normal direction? */
bool SidedAxisPlane::can_intersect(const vertex_t& camera) const {
return positive ? camera.v[os.n] > pos.v[os.n] : camera.v[os.n] < pos.v[os.n];
}
/** @brief normal pointing to opposite direction? */
INLINE bool SidedAxisPlane::can_intersect(const ray_t& ray) const {
return positive ? ray.dir.v[os.n] < 0.0 : ray.dir.v[os.n] > 0.0;
}
/** @brief side-independent hit in direction possible? */
INLINE bool SidedAxisPlane::can_intersect_any(const ray_t& ray) const {
return likely(ray.dir.v[os.n] != 0.0F);
}
bool SidedAxisPlane::intersect_full(const vertex_t& pos, const box_t& dst) const {
for (const auto corner_side :
{box_t::corner_t::CORNER_A, box_t::corner_t::CORNER_B, box_t::corner_t::CORNER_C, box_t::corner_t::CORNER_D,
box_t::corner_t::CORNER_E, box_t::corner_t::CORNER_F, box_t::corner_t::CORNER_G, box_t::corner_t::CORNER_H}) {
const vertex_t corner = dst.get_corner(corner_side);
const ray_t ray{pos, corner - pos, corner};
if (likely(!can_intersect_any(ray) || !intersect(ray))) {
return false;
}
}
return true;
}