Blender  V2.93
studiolight.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2006-2007 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "BKE_studiolight.h"
25 
26 #include "BKE_appdir.h"
27 #include "BKE_icons.h"
28 
29 #include "BLI_dynstr.h"
30 #include "BLI_fileops.h"
31 #include "BLI_fileops_types.h"
32 #include "BLI_linklist.h"
33 #include "BLI_listbase.h"
34 #include "BLI_math.h"
35 #include "BLI_math_color.h"
36 #include "BLI_path_util.h"
37 #include "BLI_string.h"
38 #include "BLI_string_utils.h"
39 
40 #include "DNA_listBase.h"
41 
42 #include "IMB_imbuf.h"
43 #include "IMB_imbuf_types.h"
44 
45 #include "GPU_texture.h"
46 
47 #include "MEM_guardedalloc.h"
48 
50 
51 /* Statics */
53 static int last_studiolight_id = 0;
54 #define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 96
55 #define STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT 32
56 #define STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH (STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT * 2)
57 #define STUDIOLIGHT_PASSNAME_DIFFUSE "diffuse"
58 #define STUDIOLIGHT_PASSNAME_SPECULAR "specular"
59 /* Temporarily disabled due to the creation of textures with -nan(ind)s */
60 #define STUDIOLIGHT_SH_WINDOWING 0.0f /* 0.0 is disabled */
61 
62 /*
63  * Disable this option so caches are not loaded from disk
64  * Do not checking with this commented out.
65  */
66 #define STUDIOLIGHT_LOAD_CACHED_FILES
67 
68 static const char *STUDIOLIGHT_LIGHTS_FOLDER = "studiolights/studio/";
69 static const char *STUDIOLIGHT_WORLD_FOLDER = "studiolights/world/";
70 static const char *STUDIOLIGHT_MATCAP_FOLDER = "studiolights/matcap/";
71 
72 static const char *STUDIOLIGHT_WORLD_DEFAULT = "forest.exr";
73 static const char *STUDIOLIGHT_MATCAP_DEFAULT = "basic_1.exr";
74 
75 /* ITER MACRO */
76 
90 #define ITER_PIXELS(type, src, channels, width, height) \
91  { \
92  float texel_size[2]; \
93  texel_size[0] = 1.0f / width; \
94  texel_size[1] = 1.0f / height; \
95  type(*pixel_)[channels] = (type(*)[channels])src; \
96  for (float y = 0.5 * texel_size[1]; y < 1.0; y += texel_size[1]) { \
97  for (float x = 0.5 * texel_size[0]; x < 1.0; x += texel_size[0], pixel_++) { \
98  type *pixel = *pixel_;
99 
100 #define ITER_PIXELS_END \
101  } \
102  } \
103  } \
104  ((void)0)
105 
106 /* FUNCTIONS */
107 #define IMB_SAFE_FREE(p) \
108  do { \
109  if (p) { \
110  IMB_freeImBuf(p); \
111  p = NULL; \
112  } \
113  } while (0)
114 
115 #define GPU_TEXTURE_SAFE_FREE(p) \
116  do { \
117  if (p) { \
118  GPU_texture_free(p); \
119  p = NULL; \
120  } \
121  } while (0)
122 
123 static void studiolight_free(struct StudioLight *sl)
124 {
125 #define STUDIOLIGHT_DELETE_ICON(s) \
126  do { \
127  if (s != 0) { \
128  BKE_icon_delete(s); \
129  s = 0; \
130  } \
131  } while (0)
132 
133  if (sl->free_function) {
134  sl->free_function(sl, sl->free_function_data);
135  }
140 #undef STUDIOLIGHT_DELETE_ICON
141 
142  for (int index = 0; index < 6; index++) {
144  }
155  MEM_SAFE_FREE(sl);
156 }
157 
159 {
160  struct StudioLight *sl = MEM_callocN(sizeof(*sl), __func__);
161  sl->path[0] = 0x00;
162  sl->name[0] = 0x00;
163  sl->path_irr_cache = NULL;
164  sl->path_sh_cache = NULL;
165  sl->free_function = NULL;
166  sl->flag = flag;
167  sl->index = ++last_studiolight_id;
170  }
171  else if (flag & STUDIOLIGHT_TYPE_MATCAP) {
175  }
176  else {
178  }
179 
180  for (int index = 0; index < 6; index++) {
182  }
183 
184  return sl;
185 }
186 
187 #define STUDIOLIGHT_FILE_VERSION 1
188 
189 #define READ_VAL(type, parser, id, val, lines) \
190  do { \
191  for (LinkNode *line = lines; line; line = line->next) { \
192  char *val_str, *str = line->link; \
193  if ((val_str = strstr(str, id " "))) { \
194  val_str += sizeof(id); /* Skip id + spacer. */ \
195  val = parser(val_str); \
196  } \
197  } \
198  } while (0)
199 
200 #define READ_FVAL(id, val, lines) READ_VAL(float, atof, id, val, lines)
201 #define READ_IVAL(id, val, lines) READ_VAL(int, atoi, id, val, lines)
202 
203 #define READ_VEC3(id, val, lines) \
204  do { \
205  READ_FVAL(id ".x", val[0], lines); \
206  READ_FVAL(id ".y", val[1], lines); \
207  READ_FVAL(id ".z", val[2], lines); \
208  } while (0)
209 
210 #define READ_SOLIDLIGHT(sl, i, lines) \
211  do { \
212  READ_IVAL("light[" STRINGIFY(i) "].flag", sl[i].flag, lines); \
213  READ_FVAL("light[" STRINGIFY(i) "].smooth", sl[i].smooth, lines); \
214  READ_VEC3("light[" STRINGIFY(i) "].col", sl[i].col, lines); \
215  READ_VEC3("light[" STRINGIFY(i) "].spec", sl[i].spec, lines); \
216  READ_VEC3("light[" STRINGIFY(i) "].vec", sl[i].vec, lines); \
217  } while (0)
218 
220 {
221  LinkNode *lines = BLI_file_read_as_lines(sl->path);
222  if (lines) {
223  READ_VEC3("light_ambient", sl->light_ambient, lines);
224  READ_SOLIDLIGHT(sl->light, 0, lines);
225  READ_SOLIDLIGHT(sl->light, 1, lines);
226  READ_SOLIDLIGHT(sl->light, 2, lines);
227  READ_SOLIDLIGHT(sl->light, 3, lines);
228  }
229  BLI_file_free_lines(lines);
230 }
231 
232 #undef READ_SOLIDLIGHT
233 #undef READ_VEC3
234 #undef READ_IVAL
235 #undef READ_FVAL
236 
237 #define WRITE_FVAL(str, id, val) (BLI_dynstr_appendf(str, id " %f\n", val))
238 #define WRITE_IVAL(str, id, val) (BLI_dynstr_appendf(str, id " %d\n", val))
239 
240 #define WRITE_VEC3(str, id, val) \
241  do { \
242  WRITE_FVAL(str, id ".x", val[0]); \
243  WRITE_FVAL(str, id ".y", val[1]); \
244  WRITE_FVAL(str, id ".z", val[2]); \
245  } while (0)
246 
247 #define WRITE_SOLIDLIGHT(str, sl, i) \
248  do { \
249  WRITE_IVAL(str, "light[" STRINGIFY(i) "].flag", sl[i].flag); \
250  WRITE_FVAL(str, "light[" STRINGIFY(i) "].smooth", sl[i].smooth); \
251  WRITE_VEC3(str, "light[" STRINGIFY(i) "].col", sl[i].col); \
252  WRITE_VEC3(str, "light[" STRINGIFY(i) "].spec", sl[i].spec); \
253  WRITE_VEC3(str, "light[" STRINGIFY(i) "].vec", sl[i].vec); \
254  } while (0)
255 
257 {
258  FILE *fp = BLI_fopen(sl->path, "wb");
259  if (fp) {
261 
262  /* Very dumb ascii format. One value per line separated by a space. */
264  WRITE_VEC3(str, "light_ambient", sl->light_ambient);
265  WRITE_SOLIDLIGHT(str, sl->light, 0);
266  WRITE_SOLIDLIGHT(str, sl->light, 1);
267  WRITE_SOLIDLIGHT(str, sl->light, 2);
268  WRITE_SOLIDLIGHT(str, sl->light, 3);
269 
270  char *cstr = BLI_dynstr_get_cstring(str);
271 
272  fwrite(cstr, BLI_dynstr_get_len(str), 1, fp);
273  fclose(fp);
274 
275  MEM_freeN(cstr);
277  }
278 }
279 
280 #undef WRITE_SOLIDLIGHT
281 #undef WRITE_VEC3
282 #undef WRITE_IVAL
283 #undef WRITE_FVAL
284 
285 static void direction_to_equirect(float r[2], const float dir[3])
286 {
287  r[0] = (atan2f(dir[1], dir[0]) - M_PI) / -(M_PI * 2);
288  r[1] = (acosf(dir[2] / 1.0) - M_PI) / -M_PI;
289 }
290 
291 static void equirect_to_direction(float r[3], float u, float v)
292 {
293  float phi = (-(M_PI * 2)) * u + M_PI;
294  float theta = -M_PI * v + M_PI;
295  float sin_theta = sinf(theta);
296  r[0] = sin_theta * cosf(phi);
297  r[1] = sin_theta * sinf(phi);
298  r[2] = cosf(theta);
299 }
300 
301 static void UNUSED_FUNCTION(direction_to_cube_face_uv)(float r_uv[2],
302  int *r_face,
303  const float dir[3])
304 {
305  if (fabsf(dir[0]) > fabsf(dir[1]) && fabsf(dir[0]) > fabsf(dir[2])) {
306  bool is_pos = (dir[0] > 0.0f);
307  *r_face = is_pos ? STUDIOLIGHT_X_POS : STUDIOLIGHT_X_NEG;
308  r_uv[0] = dir[2] / fabsf(dir[0]) * (is_pos ? 1 : -1);
309  r_uv[1] = dir[1] / fabsf(dir[0]) * -1;
310  }
311  else if (fabsf(dir[1]) > fabsf(dir[0]) && fabsf(dir[1]) > fabsf(dir[2])) {
312  bool is_pos = (dir[1] > 0.0f);
313  *r_face = is_pos ? STUDIOLIGHT_Y_POS : STUDIOLIGHT_Y_NEG;
314  r_uv[0] = dir[0] / fabsf(dir[1]) * 1;
315  r_uv[1] = dir[2] / fabsf(dir[1]) * (is_pos ? -1 : 1);
316  }
317  else {
318  bool is_pos = (dir[2] > 0.0f);
319  *r_face = is_pos ? STUDIOLIGHT_Z_NEG : STUDIOLIGHT_Z_POS;
320  r_uv[0] = dir[0] / fabsf(dir[2]) * (is_pos ? -1 : 1);
321  r_uv[1] = dir[1] / fabsf(dir[2]) * -1;
322  }
323  r_uv[0] = r_uv[0] * 0.5f + 0.5f;
324  r_uv[1] = r_uv[1] * 0.5f + 0.5f;
325 }
326 
327 static void cube_face_uv_to_direction(float r_dir[3], float x, float y, int face)
328 {
329  const float conversion_matrices[6][3][3] = {
330  {{0.0f, 0.0f, 1.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}},
331  {{0.0f, 0.0f, -1.0f}, {0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}},
332  {{1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 0.0f}},
333  {{1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {0.0f, -1.0f, 0.0f}},
334  {{1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, -1.0f}},
335  {{-1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}},
336  };
337 
338  copy_v3_fl3(r_dir, x * 2.0f - 1.0f, y * 2.0f - 1.0f, 1.0f);
339  mul_m3_v3(conversion_matrices[face], r_dir);
340  normalize_v3(r_dir);
341 }
342 
343 typedef struct MultilayerConvertContext {
345  float *diffuse_pass;
349 
350 static void *studiolight_multilayer_addview(void *UNUSED(base), const char *UNUSED(view_name))
351 {
352  return NULL;
353 }
354 static void *studiolight_multilayer_addlayer(void *base, const char *UNUSED(layer_name))
355 {
356  return base;
357 }
358 
359 /* Convert a multilayer pass to ImBuf channel 4 float buffer.
360  * NOTE: Parameter rect will become invalid. Do not use rect after calling this
361  * function */
363  float *rect,
364  const unsigned int channels)
365 {
366  if (channels == 4) {
367  return rect;
368  }
369 
370  float *new_rect = MEM_callocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__);
371 
373  rect,
374  channels,
377  false,
378  ibuf->x,
379  ibuf->y,
380  ibuf->x,
381  ibuf->x);
382 
383  MEM_freeN(rect);
384  return new_rect;
385 }
386 
387 static void studiolight_multilayer_addpass(void *base,
388  void *UNUSED(lay),
389  const char *pass_name,
390  float *rect,
391  int num_channels,
392  const char *UNUSED(chan_id),
393  const char *UNUSED(view_name))
394 {
395  MultilayerConvertContext *ctx = base;
396  /* NOTE: This function must free pass pixels data if it is not used, this
397  * is how IMB_exr_multilayer_convert() is working. */
398  /* If we've found a first combined pass, skip all the rest ones. */
399  if (STREQ(pass_name, STUDIOLIGHT_PASSNAME_DIFFUSE)) {
400  ctx->diffuse_pass = rect;
401  ctx->num_diffuse_channels = num_channels;
402  }
403  else if (STREQ(pass_name, STUDIOLIGHT_PASSNAME_SPECULAR)) {
404  ctx->specular_pass = rect;
405  ctx->num_specular_channels = num_channels;
406  }
407  else {
408  MEM_freeN(rect);
409  }
410 }
411 
413 {
414  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
416  ImBuf *specular_ibuf = NULL;
417  ImBuf *diffuse_ibuf = NULL;
418  const bool failed = (ibuf == NULL);
419 
420  if (ibuf) {
421  if (ibuf->ftype == IMB_FTYPE_OPENEXR && ibuf->userdata) {
422  /* the read file is a multilayered openexr file (userdata != NULL)
423  * This file is currently only supported for MATCAPS where
424  * the first found 'diffuse' pass will be used for diffuse lighting
425  * and the first found 'specular' pass will be used for specular lighting */
426  MultilayerConvertContext ctx = {0};
428  &ctx,
432 
433  /* `ctx.diffuse_pass` and `ctx.specular_pass` can be freed inside
434  * `studiolight_multilayer_convert_pass` when conversion happens.
435  * When not converted we move the ownership of the buffer to the
436  * `converted_pass`. We only need to free `converted_pass` as it holds
437  * the unmodified allocation from the `ctx.*_pass` or the converted data.
438  */
439  if (ctx.diffuse_pass != NULL) {
440  float *converted_pass = studiolight_multilayer_convert_pass(
441  ibuf, ctx.diffuse_pass, ctx.num_diffuse_channels);
442  diffuse_ibuf = IMB_allocFromBuffer(
443  NULL, converted_pass, ibuf->x, ibuf->y, ctx.num_diffuse_channels);
444  MEM_freeN(converted_pass);
445  }
446 
447  if (ctx.specular_pass != NULL) {
448  float *converted_pass = studiolight_multilayer_convert_pass(
449  ibuf, ctx.specular_pass, ctx.num_specular_channels);
450  specular_ibuf = IMB_allocFromBuffer(
451  NULL, converted_pass, ibuf->x, ibuf->y, ctx.num_specular_channels);
452  MEM_freeN(converted_pass);
453  }
454 
455  IMB_exr_close(ibuf->userdata);
456  ibuf->userdata = NULL;
457  IMB_freeImBuf(ibuf);
458  ibuf = NULL;
459  }
460  else {
461  /* read file is an single layer openexr file or the read file isn't
462  * an openexr file */
463  IMB_float_from_rect(ibuf);
464  diffuse_ibuf = ibuf;
465  ibuf = NULL;
466  }
467  }
468 
469  if (diffuse_ibuf == NULL) {
470  /* Create 1x1 diffuse buffer, in case image failed to load or if there was
471  * only a specular pass in the multilayer file or no passes were found. */
472  const float black[4] = {0.0f, 0.0f, 0.0f, 1.0f};
473  const float magenta[4] = {1.0f, 0.0f, 1.0f, 1.0f};
474  diffuse_ibuf = IMB_allocFromBuffer(
475  NULL, (failed || (specular_ibuf == NULL)) ? magenta : black, 1, 1, 4);
476  }
477 
478  if ((sl->flag & STUDIOLIGHT_TYPE_MATCAP)) {
479  sl->matcap_diffuse.ibuf = diffuse_ibuf;
480  sl->matcap_specular.ibuf = specular_ibuf;
481  if (specular_ibuf != NULL) {
483  }
484  }
485  else {
486  sl->equirect_radiance_buffer = diffuse_ibuf;
487  if (specular_ibuf != NULL) {
488  IMB_freeImBuf(specular_ibuf);
489  }
490  }
491  }
492 
494 }
495 
497 {
498  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
500  ImBuf *ibuf = sl->equirect_radiance_buffer;
501 
503  "studiolight_radiance", ibuf->x, ibuf->y, 1, GPU_RGBA16F, ibuf->rect_float);
506  GPU_texture_wrap_mode(tex, true, true);
507  }
509 }
510 
512 {
513  BLI_assert(sli->ibuf);
514  ImBuf *ibuf = sli->ibuf;
515  float *gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__);
516 
517  const float(*offset4)[4] = (const float(*)[4])ibuf->rect_float;
518  float(*offset3)[3] = (float(*)[3])gpu_matcap_3components;
519  for (int i = 0; i < ibuf->x * ibuf->y; i++, offset4++, offset3++) {
520  copy_v3_v3(*offset3, *offset4);
521  }
522 
523  sli->gputexture = GPU_texture_create_2d("matcap", ibuf->x, ibuf->y, 1, GPU_R11F_G11F_B10F, NULL);
524  GPU_texture_update(sli->gputexture, GPU_DATA_FLOAT, gpu_matcap_3components);
525 
526  MEM_SAFE_FREE(gpu_matcap_3components);
527 }
528 
530 {
531  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
532  if (sl->flag & STUDIOLIGHT_TYPE_MATCAP) {
535  }
536  }
538 }
540 {
541  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
542  if (sl->flag & STUDIOLIGHT_TYPE_MATCAP) {
544  if (sl->matcap_specular.ibuf) {
546  }
547  }
548  }
550 }
551 
553 {
554  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
556  ImBuf *ibuf = sl->equirect_irradiance_buffer;
558  "studiolight_irradiance", ibuf->x, ibuf->y, 1, GPU_RGBA16F, ibuf->rect_float);
561  GPU_texture_wrap_mode(tex, true, true);
562  }
564 }
565 
566 static void studiolight_calculate_radiance(ImBuf *ibuf, float color[4], const float direction[3])
567 {
568  float uv[2];
569  direction_to_equirect(uv, direction);
570  nearest_interpolation_color_wrap(ibuf, NULL, color, uv[0] * ibuf->x, uv[1] * ibuf->y);
571 }
572 
574  float *colbuf,
575  const int index_x,
576  const int index_y,
577  const int index_z,
578  const float xsign,
579  const float ysign,
580  const float zsign)
581 {
582  ITER_PIXELS (
584  float direction[3];
585  direction[index_x] = xsign * (x - 0.5f);
586  direction[index_y] = ysign * (y - 0.5f);
587  direction[index_z] = zsign * 0.5f;
588  normalize_v3(direction);
589  studiolight_calculate_radiance(ibuf, pixel, direction);
590  }
592 }
593 
595 {
596  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
598  ImBuf *ibuf = sl->equirect_radiance_buffer;
599  if (ibuf) {
600  float *colbuf = MEM_malloc_arrayN(
601  square_i(STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE), sizeof(float[4]), __func__);
602 
603  /* front */
604  studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 2, 1, 1, -1, 1);
607 
608  /* back */
609  studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 2, 1, 1, 1, -1);
612 
613  /* left */
614  studiolight_calculate_radiance_buffer(ibuf, colbuf, 2, 1, 0, 1, -1, 1);
617 
618  /* right */
619  studiolight_calculate_radiance_buffer(ibuf, colbuf, 2, 1, 0, -1, -1, -1);
622 
623  /* top */
624  studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 1, 2, -1, -1, 1);
627 
628  /* bottom */
629  studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 1, 2, 1, -1, -1);
632 
633 #if 0
635  "/tmp/studiolight_radiance_left.png",
636  IB_rectfloat);
638  "/tmp/studiolight_radiance_right.png",
639  IB_rectfloat);
641  "/tmp/studiolight_radiance_front.png",
642  IB_rectfloat);
644  "/tmp/studiolight_radiance_back.png",
645  IB_rectfloat);
647  "/tmp/studiolight_radiance_bottom.png",
648  IB_rectfloat);
650  "/tmp/studiolight_radiance_top.png",
651  IB_rectfloat);
652 #endif
653  MEM_freeN(colbuf);
654  }
655  }
657 }
658 
659 /*
660  * Spherical Harmonics
661  */
662 BLI_INLINE float area_element(float x, float y)
663 {
664  return atan2(x * y, sqrtf(x * x + y * y + 1));
665 }
666 
667 BLI_INLINE float texel_solid_angle(float x, float y, float halfpix)
668 {
669  float v1x = (x - halfpix) * 2.0f - 1.0f;
670  float v1y = (y - halfpix) * 2.0f - 1.0f;
671  float v2x = (x + halfpix) * 2.0f - 1.0f;
672  float v2y = (y + halfpix) * 2.0f - 1.0f;
673 
674  return area_element(v1x, v1y) - area_element(v1x, v2y) - area_element(v2x, v1y) +
675  area_element(v2x, v2y);
676 }
677 
679  float normal[3], float *weight, int face, float x, float y)
680 {
681  const float halfpix = 0.5f / STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE;
683  *weight = texel_solid_angle(x, y, halfpix);
684 }
685 
687 {
688  float weight_accum = 0.0f;
689  memset(sh, 0, sizeof(float[3]) * STUDIOLIGHT_SH_COEFS_LEN);
690 
691  for (int face = 0; face < 6; face++) {
692  ITER_PIXELS (float,
694  4,
697  float color[3], cubevec[3], weight;
698  studiolight_calculate_cubemap_vector_weight(cubevec, &weight, face, x, y);
699  mul_v3_v3fl(color, pixel, weight);
700  weight_accum += weight;
701 
702  int i = 0;
703  /* L0 */
704  madd_v3_v3fl(sh[i++], color, 0.2822095f);
705 #if STUDIOLIGHT_SH_BANDS > 1 /* L1 */
706  const float nx = cubevec[0];
707  const float ny = cubevec[1];
708  const float nz = cubevec[2];
709  madd_v3_v3fl(sh[i++], color, -0.488603f * nz);
710  madd_v3_v3fl(sh[i++], color, 0.488603f * ny);
711  madd_v3_v3fl(sh[i++], color, -0.488603f * nx);
712 #endif
713 #if STUDIOLIGHT_SH_BANDS > 2 /* L2 */
714  const float nx2 = SQUARE(nx);
715  const float ny2 = SQUARE(ny);
716  const float nz2 = SQUARE(nz);
717  madd_v3_v3fl(sh[i++], color, 1.092548f * nx * nz);
718  madd_v3_v3fl(sh[i++], color, -1.092548f * nz * ny);
719  madd_v3_v3fl(sh[i++], color, 0.315392f * (3.0f * ny2 - 1.0f));
720  madd_v3_v3fl(sh[i++], color, 1.092548f * nx * ny);
721  madd_v3_v3fl(sh[i++], color, 0.546274f * (nx2 - nz2));
722 #endif
723  /* Bypass L3 Because final irradiance does not need it. */
724 #if STUDIOLIGHT_SH_BANDS > 4 /* L4 */
725  const float nx4 = SQUARE(nx2);
726  const float ny4 = SQUARE(ny2);
727  const float nz4 = SQUARE(nz2);
728  madd_v3_v3fl(sh[i++], color, 2.5033429417967046f * nx * nz * (nx2 - nz2));
729  madd_v3_v3fl(sh[i++], color, -1.7701307697799304f * nz * ny * (3.0f * nx2 - nz2));
730  madd_v3_v3fl(sh[i++], color, 0.9461746957575601f * nz * nx * (-1.0f + 7.0f * ny2));
731  madd_v3_v3fl(sh[i++], color, -0.6690465435572892f * nz * ny * (-3.0f + 7.0f * ny2));
732  madd_v3_v3fl(sh[i++], color, (105.0f * ny4 - 90.0f * ny2 + 9.0f) / 28.359261614f);
733  madd_v3_v3fl(sh[i++], color, -0.6690465435572892f * nx * ny * (-3.0f + 7.0f * ny2));
734  madd_v3_v3fl(sh[i++], color, 0.9461746957575601f * (nx2 - nz2) * (-1.0f + 7.0f * ny2));
735  madd_v3_v3fl(sh[i++], color, -1.7701307697799304f * nx * ny * (nx2 - 3.0f * nz2));
736  madd_v3_v3fl(sh[i++], color, 0.6258357354491761f * (nx4 - 6.0f * nz2 * nx2 + nz4));
737 #endif
738  }
740  }
741 
742  /* The sum of solid angle should be equal to the solid angle of the sphere (4 PI),
743  * so normalize in order to make our weightAccum exactly match 4 PI. */
744  for (int i = 0; i < STUDIOLIGHT_SH_COEFS_LEN; i++) {
745  mul_v3_fl(sh[i], M_PI * 4.0f / weight_accum);
746  }
747 }
748 
749 /* Take monochrome SH as input */
750 static float studiolight_spherical_harmonics_lambda_get(float *sh, float max_laplacian)
751 {
752  /* From Peter-Pike Sloan's Stupid SH Tricks http://www.ppsloan.org/publications/StupidSH36.pdf
753  */
754  float table_l[STUDIOLIGHT_SH_BANDS];
755  float table_b[STUDIOLIGHT_SH_BANDS];
756 
757  float lambda = 0.0f;
758 
759  table_l[0] = 0.0f;
760  table_b[0] = 0.0f;
761  int index = 1;
762  for (int level = 1; level < STUDIOLIGHT_SH_BANDS; level++) {
763  table_l[level] = (float)(square_i(level) * square_i(level + 1));
764 
765  float b = 0.0f;
766  for (int m = -1; m <= level; m++) {
767  b += square_f(sh[index++]);
768  }
769  table_b[level] = b;
770  }
771 
772  float squared_lamplacian = 0.0f;
773  for (int level = 1; level < STUDIOLIGHT_SH_BANDS; level++) {
774  squared_lamplacian += table_l[level] * table_b[level];
775  }
776 
777  const float target_squared_laplacian = max_laplacian * max_laplacian;
778  if (squared_lamplacian <= target_squared_laplacian) {
779  return lambda;
780  }
781 
782  const int no_iterations = 10000000;
783  for (int i = 0; i < no_iterations; i++) {
784  float f = 0.0f;
785  float fd = 0.0f;
786 
787  for (int level = 1; level < STUDIOLIGHT_SH_BANDS; level++) {
788  f += table_l[level] * table_b[level] / square_f(1.0f + lambda * table_l[level]);
789  fd += (2.0f * square_f(table_l[level]) * table_b[level]) /
790  cube_f(1.0f + lambda * table_l[level]);
791  }
792 
793  f = target_squared_laplacian - f;
794 
795  float delta = -f / fd;
796  lambda += delta;
797 
798  if (fabsf(delta) < 1e-6f) {
799  break;
800  }
801  }
802 
803  return lambda;
804 }
805 
806 static void studiolight_spherical_harmonics_apply_windowing(float (*sh)[3], float max_laplacian)
807 {
808  if (max_laplacian <= 0.0f) {
809  return;
810  }
811 
812  float sh_r[STUDIOLIGHT_SH_COEFS_LEN];
813  float sh_g[STUDIOLIGHT_SH_COEFS_LEN];
814  float sh_b[STUDIOLIGHT_SH_COEFS_LEN];
815  for (int i = 0; i < STUDIOLIGHT_SH_COEFS_LEN; i++) {
816  sh_r[i] = sh[i][0];
817  sh_g[i] = sh[i][1];
818  sh_b[i] = sh[i][2];
819  }
820  float lambda_r = studiolight_spherical_harmonics_lambda_get(sh_r, max_laplacian);
821  float lambda_g = studiolight_spherical_harmonics_lambda_get(sh_g, max_laplacian);
822  float lambda_b = studiolight_spherical_harmonics_lambda_get(sh_b, max_laplacian);
823 
824  /* Apply windowing lambda */
825  int index = 0;
826  for (int level = 0; level < STUDIOLIGHT_SH_BANDS; level++) {
827  float s[3];
828  const int level_sq = square_i(level);
829  const int level_1_sq = square_i(level + 1.0f);
830  s[0] = 1.0f / (1.0f + lambda_r * level_sq * level_1_sq);
831  s[1] = 1.0f / (1.0f + lambda_g * level_sq * level_1_sq);
832  s[2] = 1.0f / (1.0f + lambda_b * level_sq * level_1_sq);
833 
834  for (int m = -1; m <= level; m++) {
835  mul_v3_v3(sh[index++], s);
836  }
837  }
838 }
839 
841  const float normal[3], float sh0, float sh1, float sh2, float sh3)
842 {
843  /* Use Geomerics non-linear SH. */
844  /* http://www.geomerics.com/wp-content/uploads/2015/08/CEDEC_Geomerics_ReconstructingDiffuseLighting1.pdf
845  */
846  float R0 = sh0 * M_1_PI;
847 
848  float R1[3] = {-sh3, sh2, -sh1};
849  mul_v3_fl(R1, 0.5f * M_1_PI * 1.5f); /* 1.5f is to improve the contrast a bit. */
850  float lenR1 = len_v3(R1);
851  mul_v3_fl(R1, 1.0f / lenR1);
852  float q = 0.5f * (1.0f + dot_v3v3(R1, normal));
853 
854  float p = 1.0f + 2.0f * lenR1 / R0;
855  float a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0);
856 
857  return R0 * (a + (1.0f - a) * (p + 1.0f) * powf(q, p));
858 }
859 
861  float color[3],
862  const float normal[3])
863 {
864 #if STUDIOLIGHT_SH_BANDS == 2
865  float(*sh)[3] = (float(*)[3])sl->spherical_harmonics_coefs;
866  for (int i = 0; i < 3; i++) {
868  normal, sh[0][i], sh[1][i], sh[2][i], sh[3][i]);
869  }
870 #else
871  /* L0 */
872  mul_v3_v3fl(color, sl->spherical_harmonics_coefs[0], 0.282095f);
873 # if STUDIOLIGHT_SH_BANDS > 1 /* L1 */
874  const float nx = normal[0];
875  const float ny = normal[1];
876  const float nz = normal[2];
877  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[1], -0.488603f * nz);
878  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[2], 0.488603f * ny);
879  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[3], -0.488603f * nx);
880 # endif
881 # if STUDIOLIGHT_SH_BANDS > 2 /* L2 */
882  const float nx2 = SQUARE(nx);
883  const float ny2 = SQUARE(ny);
884  const float nz2 = SQUARE(nz);
885  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[4], 1.092548f * nx * nz);
886  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[5], -1.092548f * nz * ny);
887  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[6], 0.315392f * (3.0f * ny2 - 1.0f));
888  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[7], -1.092548 * nx * ny);
889  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[8], 0.546274 * (nx2 - nz2));
890 # endif
891  /* L3 coefs are 0 */
892 # if STUDIOLIGHT_SH_BANDS > 4 /* L4 */
893  const float nx4 = SQUARE(nx2);
894  const float ny4 = SQUARE(ny2);
895  const float nz4 = SQUARE(nz2);
896  madd_v3_v3fl(
897  color, sl->spherical_harmonics_coefs[9], 2.5033429417967046f * nx * nz * (nx2 - nz2));
898  madd_v3_v3fl(color,
900  -1.7701307697799304f * nz * ny * (3.0f * nx2 - nz2));
901  madd_v3_v3fl(color,
903  0.9461746957575601f * nz * nx * (-1.0f + 7.0f * ny2));
904  madd_v3_v3fl(color,
906  -0.6690465435572892f * nz * ny * (-3.0f + 7.0f * ny2));
907  madd_v3_v3fl(color,
909  (105.0f * ny4 - 90.0f * ny2 + 9.0f) / 28.359261614f);
910  madd_v3_v3fl(color,
912  -0.6690465435572892f * nx * ny * (-3.0f + 7.0f * ny2));
913  madd_v3_v3fl(color,
915  0.9461746957575601f * (nx2 - nz2) * (-1.0f + 7.0f * ny2));
916  madd_v3_v3fl(color,
918  -1.7701307697799304f * nx * ny * (nx2 - 3.0f * nz2));
919  madd_v3_v3fl(color,
921  0.6258357354491761f * (nx4 - 6.0f * nz2 * nx2 + nz4));
922 # endif
923 #endif
924 }
925 
926 /* This modify the radiance into irradiance. */
928 {
929  static const float sl_sh_band_factors[5] = {
930  1.0f,
931  2.0f / 3.0f,
932  1.0f / 4.0f,
933  0.0f,
934  -1.0f / 24.0f,
935  };
936 
937  int index = 0, dst_idx = 0;
938  for (int band = 0; band < STUDIOLIGHT_SH_BANDS; band++) {
939  const int last_band = square_i(band + 1) - square_i(band);
940  for (int m = 0; m < last_band; m++) {
941  /* Skip L3 */
942  if (band != 3) {
943  mul_v3_v3fl(sl->spherical_harmonics_coefs[dst_idx++], sh[index], sl_sh_band_factors[band]);
944  }
945  index++;
946  }
947  }
948 }
949 
951 {
952  /* init light to black */
953  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
955 
956  float sh_coefs[STUDIOLIGHT_SH_COEFS_LEN][3];
960 
961  if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
962  FILE *fp = BLI_fopen(sl->path_sh_cache, "wb");
963  if (fp) {
964  fwrite(sl->spherical_harmonics_coefs, sizeof(sl->spherical_harmonics_coefs), 1, fp);
965  fclose(fp);
966  }
967  }
968  }
970 }
971 
973  const float normal[3],
974  float color[3],
975  int xoffset,
976  int yoffset,
977  int zoffset,
978  float zsign)
979 {
980  if (radiance_buffer == NULL) {
981  return;
982  }
983 
984  float accum[3] = {0.0f, 0.0f, 0.0f};
985  float accum_weight = 0.00001f;
986  ITER_PIXELS (float,
987  radiance_buffer->rect_float,
988  4,
991  float direction[3];
992  direction[zoffset] = zsign * 0.5f;
993  direction[xoffset] = x - 0.5f;
994  direction[yoffset] = y - 0.5f;
995  normalize_v3(direction);
996  float weight = dot_v3v3(direction, normal) > 0.95f ? 1.0f : 0.0f;
997  // float solid_angle = texel_solid_angle(x, y, texel_size[0] * 0.5f);
998  madd_v3_v3fl(accum, pixel, weight);
999  accum_weight += weight;
1000  }
1002 
1003  madd_v3_v3fl(color, accum, 1.0f / accum_weight);
1004 }
1005 
1006 static float brdf_approx(float spec_color, float roughness, float NV)
1007 {
1008  /* Very rough own approx. We don't need it to be correct, just fast.
1009  * Just simulate fresnel effect with roughness attenuation. */
1010  float fresnel = exp2(-8.35f * NV) * (1.0f - roughness);
1011  return spec_color * (1.0f - fresnel) + fresnel;
1012 }
1013 
1014 /* NL need to be unclamped. w in [0..1] range. */
1015 static float wrapped_lighting(float NL, float w)
1016 {
1017  float w_1 = w + 1.0f;
1018  return max_ff((NL + w) / (w_1 * w_1), 0.0f);
1019 }
1020 
1021 static float blinn_specular(const float L[3],
1022  const float I[3],
1023  const float N[3],
1024  const float R[3],
1025  float NL,
1026  float roughness,
1027  float wrap)
1028 {
1029  float half_dir[3];
1030  float wrapped_NL = dot_v3v3(L, R);
1031  add_v3_v3v3(half_dir, L, I);
1032  normalize_v3(half_dir);
1033  float spec_angle = max_ff(dot_v3v3(half_dir, N), 0.0f);
1034 
1035  float gloss = 1.0f - roughness;
1036  /* Reduce gloss for smooth light. (simulate bigger light) */
1037  gloss *= 1.0f - wrap;
1038  float shininess = exp2(10.0f * gloss + 1.0f);
1039 
1040  /* Pi is already divided in the light power.
1041  * normalization_factor = (shininess + 8.0) / (8.0 * M_PI) */
1042  float normalization_factor = shininess * 0.125f + 1.0f;
1043  float spec_light = powf(spec_angle, shininess) * max_ff(NL, 0.0f) * normalization_factor;
1044 
1045  /* Simulate Env. light. */
1046  float w = wrap * (1.0 - roughness) + roughness;
1047  float spec_env = wrapped_lighting(wrapped_NL, w);
1048 
1049  float w2 = wrap * wrap;
1050 
1051  return spec_light * (1.0 - w2) + spec_env * w2;
1052 }
1053 
1054 /* Keep in sync with the glsl shader function get_world_lighting() */
1055 static void studiolight_lights_eval(StudioLight *sl, float color[3], const float normal[3])
1056 {
1057  float R[3], I[3] = {0.0f, 0.0f, 1.0f}, N[3] = {normal[0], normal[2], -normal[1]};
1058  const float roughness = 0.5f;
1059  const float diffuse_color = 0.8f;
1060  const float specular_color = brdf_approx(0.05f, roughness, N[2]);
1061  float diff_light[3], spec_light[3];
1062 
1063  /* Ambient lighting */
1064  copy_v3_v3(diff_light, sl->light_ambient);
1065  copy_v3_v3(spec_light, sl->light_ambient);
1066 
1067  reflect_v3_v3v3(R, I, N);
1068  for (int i = 0; i < STUDIOLIGHT_MAX_LIGHT; i++) {
1069  SolidLight *light = &sl->light[i];
1070  if (light->flag) {
1071  /* Diffuse lighting */
1072  float NL = dot_v3v3(light->vec, N);
1073  float diff = wrapped_lighting(NL, light->smooth);
1074  madd_v3_v3fl(diff_light, light->col, diff);
1075  /* Specular lighting */
1076  float spec = blinn_specular(light->vec, I, N, R, NL, roughness, light->smooth);
1077  madd_v3_v3fl(spec_light, light->spec, spec);
1078  }
1079  }
1080 
1081  /* Multiply result by surface colors. */
1082  mul_v3_fl(diff_light, diffuse_color * (1.0 - specular_color));
1083  mul_v3_fl(spec_light, specular_color);
1084 
1085  add_v3_v3v3(color, diff_light, spec_light);
1086 }
1087 
1089 {
1090 #ifdef STUDIOLIGHT_LOAD_CACHED_FILES
1091  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
1092  ImBuf *ibuf = NULL;
1093  ibuf = IMB_loadiffname(sl->path_irr_cache, 0, NULL);
1094  if (ibuf) {
1095  IMB_float_from_rect(ibuf);
1096  sl->equirect_irradiance_buffer = ibuf;
1098  return true;
1099  }
1100  }
1101 #else
1102  UNUSED_VARS(sl);
1103 #endif
1104  return false;
1105 }
1106 
1108 {
1109 #ifdef STUDIOLIGHT_LOAD_CACHED_FILES
1110  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
1111  FILE *fp = BLI_fopen(sl->path_sh_cache, "rb");
1112  if (fp) {
1113  if (fread((void *)(sl->spherical_harmonics_coefs),
1114  sizeof(sl->spherical_harmonics_coefs),
1115  1,
1116  fp)) {
1118  fclose(fp);
1119  return true;
1120  }
1121  fclose(fp);
1122  }
1123  }
1124 #else
1125  UNUSED_VARS(sl);
1126 #endif
1127  return false;
1128 }
1129 
1131 {
1132  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
1134 
1136  STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT * sizeof(float[4]),
1137  __func__);
1138 
1139  ITER_PIXELS (float,
1140  colbuf,
1141  4,
1144  float dir[3];
1145  equirect_to_direction(dir, x, y);
1146  studiolight_spherical_harmonics_eval(sl, pixel, dir);
1147  pixel[3] = 1.0f;
1148  }
1150 
1152  colbuf,
1155  4);
1156  MEM_freeN(colbuf);
1157  }
1159 }
1160 
1161 static StudioLight *studiolight_add_file(const char *path, int flag)
1162 {
1163  char filename[FILE_MAXFILE];
1164  BLI_split_file_part(path, filename, FILE_MAXFILE);
1165 
1166  if ((((flag & STUDIOLIGHT_TYPE_STUDIO) != 0) && BLI_path_extension_check(filename, ".sl")) ||
1169  BLI_strncpy(sl->name, filename, FILE_MAXFILE);
1170  BLI_strncpy(sl->path, path, FILE_MAXFILE);
1171 
1172  if ((flag & STUDIOLIGHT_TYPE_STUDIO) != 0) {
1174  }
1175  else {
1176  sl->path_irr_cache = BLI_string_joinN(path, ".irr");
1177  sl->path_sh_cache = BLI_string_joinN(path, ".sh2");
1178  }
1179  BLI_addtail(&studiolights, sl);
1180  return sl;
1181  }
1182  return NULL;
1183 }
1184 
1185 static void studiolight_add_files_from_datafolder(const int folder_id,
1186  const char *subfolder,
1187  int flag)
1188 {
1189  struct direntry *dir;
1190  const char *folder = BKE_appdir_folder_id(folder_id, subfolder);
1191  if (folder) {
1192  uint totfile = BLI_filelist_dir_contents(folder, &dir);
1193  int i;
1194  for (i = 0; i < totfile; i++) {
1195  if ((dir[i].type & S_IFREG)) {
1196  studiolight_add_file(dir[i].path, flag);
1197  }
1198  }
1199  BLI_filelist_free(dir, totfile);
1200  dir = NULL;
1201  }
1202 }
1203 
1205 {
1206  /* Internal studiolights before external studio lights */
1207  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
1208  return 1;
1209  }
1210  return 0;
1211 }
1212 
1213 static int studiolight_cmp(const void *a, const void *b)
1214 {
1215  const StudioLight *sl1 = a;
1216  const StudioLight *sl2 = b;
1217 
1218  const int flagorder1 = studiolight_flag_cmp_order(sl1);
1219  const int flagorder2 = studiolight_flag_cmp_order(sl2);
1220 
1221  if (flagorder1 < flagorder2) {
1222  return -1;
1223  }
1224  if (flagorder1 > flagorder2) {
1225  return 1;
1226  }
1227 
1228  return BLI_strcasecmp(sl1->name, sl2->name);
1229 }
1230 
1231 /* icons */
1232 
1233 /* Takes normalized uvs as parameter (range from 0 to 1).
1234  * inner_edge and outer_edge are distances (from the center)
1235  * in uv space for the alpha mask falloff. */
1236 static uint alpha_circle_mask(float u, float v, float inner_edge, float outer_edge)
1237 {
1238  /* Coords from center. */
1239  const float co[2] = {u - 0.5f, v - 0.5f};
1240  float dist = len_v2(co);
1241  float alpha = 1.0f + (inner_edge - dist) / (outer_edge - inner_edge);
1242  uint mask = (uint)floorf(255.0f * min_ff(max_ff(alpha, 0.0f), 1.0f));
1243  return mask << 24;
1244 }
1245 
1246 /* Percentage of the icon that the preview sphere covers. */
1247 #define STUDIOLIGHT_DIAMETER 0.95f
1248 /* Rescale coord around (0.5, 0.5) by STUDIOLIGHT_DIAMETER. */
1249 #define RESCALE_COORD(x) (x / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f)
1250 
1251 /* Remaps normalized UV [0..1] to a sphere normal around (0.5, 0.5) */
1252 static void sphere_normal_from_uv(float normal[3], float u, float v)
1253 {
1254  normal[0] = u * 2.0f - 1.0f;
1255  normal[1] = v * 2.0f - 1.0f;
1256  float dist = len_v2(normal);
1257  normal[2] = sqrtf(1.0f - square_f(dist));
1258 }
1259 
1260 static void studiolight_radiance_preview(uint *icon_buffer, StudioLight *sl)
1261 {
1263 
1265  float dy = RESCALE_COORD(y);
1266  float dx = RESCALE_COORD(x);
1267 
1268  uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
1269  if (alphamask != 0) {
1270  float normal[3], direction[3], color[4];
1271  const float incoming[3] = {0.0f, 0.0f, -1.0f};
1272  sphere_normal_from_uv(normal, dx, dy);
1273  reflect_v3_v3v3(direction, incoming, normal);
1274  /* We want to see horizon not poles. */
1275  SWAP(float, direction[1], direction[2]);
1276  direction[1] = -direction[1];
1277 
1279 
1280  *pixel = rgb_to_cpack(linearrgb_to_srgb(color[0]),
1281  linearrgb_to_srgb(color[1]),
1282  linearrgb_to_srgb(color[2])) |
1283  alphamask;
1284  }
1285  else {
1286  *pixel = 0x0;
1287  }
1288  }
1290 }
1291 
1292 static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool flipped)
1293 {
1295 
1296  ImBuf *diffuse_buffer = sl->matcap_diffuse.ibuf;
1297  ImBuf *specular_buffer = sl->matcap_specular.ibuf;
1298 
1300  float dy = RESCALE_COORD(y);
1301  float dx = RESCALE_COORD(x);
1302  if (flipped) {
1303  dx = 1.0f - dx;
1304  }
1305 
1306  float color[4];
1307  float u = dx * diffuse_buffer->x - 1.0f;
1308  float v = dy * diffuse_buffer->y - 1.0f;
1309  nearest_interpolation_color(diffuse_buffer, NULL, color, u, v);
1310 
1311  if (specular_buffer) {
1312  float specular[4];
1313  nearest_interpolation_color(specular_buffer, NULL, specular, u, v);
1314  add_v3_v3(color, specular);
1315  }
1316 
1317  uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
1318 
1319  *pixel = rgb_to_cpack(linearrgb_to_srgb(color[0]),
1320  linearrgb_to_srgb(color[1]),
1321  linearrgb_to_srgb(color[2])) |
1322  alphamask;
1323  }
1325 }
1326 
1327 static void studiolight_irradiance_preview(uint *icon_buffer, StudioLight *sl)
1328 {
1330  float dy = RESCALE_COORD(y);
1331  float dx = RESCALE_COORD(x);
1332 
1333  uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
1334  if (alphamask != 0) {
1335  float normal[3], color[3];
1336  sphere_normal_from_uv(normal, dx, dy);
1337  /* We want to see horizon not poles. */
1338  SWAP(float, normal[1], normal[2]);
1339  normal[1] = -normal[1];
1340 
1341  studiolight_lights_eval(sl, color, normal);
1342 
1343  *pixel = rgb_to_cpack(linearrgb_to_srgb(color[0]),
1344  linearrgb_to_srgb(color[1]),
1345  linearrgb_to_srgb(color[2])) |
1346  alphamask;
1347  }
1348  else {
1349  *pixel = 0x0;
1350  }
1351  }
1353 }
1354 
1355 void BKE_studiolight_default(SolidLight lights[4], float light_ambient[4])
1356 {
1357  copy_v3_fl3(light_ambient, 0.0, 0.0, 0.0);
1358 
1359  lights[0].flag = 1;
1360  lights[0].smooth = 0.526620f;
1361  lights[0].col[0] = 0.033103f;
1362  lights[0].col[1] = 0.033103f;
1363  lights[0].col[2] = 0.033103f;
1364  lights[0].spec[0] = 0.266761f;
1365  lights[0].spec[1] = 0.266761f;
1366  lights[0].spec[2] = 0.266761f;
1367  lights[0].vec[0] = -0.352546f;
1368  lights[0].vec[1] = 0.170931f;
1369  lights[0].vec[2] = -0.920051f;
1370 
1371  lights[1].flag = 1;
1372  lights[1].smooth = 0.000000f;
1373  lights[1].col[0] = 0.521083f;
1374  lights[1].col[1] = 0.538226f;
1375  lights[1].col[2] = 0.538226f;
1376  lights[1].spec[0] = 0.599030f;
1377  lights[1].spec[1] = 0.599030f;
1378  lights[1].spec[2] = 0.599030f;
1379  lights[1].vec[0] = -0.408163f;
1380  lights[1].vec[1] = 0.346939f;
1381  lights[1].vec[2] = 0.844415f;
1382 
1383  lights[2].flag = 1;
1384  lights[2].smooth = 0.478261f;
1385  lights[2].col[0] = 0.038403f;
1386  lights[2].col[1] = 0.034357f;
1387  lights[2].col[2] = 0.049530f;
1388  lights[2].spec[0] = 0.106102f;
1389  lights[2].spec[1] = 0.125981f;
1390  lights[2].spec[2] = 0.158523f;
1391  lights[2].vec[0] = 0.521739f;
1392  lights[2].vec[1] = 0.826087f;
1393  lights[2].vec[2] = 0.212999f;
1394 
1395  lights[3].flag = 1;
1396  lights[3].smooth = 0.200000f;
1397  lights[3].col[0] = 0.090838f;
1398  lights[3].col[1] = 0.082080f;
1399  lights[3].col[2] = 0.072255f;
1400  lights[3].spec[0] = 0.106535f;
1401  lights[3].spec[1] = 0.084771f;
1402  lights[3].spec[2] = 0.066080f;
1403  lights[3].vec[0] = 0.624519f;
1404  lights[3].vec[1] = -0.562067f;
1405  lights[3].vec[2] = -0.542269f;
1406 }
1407 
1408 /* API */
1410 {
1411  /* Add default studio light */
1415  BLI_strncpy(sl->name, "Default", FILE_MAXFILE);
1416 
1417  BLI_addtail(&studiolights, sl);
1418 
1419  /* Go over the preset folder and add a studio-light for every image with its path. */
1420  /* For portable installs (where USER and SYSTEM paths are the same),
1421  * only go over LOCAL data-files once. */
1422  /* Also reserve icon space for it. */
1434  }
1443 
1444  /* sort studio lights on filename. */
1446 
1448 }
1449 
1451 {
1452  struct StudioLight *sl;
1453  while ((sl = BLI_pophead(&studiolights))) {
1454  studiolight_free(sl);
1455  }
1456 }
1457 
1459 {
1460  const char *default_name = "";
1461 
1462  if (flag & STUDIOLIGHT_TYPE_WORLD) {
1463  default_name = STUDIOLIGHT_WORLD_DEFAULT;
1464  }
1465  else if (flag & STUDIOLIGHT_TYPE_MATCAP) {
1466  default_name = STUDIOLIGHT_MATCAP_DEFAULT;
1467  }
1468 
1470  if ((sl->flag & flag) && STREQ(sl->name, default_name)) {
1471  return sl;
1472  }
1473  }
1474 
1476  if ((sl->flag & flag)) {
1477  return sl;
1478  }
1479  }
1480  return NULL;
1481 }
1482 
1483 struct StudioLight *BKE_studiolight_find(const char *name, int flag)
1484 {
1486  if (STREQLEN(sl->name, name, FILE_MAXFILE)) {
1487  if ((sl->flag & flag)) {
1488  return sl;
1489  }
1490 
1491  /* flags do not match, so use default */
1493  }
1494  }
1495  /* When not found, use the default studio light */
1497 }
1498 
1500 {
1502  if (sl->index == index) {
1503  return sl;
1504  }
1505  }
1506  /* When not found, use the default studio light */
1508 }
1509 
1511 {
1512  return &studiolights;
1513 }
1514 
1515 void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type)
1516 {
1517  switch (icon_id_type) {
1519  default: {
1520  studiolight_radiance_preview(icon_buffer, sl);
1521  break;
1522  }
1524  studiolight_irradiance_preview(icon_buffer, sl);
1525  break;
1526  }
1528  studiolight_matcap_preview(icon_buffer, sl, false);
1529  break;
1530  }
1532  studiolight_matcap_preview(icon_buffer, sl, true);
1533  break;
1534  }
1535  }
1536 }
1537 
1538 /* Ensure state of Studiolights */
1540 {
1541  if ((sl->flag & flag) == flag) {
1542  return;
1543  }
1544 
1545  if ((flag & STUDIOLIGHT_EXTERNAL_IMAGE_LOADED)) {
1547  }
1550  }
1554  }
1555  }
1558  }
1561  }
1565  }
1566  }
1569  }
1572  }
1573 }
1574 
1575 /*
1576  * Python API Functions
1577  */
1579 {
1580  if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
1581  BLI_remlink(&studiolights, sl);
1582  studiolight_free(sl);
1583  }
1584 }
1585 
1586 StudioLight *BKE_studiolight_load(const char *path, int type)
1587 {
1589  return sl;
1590 }
1591 
1593  const SolidLight light[4],
1594  const float light_ambient[3])
1595 {
1599 
1600  char filename[FILE_MAXFILE];
1601  BLI_split_file_part(path, filename, FILE_MAXFILE);
1602  STRNCPY(sl->path, path);
1603  STRNCPY(sl->name, filename);
1604 
1605  memcpy(sl->light, light, sizeof(*light) * 4);
1606  memcpy(sl->light_ambient, light_ambient, sizeof(*light_ambient) * 3);
1607 
1609 
1610  BLI_addtail(&studiolights, sl);
1611  return sl;
1612 }
1613 
1614 /* Only useful for workbench while editing the userprefs. */
1616 {
1617  static StudioLight sl = {0};
1619 
1620  memcpy(sl.light, U.light_param, sizeof(*sl.light) * 4);
1621  memcpy(sl.light_ambient, U.light_ambient, sizeof(*sl.light_ambient) * 3);
1622 
1623  return &sl;
1624 }
1625 
1627 {
1630 }
1631 
1633  StudioLightFreeFunction *free_function,
1634  void *data)
1635 {
1636  sl->free_function = free_function;
1637  sl->free_function_data = data;
1638 }
1639 
1641 {
1642  BLI_assert(sl != NULL);
1643  if (sl->icon_id_radiance == icon_id) {
1644  sl->icon_id_radiance = 0;
1645  }
1646  if (sl->icon_id_irradiance == icon_id) {
1647  sl->icon_id_irradiance = 0;
1648  }
1649  if (sl->icon_id_matcap == icon_id) {
1650  sl->icon_id_matcap = 0;
1651  }
1652  if (sl->icon_id_matcap_flipped == icon_id) {
1653  sl->icon_id_matcap_flipped = 0;
1654  }
1655 }
typedef float(TangentPoint)[2]
@ BLENDER_USER_DATAFILES
Definition: BKE_appdir.h:82
@ BLENDER_SYSTEM_DATAFILES
Definition: BKE_appdir.h:87
bool BKE_appdir_app_is_portable_install(void)
Definition: appdir.c:399
const char * BKE_appdir_folder_id(const int folder_id, const char *subfolder)
Definition: appdir.c:674
int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type)
Definition: icons.cc:1057
#define STUDIOLIGHT_ICON_ID_TYPE_MATCAP
#define STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED
#define STUDIOLIGHT_ICON_ID_TYPE_RADIANCE
#define STUDIOLIGHT_X_POS
@ STUDIOLIGHT_EXTERNAL_IMAGE_LOADED
@ STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE
@ STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE
@ STUDIOLIGHT_USER_DEFINED
@ STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED
@ STUDIOLIGHT_INTERNAL
@ STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED
@ STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE
@ STUDIOLIGHT_TYPE_MATCAP
@ STUDIOLIGHT_TYPE_WORLD
@ STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED
@ STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS
@ STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE
@ STUDIOLIGHT_TYPE_STUDIO
@ STUDIOLIGHT_EXTERNAL_FILE
void StudioLightFreeFunction(struct StudioLight *, void *data)
#define STUDIOLIGHT_SH_BANDS
#define STUDIOLIGHT_X_NEG
#define STUDIOLIGHT_ICON_SIZE
#define STUDIOLIGHT_Y_NEG
#define STUDIOLIGHT_Z_POS
#define STUDIOLIGHT_Z_NEG
#define STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE
#define STUDIOLIGHT_Y_POS
#define STUDIOLIGHT_MAX_LIGHT
#define STUDIOLIGHT_SH_COEFS_LEN
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
A dynamically sized string ADT.
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_dynstr.c:71
int BLI_dynstr_get_len(DynStr *ds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_dynstr.c:286
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
Definition: BLI_dynstr.c:358
char * BLI_dynstr_get_cstring(DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_dynstr.c:323
File and directory operations.
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries)
Definition: BLI_filelist.c:467
unsigned int BLI_filelist_dir_contents(const char *dir, struct direntry **r_filelist)
Definition: BLI_filelist.c:238
void BLI_file_free_lines(struct LinkNode *lines)
Definition: storage.c:639
struct LinkNode * BLI_file_read_as_lines(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:590
FILE * BLI_fopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:1003
Some types for dealing with directories.
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:257
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void void BLI_listbase_sort(struct ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
#define M_1_PI
Definition: BLI_math_base.h:59
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
MINLINE int square_i(int a)
MINLINE float cube_f(float a)
MINLINE float square_f(float a)
#define M_PI
Definition: BLI_math_base.h:38
unsigned int rgb_to_cpack(float r, float g, float b)
Definition: math_color.c:379
float linearrgb_to_srgb(float c)
Definition: math_color.c:443
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:930
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
void reflect_v3_v3v3(float out[3], const float vec[3], const float normal[3])
Definition: math_vector.c:818
MINLINE float normalize_v3(float r[3])
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z)
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
bool BLI_path_extension_check_array(const char *str, const char **ext_array) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1487
#define FILE_MAXFILE
bool BLI_path_extension_check(const char *str, const char *ext) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1459
void BLI_split_file_part(const char *string, char *file, const size_t filelen)
Definition: path_util.c:1690
#define STRNCPY(dst, src)
Definition: BLI_string.h:163
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:666
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#define BLI_string_joinN(...)
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED_FUNCTION(x)
#define UNUSED_VARS(...)
#define SWAP(type, a, b)
#define STREQLEN(a, b, n)
#define UNUSED(x)
#define STREQ(a, b)
These structs are the foundation for all linked lists in the library system.
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble ny
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat, bool use_clamp)
Definition: gpu_texture.cc:496
struct GPUTexture GPUTexture
Definition: GPU_texture.h:33
@ GPU_DATA_FLOAT
Definition: GPU_texture.h:172
void GPU_texture_update(GPUTexture *tex, eGPUDataFormat data_format, const void *data)
Definition: gpu_texture.cc:391
void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter)
Definition: gpu_texture.cc:468
GPUTexture * GPU_texture_create_2d(const char *name, int w, int h, int mip_len, eGPUTextureFormat format, const float *data)
Definition: gpu_texture.cc:250
@ GPU_RGBA16F
Definition: GPU_texture.h:94
@ GPU_R11F_G11F_B10F
Definition: GPU_texture.h:119
void IMB_float_from_rect(struct ImBuf *ibuf)
Definition: divers.c:780
void IMB_freeImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:211
void nearest_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
Definition: imageprocess.c:298
void nearest_interpolation_color(struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
Definition: imageprocess.c:242
void IMB_buffer_float_from_float(float *rect_to, const float *rect_from, int channels_from, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
Definition: divers.c:430
struct ImBuf * IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_SPACE])
Definition: readimage.c:224
struct ImBuf * IMB_allocFromBuffer(const unsigned int *rect, const float *rectf, unsigned int w, unsigned int h, unsigned int channels)
Definition: allocimbuf.c:433
bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags)
Definition: writeimage.c:44
Contains defines and structs used throughout the imbuf module.
#define IB_PROFILE_LINEAR_RGB
@ IB_rectfloat
@ IB_multilayer
const char * imb_ext_image[]
Definition: util.c:60
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert * v
unsigned int U
Definition: btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
#define NL
static CCL_NAMESPACE_BEGIN const double alpha
float texel_size[2]
Definition: eevee_effects.c:42
#define str(s)
@ IMB_FTYPE_OPENEXR
IconTextureDrawCall normal
#define sinf(x)
#define cosf(x)
#define powf(x, y)
#define atan2f(x, y)
#define floorf(x)
#define acosf(x)
#define fabsf(x)
#define sqrtf(x)
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:48
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
#define R
#define L
static unsigned a[3]
Definition: RandGen.cpp:92
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt=1)
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
Definition: rall1d.h:429
static GPUContext * wrap(Context *ctx)
static const pxr::TfToken roughness("roughness", pxr::TfToken::Immortal)
static const pxr::TfToken diffuse_color("diffuseColor", pxr::TfToken::Immortal)
#define I
void IMB_exr_close(void *handle)
void IMB_exr_multilayer_convert(void *handle, void *base, void *(*addview)(void *base, const char *str), void *(*addlayer)(void *base, const char *str), void(*addpass)(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id, const char *view))
params N
void * userdata
enum eImbFileType ftype
float * rect_float
struct GPUTexture * gputexture
struct ImBuf * ibuf
StudioLightImage matcap_specular
SolidLight light[STUDIOLIGHT_MAX_LIGHT]
void * free_function_data
struct GPUTexture * equirect_radiance_gputexture
char path[FILE_MAX]
float spherical_harmonics_coefs[STUDIOLIGHT_SH_EFFECTIVE_COEFS_LEN][3]
struct ImBuf * equirect_irradiance_buffer
StudioLightFreeFunction * free_function
char * path_sh_cache
struct ImBuf * equirect_radiance_buffer
int icon_id_matcap_flipped
char name[FILE_MAXFILE]
char * path_irr_cache
StudioLightImage matcap_diffuse
struct ImBuf * radiance_cubemap_buffers[6]
float light_ambient[3]
struct GPUTexture * equirect_irradiance_gputexture
const char * path
static void studiolight_create_matcap_specular_gputexture(StudioLight *sl)
Definition: studiolight.c:539
#define STUDIOLIGHT_FILE_VERSION
Definition: studiolight.c:187
static const char * STUDIOLIGHT_LIGHTS_FOLDER
Definition: studiolight.c:68
static void studiolight_radiance_preview(uint *icon_buffer, StudioLight *sl)
Definition: studiolight.c:1260
#define WRITE_IVAL(str, id, val)
Definition: studiolight.c:238
void BKE_studiolight_remove(StudioLight *sl)
Definition: studiolight.c:1578
#define STUDIOLIGHT_PASSNAME_DIFFUSE
Definition: studiolight.c:57
#define STUDIOLIGHT_SH_WINDOWING
Definition: studiolight.c:60
static float * studiolight_multilayer_convert_pass(ImBuf *ibuf, float *rect, const unsigned int channels)
Definition: studiolight.c:362
static void * studiolight_multilayer_addview(void *UNUSED(base), const char *UNUSED(view_name))
Definition: studiolight.c:350
struct StudioLight * BKE_studiolight_findindex(int index, int flag)
Definition: studiolight.c:1499
static void studiolight_irradiance_preview(uint *icon_buffer, StudioLight *sl)
Definition: studiolight.c:1327
static const char * STUDIOLIGHT_MATCAP_DEFAULT
Definition: studiolight.c:73
static void studiolight_spherical_harmonics_calculate_coefficients(StudioLight *sl, float(*sh)[3])
Definition: studiolight.c:686
static struct StudioLight * studiolight_create(int flag)
Definition: studiolight.c:158
#define WRITE_SOLIDLIGHT(str, sl, i)
Definition: studiolight.c:247
void BKE_studiolight_default(SolidLight lights[4], float light_ambient[4])
Definition: studiolight.c:1355
static bool studiolight_load_irradiance_equirect_image(StudioLight *sl)
Definition: studiolight.c:1088
static void studiolight_lights_eval(StudioLight *sl, float color[3], const float normal[3])
Definition: studiolight.c:1055
static int last_studiolight_id
Definition: studiolight.c:53
static int studiolight_cmp(const void *a, const void *b)
Definition: studiolight.c:1213
static void studiolight_calculate_cubemap_vector_weight(float normal[3], float *weight, int face, float x, float y)
Definition: studiolight.c:678
#define ITER_PIXELS(type, src, channels, width, height)
Definition: studiolight.c:90
static int studiolight_flag_cmp_order(const StudioLight *sl)
Definition: studiolight.c:1204
struct MultilayerConvertContext MultilayerConvertContext
static void studiolight_calculate_radiance_buffer(ImBuf *ibuf, float *colbuf, const int index_x, const int index_y, const int index_z, const float xsign, const float ysign, const float zsign)
Definition: studiolight.c:573
static void cube_face_uv_to_direction(float r_dir[3], float x, float y, int face)
Definition: studiolight.c:327
static StudioLight * studiolight_add_file(const char *path, int flag)
Definition: studiolight.c:1161
static ListBase studiolights
Definition: studiolight.c:52
static bool studiolight_load_spherical_harmonics_coefficients(StudioLight *sl)
Definition: studiolight.c:1107
struct ListBase * BKE_studiolight_listbase(void)
Definition: studiolight.c:1510
static void studiolight_calculate_radiance(ImBuf *ibuf, float color[4], const float direction[3])
Definition: studiolight.c:566
StudioLight * BKE_studiolight_load(const char *path, int type)
Definition: studiolight.c:1586
static void studiolight_spherical_harmonics_apply_windowing(float(*sh)[3], float max_laplacian)
Definition: studiolight.c:806
StudioLight * BKE_studiolight_create(const char *path, const SolidLight light[4], const float light_ambient[3])
Definition: studiolight.c:1592
BLI_INLINE float texel_solid_angle(float x, float y, float halfpix)
Definition: studiolight.c:667
static void studiolight_load_equirect_image(StudioLight *sl)
Definition: studiolight.c:412
void BKE_studiolight_unset_icon_id(StudioLight *sl, int icon_id)
Definition: studiolight.c:1640
static uint alpha_circle_mask(float u, float v, float inner_edge, float outer_edge)
Definition: studiolight.c:1236
static void studiolight_calculate_radiance_cubemap_buffers(StudioLight *sl)
Definition: studiolight.c:594
static void studiolight_create_matcap_gputexture(StudioLightImage *sli)
Definition: studiolight.c:511
static void UNUSED_FUNCTION() direction_to_cube_face_uv(float r_uv[2], int *r_face, const float dir[3])
Definition: studiolight.c:301
static void sphere_normal_from_uv(float normal[3], float u, float v)
Definition: studiolight.c:1252
#define STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT
Definition: studiolight.c:55
static void * studiolight_multilayer_addlayer(void *base, const char *UNUSED(layer_name))
Definition: studiolight.c:354
void BKE_studiolight_set_free_function(StudioLight *sl, StudioLightFreeFunction *free_function, void *data)
Definition: studiolight.c:1632
#define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE
Definition: studiolight.c:54
static void studiolight_add_files_from_datafolder(const int folder_id, const char *subfolder, int flag)
Definition: studiolight.c:1185
#define WRITE_VEC3(str, id, val)
Definition: studiolight.c:240
BLI_INLINE float area_element(float x, float y)
Definition: studiolight.c:662
static void studiolight_calculate_diffuse_light(StudioLight *sl)
Definition: studiolight.c:950
#define ITER_PIXELS_END
Definition: studiolight.c:100
static void studiolight_calculate_irradiance_equirect_image(StudioLight *sl)
Definition: studiolight.c:1130
static void studiolight_load_solid_light(StudioLight *sl)
Definition: studiolight.c:219
void BKE_studiolight_init(void)
Definition: studiolight.c:1409
static void studiolight_multilayer_addpass(void *base, void *UNUSED(lay), const char *pass_name, float *rect, int num_channels, const char *UNUSED(chan_id), const char *UNUSED(view_name))
Definition: studiolight.c:387
static float wrapped_lighting(float NL, float w)
Definition: studiolight.c:1015
static void studiolight_free(struct StudioLight *sl)
Definition: studiolight.c:123
#define STUDIOLIGHT_DELETE_ICON(s)
#define STUDIOLIGHT_PASSNAME_SPECULAR
Definition: studiolight.c:58
static const char * STUDIOLIGHT_WORLD_FOLDER
Definition: studiolight.c:69
static void studiolight_spherical_harmonics_apply_band_factors(StudioLight *sl, float(*sh)[3])
Definition: studiolight.c:927
static void studiolight_create_matcap_diffuse_gputexture(StudioLight *sl)
Definition: studiolight.c:529
struct StudioLight * BKE_studiolight_find(const char *name, int flag)
Definition: studiolight.c:1483
#define READ_VEC3(id, val, lines)
Definition: studiolight.c:203
void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
Definition: studiolight.c:1539
#define IMB_SAFE_FREE(p)
Definition: studiolight.c:107
static float studiolight_spherical_harmonics_lambda_get(float *sh, float max_laplacian)
Definition: studiolight.c:750
#define STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH
Definition: studiolight.c:56
static const char * STUDIOLIGHT_MATCAP_FOLDER
Definition: studiolight.c:70
#define RESCALE_COORD(x)
Definition: studiolight.c:1249
static void studiolight_create_equirect_radiance_gputexture(StudioLight *sl)
Definition: studiolight.c:496
static float brdf_approx(float spec_color, float roughness, float NV)
Definition: studiolight.c:1006
BLI_INLINE void studiolight_spherical_harmonics_eval(StudioLight *sl, float color[3], const float normal[3])
Definition: studiolight.c:860
#define GPU_TEXTURE_SAFE_FREE(p)
Definition: studiolight.c:115
static void direction_to_equirect(float r[2], const float dir[3])
Definition: studiolight.c:285
static float studiolight_spherical_harmonics_geomerics_eval(const float normal[3], float sh0, float sh1, float sh2, float sh3)
Definition: studiolight.c:840
static void studiolight_write_solid_light(StudioLight *sl)
Definition: studiolight.c:256
struct StudioLight * BKE_studiolight_find_default(int flag)
Definition: studiolight.c:1458
static const char * STUDIOLIGHT_WORLD_DEFAULT
Definition: studiolight.c:72
static void studiolight_create_equirect_irradiance_gputexture(StudioLight *sl)
Definition: studiolight.c:552
StudioLight * BKE_studiolight_studio_edit_get(void)
Definition: studiolight.c:1615
void BKE_studiolight_free(void)
Definition: studiolight.c:1450
static void equirect_to_direction(float r[3], float u, float v)
Definition: studiolight.c:291
#define READ_SOLIDLIGHT(sl, i, lines)
Definition: studiolight.c:210
static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool flipped)
Definition: studiolight.c:1292
static float blinn_specular(const float L[3], const float I[3], const float N[3], const float R[3], float NL, float roughness, float wrap)
Definition: studiolight.c:1021
BLI_INLINE void studiolight_evaluate_specular_radiance_buffer(ImBuf *radiance_buffer, const float normal[3], float color[3], int xoffset, int yoffset, int zoffset, float zsign)
Definition: studiolight.c:972
void BKE_studiolight_refresh(void)
Definition: studiolight.c:1626
void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type)
Definition: studiolight.c:1515
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)