4ef7b3d224711a1306345e2a501bc11d39418cd7
[blender.git] / source / blender / blenkernel / intern / studiolight.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2006-2007 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  *
27  */
28
29 /** \file blender/blenkernel/intern/studiolight.c
30  *  \ingroup bke
31  */
32
33 #include "BKE_studiolight.h"
34
35 #include "BKE_appdir.h"
36 #include "BKE_icons.h"
37
38 #include "BLI_fileops.h"
39 #include "BLI_fileops_types.h"
40 #include "BLI_listbase.h"
41 #include "BLI_math.h"
42 #include "BLI_path_util.h"
43 #include "BLI_rand.h"
44 #include "BLI_string.h"
45
46 #include "DNA_listBase.h"
47
48 #include "IMB_imbuf.h"
49 #include "IMB_imbuf_types.h"
50
51 #include "GPU_texture.h"
52
53 #include "MEM_guardedalloc.h"
54
55
56 /* Statics */
57 static ListBase studiolights;
58 #define STUDIOLIGHT_EXTENSIONS ".jpg", ".hdr"
59 #define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 8
60 #define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT 32
61 #define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH (STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT * 2)
62
63 static const char *STUDIOLIGHT_CAMERA_FOLDER = "studiolights/camera/";
64 static const char *STUDIOLIGHT_WORLD_FOLDER = "studiolights/world/";
65
66 /* FUNCTIONS */
67 static void studiolight_free(struct StudioLight *sl)
68 {
69         for (int index = 0 ; index < 6 ; index ++) {
70                 if (sl->radiance_cubemap_buffers[index] != NULL) {
71                         IMB_freeImBuf(sl->radiance_cubemap_buffers[index]);
72                         sl->radiance_cubemap_buffers[index] = NULL;
73                 }
74
75                 if (sl->equirectangular_radiance_gputexture) {
76                         GPU_texture_free(sl->equirectangular_radiance_gputexture);
77                         sl->equirectangular_radiance_gputexture = NULL;
78                 }
79
80                 if (sl->equirectangular_irradiance_gputexture) {
81                         GPU_texture_free(sl->equirectangular_irradiance_gputexture);
82                         sl->equirectangular_irradiance_gputexture = NULL;
83                 }
84
85                 if (sl->equirectangular_radiance_buffer) {
86                         IMB_freeImBuf(sl->equirectangular_radiance_buffer);
87                         sl->equirectangular_radiance_buffer = NULL;
88                 }
89
90                 if (sl->equirectangular_irradiance_buffer) {
91                         IMB_freeImBuf(sl->equirectangular_irradiance_buffer);
92                         sl->equirectangular_irradiance_buffer = NULL;
93                 }
94         }
95         MEM_freeN(sl);
96 }
97
98 static struct StudioLight *studiolight_create(void)
99 {
100         struct StudioLight *sl = MEM_callocN(sizeof(*sl), __func__);
101         sl->path[0] = 0x00;
102         sl->name[0] = 0x00;
103         sl->flag = 0;
104         sl->index = BLI_listbase_count(&studiolights);
105         sl->radiance_icon_id = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_RADIANCE);
106         sl->irradiance_icon_id = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE);
107
108         for (int index = 0 ; index < 6 ; index ++) {
109                 sl->radiance_cubemap_buffers[index] = NULL;
110         }
111         return sl;
112 }
113
114 static void direction_to_equirectangular(float r[2], const float dir[3])
115 {
116         r[0] = (atan2f(dir[1], dir[0]) - M_PI) / -(M_PI * 2);
117         r[1] = (acosf(dir[2] / 1.0) - M_PI) / -M_PI;
118 }
119
120 static void equirectangular_to_direction(float r[3], float u, float v)
121 {
122         float phi = (-(M_PI * 2)) * u + M_PI;
123         float theta = -M_PI * v + M_PI;
124         float sin_theta = sinf(theta);
125         r[0] = sin_theta * cosf(phi);
126         r[1] = sin_theta * sinf(phi);
127         r[2] = cosf(theta);
128 }
129
130 static void studiolight_calculate_radiance(ImBuf *ibuf, float color[4], const float direction[3])
131 {
132         float uv[2];
133         direction_to_equirectangular(uv, direction);
134         nearest_interpolation_color_wrap(ibuf, NULL, color, uv[0] * ibuf->x, uv[1] * ibuf->y);
135 }
136
137 static void studiolight_calculate_radiance_buffer(
138         ImBuf *ibuf, float *colbuf,
139         const float start_x, const float add_x,
140         const float start_y, const float add_y, const float z,
141         const int index_x, const int index_y, const int index_z)
142 {
143         float direction[3];
144         float yf = start_y;
145         float xf;
146         float *color = colbuf;
147
148         for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y ++, yf += add_y) {
149                 xf = start_x;
150                 for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x ++, xf += add_x) {
151                         direction[index_x] = xf;
152                         direction[index_y] = yf;
153                         direction[index_z] = z;
154                         normalize_v3(direction);
155                         studiolight_calculate_radiance(ibuf, color, direction);
156                         color += 4;
157                 }
158         }
159 }
160
161 static void studiolight_load_equierectangular_image(StudioLight *sl)
162 {
163         if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
164                 ImBuf *ibuf = NULL;
165                 ibuf = IMB_loadiffname(sl->path, 0, NULL);
166                 if (ibuf) {
167                         IMB_float_from_rect(ibuf);
168                         sl->equirectangular_radiance_buffer = ibuf;
169                 }
170         }
171         sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED;
172 }
173
174 static void studiolight_create_equierectangular_radiance_gputexture(StudioLight *sl)
175 {
176         if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
177                 char error[256];
178                 BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED);
179                 ImBuf *ibuf = sl->equirectangular_radiance_buffer;
180                 sl->equirectangular_radiance_gputexture = GPU_texture_create_2D(ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
181                 GPUTexture *tex = sl->equirectangular_radiance_gputexture;
182                 GPU_texture_bind(tex, 0);
183                 GPU_texture_filter_mode(tex, true);
184                 GPU_texture_wrap_mode(tex, true);
185                 GPU_texture_unbind(tex);
186         }
187         sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE;
188 }
189
190 static void studiolight_create_equierectangular_irradiance_gputexture(StudioLight *sl)
191 {
192         if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
193                 char error[256];
194                 BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED);
195                 ImBuf *ibuf = sl->equirectangular_irradiance_buffer;
196                 sl->equirectangular_irradiance_gputexture = GPU_texture_create_2D(ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
197                 GPUTexture *tex = sl->equirectangular_irradiance_gputexture;
198                 GPU_texture_bind(tex, 0);
199                 GPU_texture_filter_mode(tex, true);
200                 GPU_texture_wrap_mode(tex, true);
201                 GPU_texture_unbind(tex);
202         }
203         sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE;
204 }
205
206 static void studiolight_calculate_radiance_cubemap_buffers(StudioLight *sl)
207 {
208         if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
209                 BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED);
210                 ImBuf *ibuf = sl->equirectangular_radiance_buffer;
211                 if (ibuf) {
212                         float *colbuf = MEM_mallocN(SQUARE(STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * sizeof(float[4]), __func__);
213                         const float add = 1.0f / (STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE + 1);
214                         const float start = ((1.0f / STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * 0.5f) - 0.5f;
215
216                         /* front */
217                         studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, 0.5f, 0, 2, 1);
218                         sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS] = IMB_allocFromBuffer(
219                                 NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
220
221                         /* back */
222                         studiolight_calculate_radiance_buffer(ibuf, colbuf, -start, -add, start, add, -0.5f, 0, 2, 1);
223                         sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG] = IMB_allocFromBuffer(
224                                 NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
225
226                         /* left */
227                         studiolight_calculate_radiance_buffer(ibuf, colbuf, -start, -add, start, add, 0.5f, 1, 2, 0);
228                         sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS] = IMB_allocFromBuffer(
229                                 NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
230
231                         /* right */
232                         studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, -0.5f, 1, 2, 0);
233                         sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG] = IMB_allocFromBuffer(
234                                 NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
235
236                         /* top */
237                         studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, -0.5f, 0, 1, 2);
238                         sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG] = IMB_allocFromBuffer(
239                                 NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
240
241                         /* bottom */
242                         studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, -start, -add, 0.5f, 0, 1, 2);
243                         sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS] = IMB_allocFromBuffer(
244                                 NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
245
246 #if 0
247                         IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], "/tmp/studiolight_radiance_left.png", IB_rectfloat);
248                         IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], "/tmp/studiolight_radiance_right.png", IB_rectfloat);
249                         IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], "/tmp/studiolight_radiance_front.png", IB_rectfloat);
250                         IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], "/tmp/studiolight_radiance_back.png", IB_rectfloat);
251                         IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], "/tmp/studiolight_radiance_bottom.png", IB_rectfloat);
252                         IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], "/tmp/studiolight_radiance_top.png", IB_rectfloat);
253 #endif
254                         MEM_freeN(colbuf);
255                 }
256         }
257         sl->flag |= STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED;
258 }
259
260 BLI_INLINE void studiolight_evaluate_radiance_buffer(
261         ImBuf *radiance_buffer, const float normal[3], float color[3], int *hits,
262         int xoffset, int yoffset, int zoffset, float zvalue)
263 {
264         if (radiance_buffer == NULL) {
265                 return;
266         }
267         float angle;
268         float *radiance_color = radiance_buffer->rect_float;
269         float direction[3];
270         for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y ++) {
271                 for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x ++) {
272                         // calculate light direction;
273                         direction[zoffset] = zvalue;
274                         direction[xoffset] = (x / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
275                         direction[yoffset] = (y / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
276                         normalize_v3(direction);
277                         angle = fmax(0.0f, dot_v3v3(direction, normal));
278                         madd_v3_v3fl(color, radiance_color, angle);
279                         (*hits) ++;
280                         radiance_color += 4;
281                 }
282         }
283
284 }
285
286 static void studiolight_calculate_irradiance(StudioLight *sl, float color[3], const float normal[3])
287 {
288         int hits = 0;
289         copy_v3_fl(color, 0.0f);
290
291         /* back */
292         studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], normal, color, &hits, 0, 2, 1, 0.5);
293         /* front */
294         studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], normal, color, &hits, 0, 2, 1, -0.5);
295
296         /* left */
297         studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], normal, color, &hits, 1, 2, 0, 0.5);
298         /* right */
299         studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], normal, color, &hits, 1, 2, 0, -0.5);
300
301         /* top */
302         studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], normal, color, &hits, 0, 1, 2, 0.5);
303         /* bottom */
304         studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], normal, color, &hits, 0, 1, 2, -0.5);
305
306         if (hits) {
307                 mul_v3_fl(color, 3.0 / hits);
308         }
309         else {
310                 copy_v3_fl3(color, 1.0, 0.0, 1.0);
311         }
312 }
313
314
315 static void studiolight_calculate_diffuse_light(StudioLight *sl)
316 {
317         /* init light to black */
318         copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_POS], 0.0f);
319         copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_NEG], 0.0f);
320         copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_POS], 0.0f);
321         copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_NEG], 0.0f);
322         copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_POS], 0.0f);
323         copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_NEG], 0.0f);
324
325         if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
326                 const float normal_x_neg[3] = {-1.0f,  0.0f,  0.0f};
327                 const float normal_x_pos[3] = { 1.0f,  0.0f,  0.0f};
328                 const float normal_y_neg[3] = { 0.0f,  1.0f,  0.0f};
329                 const float normal_y_pos[3] = { 0.0f, -1.0f,  0.0f};
330                 const float normal_z_neg[3] = { 0.0f,  0.0f, -1.0f};
331                 const float normal_z_pos[3] = { 0.0f,  0.0f,  1.0f};
332
333                 BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED);
334
335                 studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_X_POS], normal_x_pos);
336                 studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_X_NEG], normal_x_neg);
337                 studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_Y_POS], normal_y_pos);
338                 studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_Y_NEG], normal_y_neg);
339                 studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_Z_POS], normal_z_pos);
340                 studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_Z_NEG], normal_z_neg);
341         }
342         sl->flag |= STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED;
343 }
344
345 BLI_INLINE void studiolight_evaluate_specular_radiance_buffer(
346         ImBuf *radiance_buffer, const float specular, const float normal[3], float color[3], int *hits,
347         int xoffset, int yoffset, int zoffset, float zvalue)
348 {
349         if (radiance_buffer == NULL) {
350                 return;
351         }
352         float angle;
353         float *radiance_color = radiance_buffer->rect_float;
354         float direction[3];
355         for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y ++) {
356                 for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x ++) {
357                         // calculate light direction;
358                         direction[zoffset] = zvalue;
359                         direction[xoffset] = (x / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
360                         direction[yoffset] = (y / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
361                         normalize_v3(direction);
362                         angle = pow(fmax(0.0f, dot_v3v3(direction, normal)), specular);
363                         madd_v3_v3fl(color, radiance_color, angle);
364                         (*hits) ++;
365                         radiance_color += 4;
366                 }
367         }
368
369 }
370
371 static void studiolight_calculate_specular_irradiance(StudioLight *sl, float color[3], const float normal[3])
372 {
373         const float specular = 4.0f;
374         int hits = 0;
375         copy_v3_fl(color, 0.0f);
376
377         /* back */
378         studiolight_evaluate_specular_radiance_buffer(
379                 sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], specular, normal, color, &hits, 0, 2, 1, 0.5);
380         /* front */
381         studiolight_evaluate_specular_radiance_buffer(
382                 sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], specular, normal, color, &hits, 0, 2, 1, -0.5);
383
384         /* left */
385         studiolight_evaluate_specular_radiance_buffer(
386                 sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], specular, normal, color, &hits, 1, 2, 0, 0.5);
387         /* right */
388         studiolight_evaluate_specular_radiance_buffer(
389                 sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], specular, normal, color, &hits, 1, 2, 0, -0.5);
390
391         /* top */
392         studiolight_evaluate_specular_radiance_buffer(
393                 sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], specular, normal, color, &hits, 0, 1, 2, 0.5);
394         /* bottom */
395         studiolight_evaluate_specular_radiance_buffer(
396                 sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], specular, normal, color, &hits, 0, 1, 2, -0.5);
397
398         if (hits) {
399                 mul_v3_fl(color, specular / hits);
400         }
401         else {
402                 copy_v3_fl3(color, 1.0, 0.0, 1.0);
403         }
404 }
405
406 static void studiolight_calculate_irradiance_equirectangular_image(StudioLight *sl)
407 {
408         if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
409                 BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED);
410
411                 float *colbuf = MEM_mallocN(STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH * STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT * sizeof(float[4]), __func__);
412                 float *color = colbuf;
413                 for (int y = 0; y < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT ; y ++) {
414                         float yf = y / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT;
415
416                         for (int x = 0; x < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH ; x ++) {
417                                 float xf = x / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH;
418                                 float dir[3];
419                                 equirectangular_to_direction(dir, xf, yf);
420                                 studiolight_calculate_specular_irradiance(sl, color, dir);
421                                 color[3] = 1.0f;
422                                 color += 4;
423                         }
424                 }
425                 sl->equirectangular_irradiance_buffer = IMB_allocFromBuffer(
426                         NULL, colbuf,
427                         STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH,
428                         STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT);
429                 MEM_freeN(colbuf);
430 #if 0
431                 IMB_saveiff(sl->equirectangular_irradiance_buffer, "/tmp/studiolight_specular_irradiance.png", IB_rectfloat);
432 #endif
433
434         }
435         sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED;
436 }
437
438 static void studiolight_calculate_light_direction(StudioLight *sl)
439 {
440         float best_light = 0.0;
441         sl->light_direction[0] = 0.0f;
442         sl->light_direction[1] = 0.0f;
443         sl->light_direction[2] = -1.0f;
444
445         if ((sl->flag & STUDIOLIGHT_EXTERNAL_FILE) && (sl->flag & STUDIOLIGHT_ORIENTATION_WORLD)) {
446                 BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED);
447                 ImBuf *ibuf = sl->equirectangular_irradiance_buffer;
448                 if (ibuf) {
449                         /* go over every pixel, determine light, if higher calc direction off the light */
450                         float new_light;
451                         float *color = ibuf->rect_float;
452                         for (int y = 0; y < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT; y ++) {
453                                 for (int x = 0; x < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH; x ++) {
454                                         new_light = color[0] + color[1] + color[2];
455                                         if (new_light > best_light) {
456                                                 float u = x / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH;
457                                                 float v = y / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT;
458                                                 equirectangular_to_direction(sl->light_direction, u, v);
459                                                 SWAP(float, sl->light_direction[0], sl->light_direction[1]);
460                                                 normalize_v3(sl->light_direction);
461                                                 negate_v3(sl->light_direction);
462                                                 best_light = new_light;
463                                         }
464                                         color += 4;
465                                 }
466                         }
467                 }
468         }
469         sl->flag |= STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED;
470 }
471
472 static void studiolight_add_files_from_datafolder(const int folder_id, const char *subfolder, int flag)
473 {
474         StudioLight *sl;
475         struct direntry *dir;
476         const char *folder = BKE_appdir_folder_id(folder_id, subfolder);
477         if (folder) {
478                 uint totfile = BLI_filelist_dir_contents(folder, &dir);
479                 int i;
480                 for (i = 0; i < totfile; i++) {
481                         if ((dir[i].type & S_IFREG)) {
482                                 const char *filename = dir[i].relname;
483                                 const char *path = dir[i].path;
484                                 if (BLI_testextensie_n(filename, STUDIOLIGHT_EXTENSIONS, NULL)) {
485                                         sl = studiolight_create();
486                                         sl->flag = STUDIOLIGHT_EXTERNAL_FILE | flag;
487                                         BLI_strncpy(sl->name, filename, FILE_MAXFILE);
488                                         BLI_strncpy(sl->path, path, FILE_MAXFILE);
489                                         BLI_addtail(&studiolights, sl);
490                                 }
491                         }
492                 }
493                 BLI_filelist_free(dir, totfile);
494                 dir = NULL;
495         }
496
497 }
498
499 static int studiolight_flag_cmp_order(const StudioLight *sl)
500 {
501         /* Internal studiolights before external studio lights */
502         if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
503                 return 1;
504         }
505         return 0;
506 }
507
508 static int studiolight_cmp(const void *a, const void *b)
509 {
510         const StudioLight *sl1 = a;
511         const StudioLight *sl2 = b;
512
513         const int flagorder1 = studiolight_flag_cmp_order(sl1);
514         const int flagorder2 = studiolight_flag_cmp_order(sl2);
515
516         if (flagorder1 < flagorder2) {
517                 return -1;
518         }
519         else if (flagorder1 > flagorder2) {
520                 return 1;
521         }
522         else {
523                 return BLI_strcasecmp(sl1->name, sl2->name);
524         }
525 }
526
527 /* icons */
528 static uint *studiolight_radiance_preview(StudioLight *sl, int icon_size)
529 {
530         BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED);
531
532         uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__);
533         int icon_center = icon_size / 2;
534         float sphere_radius = icon_center * 0.9;
535
536         int offset = 0;
537         for (int y = 0; y < icon_size; y++) {
538                 float dy = y - icon_center;
539                 for (int x = 0; x < icon_size; x++) {
540                         float dx = x - icon_center;
541                         /* calculate aliasing */
542                         float alias = 0;
543                         const float alias_step = 0.333;
544                         for (float ay = dy - 0.5; ay < dy + 0.5; ay += alias_step) {
545                                 for (float ax = dx - 0.5; ax < dx + 0.5; ax += alias_step) {
546                                         if (sqrt(ay * ay + ax * ax) < sphere_radius) {
547                                                 alias += alias_step * alias_step;
548                                         }
549                                 }
550                         }
551                         uint pixelresult = 0x0;
552                         uint alias_i = clamp_i(alias * 256, 0, 255);
553                         if (alias_i != 0) {
554                                 /* calculate normal */
555                                 uint alias_mask = alias_i << 24;
556                                 float incoming[3];
557                                 copy_v3_fl3(incoming, 0.0, 1.0, 0.0);
558
559                                 float normal[3];
560                                 normal[0] = dx / sphere_radius;
561                                 normal[2] = dy / sphere_radius;
562                                 normal[1] = -sqrt(-(normal[0] * normal[0]) - (normal[2] * normal[2]) + 1);
563                                 normalize_v3(normal);
564
565                                 float direction[3];
566                                 reflect_v3_v3v3(direction, incoming, normal);
567
568                                 float color[4];
569                                 studiolight_calculate_radiance(sl->equirectangular_radiance_buffer, color, direction);
570
571                                 pixelresult = rgb_to_cpack(
572                                         linearrgb_to_srgb(color[0]),
573                                         linearrgb_to_srgb(color[1]),
574                                         linearrgb_to_srgb(color[2])) | alias_mask;
575                         }
576                         rect[offset++] = pixelresult;
577                 }
578         }
579         return rect;
580 }
581
582 static uint *studiolight_irradiance_preview(StudioLight *sl, int icon_size)
583 {
584         if (/*!(sl->flag & STUDIOLIGHT_EXTERNAL_FILE)*/ 1) {
585
586                 BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED);
587
588                 uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__);
589                 int icon_center = icon_size / 2;
590                 float sphere_radius = icon_center * 0.9;
591
592                 int offset = 0;
593                 for (int y = 0; y < icon_size; y++) {
594                         float dy = y - icon_center;
595                         for (int x = 0; x < icon_size; x++) {
596                                 float dx = x - icon_center;
597                                 /* calculate aliasing */
598                                 float alias = 0;
599                                 const float alias_step = 0.333;
600                                 for (float ay = dy - 0.5; ay < dy + 0.5; ay += alias_step) {
601                                         for (float ax = dx - 0.5; ax < dx + 0.5; ax += alias_step) {
602                                                 if (sqrt(ay * ay + ax * ax) < sphere_radius) {
603                                                         alias += alias_step * alias_step;
604                                                 }
605                                         }
606                                 }
607                                 uint pixelresult = 0x0;
608                                 uint alias_i = clamp_i(alias * 256, 0, 255);
609                                 if (alias_i != 0) {
610                                         /* calculate normal */
611                                         uint alias_mask = alias_i << 24;
612                                         float normal[3];
613                                         normal[0] = dx / sphere_radius;
614                                         normal[1] = dy / sphere_radius;
615                                         normal[2] = sqrt(-(normal[0] * normal[0]) - (normal[1] * normal[1]) + 1);
616                                         normalize_v3(normal);
617
618                                         float color[3];
619                                         mul_v3_v3fl(color, sl->diffuse_light[STUDIOLIGHT_X_POS], clamp_f(normal[0], 0.0, 1.0));
620                                         interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_X_NEG], clamp_f(-normal[0], 0.0, 1.0));
621                                         interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_Z_POS], clamp_f(normal[1], 0.0, 1.0));
622                                         interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_Z_NEG], clamp_f(-normal[1], 0.0, 1.0));
623                                         interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_Y_POS], clamp_f(normal[2], 0.0, 1.0));
624
625                                         pixelresult = rgb_to_cpack(
626                                                 linearrgb_to_srgb(color[0]),
627                                                 linearrgb_to_srgb(color[1]),
628                                                 linearrgb_to_srgb(color[2])) | alias_mask;
629                                 }
630                                 rect[offset++] = pixelresult;
631                         }
632                 }
633                 return rect;
634         }
635         else {
636                 BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED);
637
638                 uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__);
639                 int icon_center = icon_size / 2;
640                 float sphere_radius = icon_center * 0.9;
641
642                 int offset = 0;
643                 for (int y = 0; y < icon_size; y++) {
644                         float dy = y - icon_center;
645                         for (int x = 0; x < icon_size; x++) {
646                                 float dx = x - icon_center;
647                                 /* calculate aliasing */
648                                 float alias = 0;
649                                 const float alias_step = 0.333;
650                                 for (float ay = dy - 0.5; ay < dy + 0.5; ay += alias_step) {
651                                         for (float ax = dx - 0.5; ax < dx + 0.5; ax += alias_step) {
652                                                 if (sqrt(ay * ay + ax * ax) < sphere_radius) {
653                                                         alias += alias_step * alias_step;
654                                                 }
655                                         }
656                                 }
657                                 uint pixelresult = 0x0;
658                                 uint alias_i = clamp_i(alias * 256, 0, 255);
659                                 if (alias_i != 0) {
660                                         /* calculate normal */
661                                         uint alias_mask = alias_i << 24;
662                                         float incoming[3];
663                                         copy_v3_fl3(incoming, 0.0, 1.0, 0.0);
664
665                                         float normal[3];
666                                         normal[0] = dx / sphere_radius;
667                                         normal[2] = dy / sphere_radius;
668                                         normal[1] = -sqrt(-(normal[0] * normal[0]) - (normal[2] * normal[2]) + 1);
669                                         normalize_v3(normal);
670
671                                         float direction[3];
672                                         reflect_v3_v3v3(direction, incoming, normal);
673
674                                         float color[4];
675                                         studiolight_calculate_radiance(sl->equirectangular_irradiance_buffer, color, direction);
676
677                                         pixelresult = rgb_to_cpack(
678                                                 linearrgb_to_srgb(color[0]),
679                                                 linearrgb_to_srgb(color[1]),
680                                                 linearrgb_to_srgb(color[2])) | alias_mask;
681                                 }
682                                 rect[offset++] = pixelresult;
683                         }
684                 }
685                 return rect;
686         }
687 }
688
689 /* API */
690 void BKE_studiolight_init(void)
691 {
692         StudioLight *sl;
693         /* go over the preset folder and add a studiolight for every image with its path */
694         /* order studio lights by name */
695         /* Also reserve icon space for it. */
696         /* Add default studio light */
697         sl = studiolight_create();
698         BLI_strncpy(sl->name, "INTERNAL_01", FILE_MAXFILE);
699         sl->flag = STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED | STUDIOLIGHT_ORIENTATION_CAMERA;
700         copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_POS], 0.0f);
701         copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_NEG], 0.0f);
702         copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_POS], 0.8f);
703         copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_NEG], 0.05f);
704         copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_POS], 0.2f);
705         copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_NEG], 0.1f);
706         BLI_addtail(&studiolights, sl);
707
708         studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA);
709         studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,   STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA);
710         studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER,  STUDIOLIGHT_ORIENTATION_WORLD);
711         studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,   STUDIOLIGHT_WORLD_FOLDER,  STUDIOLIGHT_ORIENTATION_WORLD);
712
713         /* sort studio lights on filename. */
714         BLI_listbase_sort(&studiolights, studiolight_cmp);
715 }
716
717 void BKE_studiolight_free(void)
718 {
719         struct StudioLight *sl;
720         while ((sl = BLI_pophead(&studiolights))) {
721                 studiolight_free(sl);
722         }
723 }
724
725 struct StudioLight *BKE_studiolight_find(const char *name, int flag)
726 {
727         LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
728                 if (STREQLEN(sl->name, name, FILE_MAXFILE)) {
729                         if ((sl->flag & flag) == flag) {
730                                 return sl;
731                         }
732                         else {
733                                 /* flags do not match, so use default */
734                                 return studiolights.first;
735                         }
736                 }
737         }
738         /* When not found, use the default studio light */
739         return studiolights.first;
740 }
741
742 struct StudioLight *BKE_studiolight_findindex(int index)
743 {
744         LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
745                 if (sl->index == index) {
746                         return sl;
747                 }
748         }
749         /* When not found, use the default studio light */
750         return studiolights.first;
751 }
752
753 const struct ListBase *BKE_studiolight_listbase(void)
754 {
755         return &studiolights;
756 }
757
758 uint *BKE_studiolight_preview(StudioLight *sl, int icon_size, int icon_id_type)
759 {
760         if (icon_id_type == STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE) {
761                 return studiolight_irradiance_preview(sl, icon_size);
762         }
763         else {
764                 return studiolight_radiance_preview(sl, icon_size);
765         }
766 }
767
768 void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
769 {
770         if ((sl->flag & flag) == flag) {
771                 return;
772         }
773
774         if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED)) {
775                 studiolight_load_equierectangular_image(sl);
776         }
777         if ((flag & STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED)) {
778                 studiolight_calculate_radiance_cubemap_buffers(sl);
779         }
780         if ((flag & STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED)) {
781                 studiolight_calculate_diffuse_light(sl);
782         }
783         if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE)) {
784                 studiolight_create_equierectangular_radiance_gputexture(sl);
785         }
786         if ((flag & STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED)) {
787                 studiolight_calculate_light_direction(sl);
788         }
789         if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE)) {
790                 studiolight_create_equierectangular_irradiance_gputexture(sl);
791         }
792         if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED)) {
793                 studiolight_calculate_irradiance_equirectangular_image(sl);
794         }
795 }