crt/scene.cpp
#include "scene.hpp"
#include "stats.hpp"
Scene::Scene(): lighting(new Lights()), cleanup(true) {
}
Scene::~Scene() {
delete lighting;
if (!cleanup) {
return;
}
while (objects.size()) {
delete objects.back();
objects.pop_back();
}
while (lights.size()) {
delete lights.back();
lights.pop_back();
}
}
bool Scene::push(Object* o) {
if (objects.empty()) {
bound_min = o->bound_min;
bound_max = o->bound_max;
} else {
bound_min = vertex_t::minof(bound_min, o->bound_min);
bound_max = vertex_t::maxof(bound_max, o->bound_max);
}
objects.push_back(o);
light_objects.push_back(o);
return true;
}
bool Scene::push(Light* l) {
lights.push_back(l);
return true;
}
void Scene::finalize() {
for (std::vector<const Light*>::const_iterator lit=lights.begin(); lit!=lights.end(); lit++) {
lighting->push(*lit);
}
lighting->finalize(objects);
}
bool Scene::intersect(const ray_t& ray, std::vector<const Object*>& obj) {
static Counter scene_light_hit("scene light hit", true);
const vertex_t rdst = ray.origin + ray.direction;
const vertex_t rmin = vertex_t::minof(ray.origin, rdst);
const vertex_t rmax = vertex_t::maxof(ray.origin, rdst);
for (std::vector<const Object*>::iterator it = obj.begin(); it != obj.end(); it++) {
const Object* o = *it;
if (!o->intersect_box(rmin, rmax)) {
continue;
}
if (o->intersect(ray)) {
#ifndef NO_OBJ_LRU
if (it != obj.begin()) {
scene_light_hit.inc();
const Object* tmp = obj.front();
obj.front() = *it;
*it = tmp;
} else {
scene_light_hit.inc(1);
}
#endif
return true;
}
}
return false;
}
bool Scene::intersect(const ray_t& ray) const {
return intersect(ray, light_objects);
}
const Object* Scene::intersect(ray_t& ray, const vertex_t& ray_normal, vertex_t& hitpoint, vertex_t& normal, LightValue& light, Img::rgb_t* col) const {
static Counter scene_hit("scene first hit", true);
static Counter scene_miss("scene miss", true);
static Counter scene_late_miss("scene late miss", true);
// build full camera box to detect intersection with object boxes XXX: this can be even a full quadrant
vertex_t rdst = ray.origin + ray.direction;
vertex_t rmin = vertex_t::minof(ray.origin, rdst);
vertex_t rmax = vertex_t::maxof(ray.origin, rdst);
if (!Object::intersect_box(rmin, rmax, bound_min, bound_max)) {
return NULL; // misses whole scene
}
const Object* rv = NULL;
std::vector<const Object*>::iterator rv_it;
Object::intersect_ctx_t rv_ctx;
LightValue rv_light;
for (std::vector<const Object*>::iterator it = objects.begin(); it != objects.end(); it++) {
const Object* o = *it;
if (!o->intersect_box(rmin, rmax)) {
scene_miss.inc(1);
scene_late_miss.inc();
continue;
}
Object::intersect_ctx_t ctx;
if (o->intersect(ctx, ray, ray_normal, hitpoint)) {
rv = o;
rv_it = it;
rv_ctx = ctx;
ray.direction = hitpoint - ray.origin; // decrease depth to handle occlusion
rdst = ray.origin + ray.direction;
rmin = vertex_t::minof(ray.origin, rdst);
rmax = vertex_t::maxof(ray.origin, rdst);
scene_miss.inc();
scene_late_miss.inc();
} else {
scene_miss.inc();
scene_late_miss.inc(1);
}
}
unless (rv) {
return NULL;
}
// get the corresponding (possibly costly) light, normal, and texture information
rv->intersect(rv_ctx, ray, hitpoint, normal, light, col);
#ifndef NO_OBJ_LRU
if (rv_it != objects.begin()) {
scene_hit.inc();
const Object* tmp = objects.front();
objects.front() = rv;
*rv_it = tmp;
} else {
scene_hit.inc(1);
}
#endif
return rv;
}
void Scene::get_light(const Object* o, const vertex_t& hit, const vertex_t& ray, const vertex_t& raynrm, const vertex_t& nrm, LightValue& lv) const {
lighting->get_light(o, hit, &raynrm, nrm, lv);
}
const Scene* Scene::getSMPcopy() const {
Scene* s = new Scene();
s->cleanup = false;
for (std::vector<const Object*>::const_iterator it=objects.begin(); it!=objects.end(); it++) {
s->push(const_cast<Object*>(*it));
}
for (std::vector<const Light*>::const_iterator it=lights.begin(); it!=lights.end(); it++) {
s->push(const_cast<Light*>(*it));
}
lighting->getSMPcopy(*s->lighting);
return s;
}