]> git.tdb.fi Git - libs/gl.git/blob - source/materials/lighting.cpp
721d5cdca8593a131e0a82070648a7dc6c3082fa
[libs/gl.git] / source / materials / lighting.cpp
1 #include <stdexcept>
2 #include <cmath>
3 #include <msp/core/algorithm.h>
4 #include <msp/fs/utils.h>
5 #include "error.h"
6 #include "light.h"
7 #include "lighting.h"
8 #include "matrix.h"
9
10 using namespace std;
11
12 namespace Msp {
13 namespace GL {
14
15 Lighting::Lighting():
16         zenith_direction(0, 0, 1),
17         horizon_angle(Geometry::Angle<float>::zero())
18 {
19         set_ambient(0.2f);
20         set_fog_color(Color(0.0f, 0.0f, 0.0f, 0.0f));
21         set_fog_density(0.0f);
22 }
23
24 void Lighting::set_ambient(const Color &a)
25 {
26         ambient = a;
27         shdata.uniform("ambient_color", ambient);
28 }
29
30 void Lighting::set_sky_color(const Color &s)
31 {
32         sky_color = s;
33         shdata.uniform("sky_color", sky_color);
34 }
35
36 void Lighting::set_zenith_direction(const Vector3 &d)
37 {
38         zenith_direction = d;
39         shdata.uniform("world_zenith_dir", zenith_direction);
40 }
41
42 void Lighting::set_horizon_angle(const Geometry::Angle<float> &a)
43 {
44         horizon_angle = a;
45         shdata.uniform("horizon_limit", horizon_angle.radians());
46 }
47
48 void Lighting::set_fog_color(const Color &c)
49 {
50         fog_color = c;
51         shdata.uniform("fog_color", fog_color);
52 }
53
54 void Lighting::set_fog_density(float d)
55 {
56         if(d<0)
57                 throw invalid_argument("Lighting::set_fog_density");
58
59         fog_density = d;
60         shdata.uniform("fog_density", fog_density);
61 }
62
63 void Lighting::set_fog_half_distance(float d)
64 {
65         set_fog_density(-log(pow(0.5, 1.0/d)));
66 }
67
68 void Lighting::attach(const Light &l)
69 {
70         if(find_member(lights, &l, &AttachedLight::light)==lights.end())
71                 lights.push_back(&l);
72 }
73
74 void Lighting::detach(const Light &l)
75 {
76         auto i = find_member(lights, &l, &AttachedLight::light);
77         if(i!=lights.end())
78                 lights.erase(i);
79 }
80
81 void Lighting::detach(unsigned i)
82 {
83         if(i>=lights.size())
84                 return;
85
86         detach(*lights[i].light);
87 }
88
89 const Light *Lighting::get_attached_light(unsigned i) const
90 {
91         return i<lights.size() ? lights[i].light : 0;
92 }
93
94 void Lighting::update_shader_data(ProgramData &sd, const Matrix &) const
95 {
96         sd.uniform("ambient_color", ambient);
97         sd.uniform("sky_color", sky_color);
98         sd.uniform("world_zenith_dir", zenith_direction);
99         sd.uniform("horizon_limit", horizon_angle.radians());
100         sd.uniform("fog_color", fog_color);
101         sd.uniform("fog_density", fog_density);
102
103         for(unsigned i=0; i<lights.size(); ++i)
104                 if(lights[i].light)
105                         lights[i].light->update_shader_data(sd, i);
106 }
107
108 const ProgramData &Lighting::get_shader_data() const
109 {
110         for(unsigned i=0; i<lights.size(); ++i)
111                 if(lights[i].light->get_generation()!=lights[i].generation)
112                 {
113                         lights[i].light->update_shader_data(shdata, i);
114                         lights[i].generation = lights[i].light->get_generation();
115                 }
116
117         return shdata;
118 }
119
120 void Lighting::set_debug_name(const string &name)
121 {
122 #ifdef DEBUG
123         shdata.set_debug_name(name+" [UBO]");
124 #else
125         (void)name;
126 #endif
127 }
128
129
130 DataFile::Loader::ActionMap Lighting::Loader::shared_actions;
131
132 Lighting::Loader::Loader(Lighting &l):
133         CollectionObjectLoader<Lighting>(l, 0)
134 {
135         set_actions(shared_actions);
136 }
137
138 Lighting::Loader::Loader(Lighting &l, Collection &c):
139         CollectionObjectLoader<Lighting>(l, &c)
140 {
141         set_actions(shared_actions);
142 }
143
144 void Lighting::Loader::init_actions()
145 {
146         add("ambient", &Loader::ambient);
147         add("fog_color", &Loader::fog_color);
148         add("fog_density", &Loader::fog_density);
149         add("fog_half_distance", &Loader::fog_half_distance);
150         add("light", &Loader::light);
151         add("light", &Loader::light_inline);
152
153         // Deprecated
154         add("horizon_angle", &Loader::horizon_angle);
155         add("light", &Loader::light_inline_index);
156         add("sky_color", &Loader::sky_color);
157         add("zenith_direction", &Loader::zenith_direction);
158 }
159
160 void Lighting::Loader::ambient(float r, float g, float b)
161 {
162         obj.set_ambient(Color(r, g, b));
163 }
164
165 void Lighting::Loader::fog_color(float r, float g, float b)
166 {
167         obj.set_fog_color(Color(r, g, b));
168 }
169
170 void Lighting::Loader::fog_density(float d)
171 {
172         obj.set_fog_density(d);
173 }
174
175 void Lighting::Loader::fog_half_distance(float d)
176 {
177         obj.set_fog_half_distance(d);
178 }
179
180 #pragma GCC diagnostic push
181 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
182 void Lighting::Loader::horizon_angle(float a)
183 {
184         obj.set_horizon_angle(Geometry::Angle<float>::from_degrees(a));
185 }
186 #pragma GCC diagnostic pop
187
188 void Lighting::Loader::light(const string &name)
189 {
190         obj.attach(get_collection().get<Light>(name));
191 }
192
193 void Lighting::Loader::light_inline()
194 {
195         RefPtr<Light> lgt = new Light;
196         load_sub(*lgt);
197         get_collection().add(format("%s/%d.light", FS::basename(get_source()), obj.lights.size()), lgt.get());
198         obj.attach(*lgt.release());
199 }
200
201 void Lighting::Loader::light_inline_index(unsigned)
202 {
203         light_inline();
204 }
205
206 #pragma GCC diagnostic push
207 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
208 void Lighting::Loader::sky_color(float r, float g, float b)
209 {
210         obj.set_sky_color(Color(r, g, b));
211 }
212
213 void Lighting::Loader::zenith_direction(float x, float y, float z)
214 {
215         obj.set_zenith_direction(Vector3(x, y, z));
216 }
217 #pragma GCC diagnostic pop
218
219 } // namespace GL
220 } // namespace Msp