light.cpp 3.54 KB
Newer Older
TheNumbat's avatar
TheNumbat committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

#include "light.h"

#include "../geometry/util.h"
#include "renderer.h"

#include <sstream>

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);
}