#include "light.h" #include "../geometry/util.h" #include "renderer.h" #include const char* Light_Type_Names[(int)Light_Type::count] = { "Directional", "Sphere", "Hemisphere", "Point", "Spot", "Rectangle" }; Scene_Light::Scene_Light(Light_Type type, Scene_ID id, Pose p, std::string n) : pose(p), _id(id), _lines(1.0f) { opt.type = type; if(n.size()) { snprintf(opt.name, max_name_len, "%s", n.c_str()); } else { snprintf(opt.name, max_name_len, "%s Light %d", Light_Type_Names[(int)type], id); } } bool Scene_Light::is_env() const { return opt.type == Light_Type::sphere || opt.type == Light_Type::hemisphere; } void Scene_Light::set_time(float time) { if(lanim.splines.any()) { lanim.at(time, opt); } dirty(); } void Scene_Light::emissive_clear() { opt.has_emissive_map = false; } HDR_Image Scene_Light::emissive_copy() const { return _emissive.copy(); } std::string Scene_Light::emissive_load(std::string file) { std::string err = _emissive.load_from(file); if(err.empty()) { opt.has_emissive_map = true; } return err; } std::string Scene_Light::emissive_loaded() const { return _emissive.loaded_from(); } const GL::Tex2D& Scene_Light::emissive_texture() const { return _emissive.get_texture(); } BBox Scene_Light::bbox() const { BBox box = _mesh.bbox(); box.transform(pose.transform()); return box; } Scene_Light::Scene_Light(Scene_Light&& src) : _lines(1.0f) { *this = std::move(src); } void Scene_Light::regen_mesh() { switch(opt.type) { case Light_Type::spot: { Vec3 col(opt.spectrum.r, opt.spectrum.g, opt.spectrum.b); _lines = Util::spotlight_mesh(col, opt.angle_bounds.x, opt.angle_bounds.y); _mesh = Util::sphere_mesh(0.15f, 2); } break; case Light_Type::directional: { _mesh = Util::arrow_mesh(0.03f, 0.075f, 1.0f); } break; case Light_Type::point: { _mesh = Util::sphere_mesh(0.15f, 2); } break; case Light_Type::rectangle: { _mesh = Util::quad_mesh(opt.size.x, opt.size.y); } break; default: break; } _dirty = false; } void Scene_Light::dirty() { _dirty = true; } Spectrum Scene_Light::radiance() const { return opt.spectrum * opt.intensity; } void Scene_Light::render(const Mat4& view, bool depth_only, bool posed) { if(_dirty) regen_mesh(); Renderer& renderer = Renderer::get(); Spectrum s = opt.spectrum; s.make_srgb(); Vec3 col(s.r,s.g,s.b); Mat4 rot = view; rot.cols[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f); Mat4 T = posed ? pose.transform() : Mat4::I; if(opt.type == Light_Type::spot && !depth_only) renderer.lines(_lines, view, T); if(opt.type == Light_Type::hemisphere) { renderer.skydome(rot, col, 0.0f); } else if(opt.type == Light_Type::sphere) { if(opt.has_emissive_map) renderer.skydome(rot, col, -1.1f, _emissive.get_texture()); else renderer.skydome(rot, col, -1.1f); } else { Renderer::MeshOpt opts; opts.modelview = view * T; opts.id = _id; opts.solid_color = true; opts.depth_only = depth_only; opts.color = col; renderer.mesh(_mesh, opts); } } bool operator!=(const Scene_Light::Options& l, const Scene_Light::Options& r) { return l.type != r.type || std::string(l.name) != std::string(r.name) || l.spectrum != r.spectrum || l.intensity != r.intensity || l.angle_bounds != r.angle_bounds || l.size != r.size || l.has_emissive_map != r.has_emissive_map; } void Scene_Light::Anim_Light::at(float t, Options& o) const { auto [s, i, a, sz] = splines.at(t); o.spectrum = s; o.intensity = i; o.angle_bounds = a; o.size = sz; } void Scene_Light::Anim_Light::set(float t, Options o) { splines.set(t, o.spectrum, o.intensity, o.angle_bounds, o.size); }