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