Blender  V3.3
studiolight.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2006-2007 Blender Foundation. All rights reserved. */
3 
8 #include "BKE_studiolight.h"
9 
10 #include "BKE_appdir.h"
11 #include "BKE_icons.h"
12 
13 #include "BLI_dynstr.h"
14 #include "BLI_fileops.h"
15 #include "BLI_fileops_types.h"
16 #include "BLI_linklist.h"
17 #include "BLI_listbase.h"
18 #include "BLI_math.h"
19 #include "BLI_math_color.h"
20 #include "BLI_path_util.h"
21 #include "BLI_string.h"
22 #include "BLI_string_utils.h"
23 
24 #include "DNA_listBase.h"
25 
26 #include "IMB_imbuf.h"
27 #include "IMB_imbuf_types.h"
28 #include "IMB_openexr.h"
29 
30 #include "GPU_texture.h"
31 
32 #include "MEM_guardedalloc.h"
33 
34 /* Statics */
36 static int last_studiolight_id = 0;
37 #define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 96
38 #define STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT 32
39 #define STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH (STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT * 2)
40 #define STUDIOLIGHT_PASSNAME_DIFFUSE "diffuse"
41 #define STUDIOLIGHT_PASSNAME_SPECULAR "specular"
42 /* Temporarily disabled due to the creation of textures with -nan(ind)s */
43 #define STUDIOLIGHT_SH_WINDOWING 0.0f /* 0.0 is disabled */
44 
45 /*
46  * Disable this option so caches are not loaded from disk
47  * Do not checking with this commented out.
48  */
49 #define STUDIOLIGHT_LOAD_CACHED_FILES
50 
51 static const char *STUDIOLIGHT_LIGHTS_FOLDER = "studiolights/studio/";
52 static const char *STUDIOLIGHT_WORLD_FOLDER = "studiolights/world/";
53 static const char *STUDIOLIGHT_MATCAP_FOLDER = "studiolights/matcap/";
54 
55 static const char *STUDIOLIGHT_WORLD_DEFAULT = "forest.exr";
56 static const char *STUDIOLIGHT_MATCAP_DEFAULT = "basic_1.exr";
57 
58 /* ITER MACRO */
59 
73 #define ITER_PIXELS(type, src, channels, width, height) \
74  { \
75  float texel_size[2]; \
76  texel_size[0] = 1.0f / width; \
77  texel_size[1] = 1.0f / height; \
78  type(*pixel_)[channels] = (type(*)[channels])src; \
79  for (float y = 0.5 * texel_size[1]; y < 1.0; y += texel_size[1]) { \
80  for (float x = 0.5 * texel_size[0]; x < 1.0; x += texel_size[0], pixel_++) { \
81  type *pixel = *pixel_;
82 
83 #define ITER_PIXELS_END \
84  } \
85  } \
86  } \
87  ((void)0)
88 
89 /* FUNCTIONS */
90 #define IMB_SAFE_FREE(p) \
91  do { \
92  if (p) { \
93  IMB_freeImBuf(p); \
94  p = NULL; \
95  } \
96  } while (0)
97 
98 #define GPU_TEXTURE_SAFE_FREE(p) \
99  do { \
100  if (p) { \
101  GPU_texture_free(p); \
102  p = NULL; \
103  } \
104  } while (0)
105 
106 static void studiolight_free(struct StudioLight *sl)
107 {
108 #define STUDIOLIGHT_DELETE_ICON(s) \
109  do { \
110  if (s != 0) { \
111  BKE_icon_delete(s); \
112  s = 0; \
113  } \
114  } while (0)
115 
116  if (sl->free_function) {
117  sl->free_function(sl, sl->free_function_data);
118  }
123 #undef STUDIOLIGHT_DELETE_ICON
124 
125  for (int index = 0; index < 6; index++) {
127  }
138  MEM_SAFE_FREE(sl);
139 }
140 
142 {
143  struct StudioLight *sl = MEM_callocN(sizeof(*sl), __func__);
144  sl->path[0] = 0x00;
145  sl->name[0] = 0x00;
146  sl->path_irr_cache = NULL;
147  sl->path_sh_cache = NULL;
148  sl->free_function = NULL;
149  sl->flag = flag;
150  sl->index = ++last_studiolight_id;
153  }
154  else if (flag & STUDIOLIGHT_TYPE_MATCAP) {
158  }
159  else {
161  }
162 
163  for (int index = 0; index < 6; index++) {
165  }
166 
167  return sl;
168 }
169 
170 #define STUDIOLIGHT_FILE_VERSION 1
171 
172 #define READ_VAL(type, parser, id, val, lines) \
173  do { \
174  for (LinkNode *line = lines; line; line = line->next) { \
175  char *val_str, *str = line->link; \
176  if ((val_str = strstr(str, id " "))) { \
177  val_str += sizeof(id); /* Skip id + spacer. */ \
178  val = parser(val_str); \
179  } \
180  } \
181  } while (0)
182 
183 #define READ_FVAL(id, val, lines) READ_VAL(float, atof, id, val, lines)
184 #define READ_IVAL(id, val, lines) READ_VAL(int, atoi, id, val, lines)
185 
186 #define READ_VEC3(id, val, lines) \
187  do { \
188  READ_FVAL(id ".x", val[0], lines); \
189  READ_FVAL(id ".y", val[1], lines); \
190  READ_FVAL(id ".z", val[2], lines); \
191  } while (0)
192 
193 #define READ_SOLIDLIGHT(sl, i, lines) \
194  do { \
195  READ_IVAL("light[" STRINGIFY(i) "].flag", sl[i].flag, lines); \
196  READ_FVAL("light[" STRINGIFY(i) "].smooth", sl[i].smooth, lines); \
197  READ_VEC3("light[" STRINGIFY(i) "].col", sl[i].col, lines); \
198  READ_VEC3("light[" STRINGIFY(i) "].spec", sl[i].spec, lines); \
199  READ_VEC3("light[" STRINGIFY(i) "].vec", sl[i].vec, lines); \
200  } while (0)
201 
203 {
204  LinkNode *lines = BLI_file_read_as_lines(sl->path);
205  if (lines) {
206  READ_VEC3("light_ambient", sl->light_ambient, lines);
207  READ_SOLIDLIGHT(sl->light, 0, lines);
208  READ_SOLIDLIGHT(sl->light, 1, lines);
209  READ_SOLIDLIGHT(sl->light, 2, lines);
210  READ_SOLIDLIGHT(sl->light, 3, lines);
211  }
212  BLI_file_free_lines(lines);
213 }
214 
215 #undef READ_SOLIDLIGHT
216 #undef READ_VEC3
217 #undef READ_IVAL
218 #undef READ_FVAL
219 
220 #define WRITE_FVAL(str, id, val) (BLI_dynstr_appendf(str, id " %f\n", val))
221 #define WRITE_IVAL(str, id, val) (BLI_dynstr_appendf(str, id " %d\n", val))
222 
223 #define WRITE_VEC3(str, id, val) \
224  do { \
225  WRITE_FVAL(str, id ".x", val[0]); \
226  WRITE_FVAL(str, id ".y", val[1]); \
227  WRITE_FVAL(str, id ".z", val[2]); \
228  } while (0)
229 
230 #define WRITE_SOLIDLIGHT(str, sl, i) \
231  do { \
232  WRITE_IVAL(str, "light[" STRINGIFY(i) "].flag", sl[i].flag); \
233  WRITE_FVAL(str, "light[" STRINGIFY(i) "].smooth", sl[i].smooth); \
234  WRITE_VEC3(str, "light[" STRINGIFY(i) "].col", sl[i].col); \
235  WRITE_VEC3(str, "light[" STRINGIFY(i) "].spec", sl[i].spec); \
236  WRITE_VEC3(str, "light[" STRINGIFY(i) "].vec", sl[i].vec); \
237  } while (0)
238 
240 {
241  FILE *fp = BLI_fopen(sl->path, "wb");
242  if (fp) {
244 
245  /* Very dumb ascii format. One value per line separated by a space. */
247  WRITE_VEC3(str, "light_ambient", sl->light_ambient);
248  WRITE_SOLIDLIGHT(str, sl->light, 0);
249  WRITE_SOLIDLIGHT(str, sl->light, 1);
250  WRITE_SOLIDLIGHT(str, sl->light, 2);
251  WRITE_SOLIDLIGHT(str, sl->light, 3);
252 
253  char *cstr = BLI_dynstr_get_cstring(str);
254 
255  fwrite(cstr, BLI_dynstr_get_len(str), 1, fp);
256  fclose(fp);
257 
258  MEM_freeN(cstr);
260  }
261 }
262 
263 #undef WRITE_SOLIDLIGHT
264 #undef WRITE_VEC3
265 #undef WRITE_IVAL
266 #undef WRITE_FVAL
267 
268 static void direction_to_equirect(float r[2], const float dir[3])
269 {
270  r[0] = (atan2f(dir[1], dir[0]) - M_PI) / -(M_PI * 2);
271  r[1] = (acosf(dir[2] / 1.0) - M_PI) / -M_PI;
272 }
273 
274 static void equirect_to_direction(float r[3], float u, float v)
275 {
276  float phi = (-(M_PI * 2)) * u + M_PI;
277  float theta = -M_PI * v + M_PI;
278  float sin_theta = sinf(theta);
279  r[0] = sin_theta * cosf(phi);
280  r[1] = sin_theta * sinf(phi);
281  r[2] = cosf(theta);
282 }
283 
284 static void UNUSED_FUNCTION(direction_to_cube_face_uv)(float r_uv[2],
285  int *r_face,
286  const float dir[3])
287 {
288  if (fabsf(dir[0]) > fabsf(dir[1]) && fabsf(dir[0]) > fabsf(dir[2])) {
289  bool is_pos = (dir[0] > 0.0f);
290  *r_face = is_pos ? STUDIOLIGHT_X_POS : STUDIOLIGHT_X_NEG;
291  r_uv[0] = dir[2] / fabsf(dir[0]) * (is_pos ? 1 : -1);
292  r_uv[1] = dir[1] / fabsf(dir[0]) * -1;
293  }
294  else if (fabsf(dir[1]) > fabsf(dir[0]) && fabsf(dir[1]) > fabsf(dir[2])) {
295  bool is_pos = (dir[1] > 0.0f);
296  *r_face = is_pos ? STUDIOLIGHT_Y_POS : STUDIOLIGHT_Y_NEG;
297  r_uv[0] = dir[0] / fabsf(dir[1]) * 1;
298  r_uv[1] = dir[2] / fabsf(dir[1]) * (is_pos ? -1 : 1);
299  }
300  else {
301  bool is_pos = (dir[2] > 0.0f);
302  *r_face = is_pos ? STUDIOLIGHT_Z_NEG : STUDIOLIGHT_Z_POS;
303  r_uv[0] = dir[0] / fabsf(dir[2]) * (is_pos ? -1 : 1);
304  r_uv[1] = dir[1] / fabsf(dir[2]) * -1;
305  }
306  r_uv[0] = r_uv[0] * 0.5f + 0.5f;
307  r_uv[1] = r_uv[1] * 0.5f + 0.5f;
308 }
309 
310 static void cube_face_uv_to_direction(float r_dir[3], float x, float y, int face)
311 {
312  const float conversion_matrices[6][3][3] = {
313  {{0.0f, 0.0f, 1.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}},
314  {{0.0f, 0.0f, -1.0f}, {0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}},
315  {{1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 0.0f}},
316  {{1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {0.0f, -1.0f, 0.0f}},
317  {{1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, -1.0f}},
318  {{-1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}},
319  };
320 
321  copy_v3_fl3(r_dir, x * 2.0f - 1.0f, y * 2.0f - 1.0f, 1.0f);
322  mul_m3_v3(conversion_matrices[face], r_dir);
323  normalize_v3(r_dir);
324 }
325 
326 typedef struct MultilayerConvertContext {
328  float *diffuse_pass;
332 
333 static void *studiolight_multilayer_addview(void *UNUSED(base), const char *UNUSED(view_name))
334 {
335  return NULL;
336 }
337 static void *studiolight_multilayer_addlayer(void *base, const char *UNUSED(layer_name))
338 {
339  return base;
340 }
341 
342 /* Convert a multilayer pass to ImBuf channel 4 float buffer.
343  * NOTE: Parameter rect will become invalid. Do not use rect after calling this
344  * function */
346  float *rect,
347  const unsigned int channels)
348 {
349  if (channels == 4) {
350  return rect;
351  }
352 
353  float *new_rect = MEM_callocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__);
354 
356  rect,
357  channels,
360  false,
361  ibuf->x,
362  ibuf->y,
363  ibuf->x,
364  ibuf->x);
365 
366  MEM_freeN(rect);
367  return new_rect;
368 }
369 
370 static void studiolight_multilayer_addpass(void *base,
371  void *UNUSED(lay),
372  const char *pass_name,
373  float *rect,
374  int num_channels,
375  const char *UNUSED(chan_id),
376  const char *UNUSED(view_name))
377 {
378  MultilayerConvertContext *ctx = base;
379  /* NOTE: This function must free pass pixels data if it is not used, this
380  * is how IMB_exr_multilayer_convert() is working. */
381  /* If we've found a first combined pass, skip all the rest ones. */
382  if (STREQ(pass_name, STUDIOLIGHT_PASSNAME_DIFFUSE)) {
383  ctx->diffuse_pass = rect;
384  ctx->num_diffuse_channels = num_channels;
385  }
386  else if (STREQ(pass_name, STUDIOLIGHT_PASSNAME_SPECULAR)) {
387  ctx->specular_pass = rect;
388  ctx->num_specular_channels = num_channels;
389  }
390  else {
391  MEM_freeN(rect);
392  }
393 }
394 
396 {
397  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
399  ImBuf *specular_ibuf = NULL;
400  ImBuf *diffuse_ibuf = NULL;
401  const bool failed = (ibuf == NULL);
402 
403  if (ibuf) {
404  if (ibuf->ftype == IMB_FTYPE_OPENEXR && ibuf->userdata) {
405  /* the read file is a multilayered openexr file (userdata != NULL)
406  * This file is currently only supported for MATCAPS where
407  * the first found 'diffuse' pass will be used for diffuse lighting
408  * and the first found 'specular' pass will be used for specular lighting */
409  MultilayerConvertContext ctx = {0};
411  &ctx,
415 
416  /* `ctx.diffuse_pass` and `ctx.specular_pass` can be freed inside
417  * `studiolight_multilayer_convert_pass` when conversion happens.
418  * When not converted we move the ownership of the buffer to the
419  * `converted_pass`. We only need to free `converted_pass` as it holds
420  * the unmodified allocation from the `ctx.*_pass` or the converted data.
421  */
422  if (ctx.diffuse_pass != NULL) {
423  float *converted_pass = studiolight_multilayer_convert_pass(
424  ibuf, ctx.diffuse_pass, ctx.num_diffuse_channels);
425  diffuse_ibuf = IMB_allocFromBufferOwn(
426  NULL, converted_pass, ibuf->x, ibuf->y, ctx.num_diffuse_channels);
427  }
428 
429  if (ctx.specular_pass != NULL) {
430  float *converted_pass = studiolight_multilayer_convert_pass(
431  ibuf, ctx.specular_pass, ctx.num_specular_channels);
432  specular_ibuf = IMB_allocFromBufferOwn(
433  NULL, converted_pass, ibuf->x, ibuf->y, ctx.num_specular_channels);
434  }
435 
436  IMB_exr_close(ibuf->userdata);
437  ibuf->userdata = NULL;
438  IMB_freeImBuf(ibuf);
439  ibuf = NULL;
440  }
441  else {
442  /* read file is an single layer openexr file or the read file isn't
443  * an openexr file */
444  IMB_float_from_rect(ibuf);
445  diffuse_ibuf = ibuf;
446  ibuf = NULL;
447  }
448  }
449 
450  if (diffuse_ibuf == NULL) {
451  /* Create 1x1 diffuse buffer, in case image failed to load or if there was
452  * only a specular pass in the multilayer file or no passes were found. */
453  const float black[4] = {0.0f, 0.0f, 0.0f, 1.0f};
454  const float magenta[4] = {1.0f, 0.0f, 1.0f, 1.0f};
455  diffuse_ibuf = IMB_allocFromBuffer(
456  NULL, (failed || (specular_ibuf == NULL)) ? magenta : black, 1, 1, 4);
457  }
458 
459  if (sl->flag & STUDIOLIGHT_TYPE_MATCAP) {
460  sl->matcap_diffuse.ibuf = diffuse_ibuf;
461  sl->matcap_specular.ibuf = specular_ibuf;
462  if (specular_ibuf != NULL) {
464  }
465  }
466  else {
467  sl->equirect_radiance_buffer = diffuse_ibuf;
468  if (specular_ibuf != NULL) {
469  IMB_freeImBuf(specular_ibuf);
470  }
471  }
472  }
473 
475 }
476 
478 {
479  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
481  ImBuf *ibuf = sl->equirect_radiance_buffer;
482 
484  "studiolight_radiance", ibuf->x, ibuf->y, 1, GPU_RGBA16F, ibuf->rect_float);
487  GPU_texture_wrap_mode(tex, true, true);
488  }
490 }
491 
493 {
494  BLI_assert(sli->ibuf);
495  ImBuf *ibuf = sli->ibuf;
496  float *gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__);
497 
498  const float(*offset4)[4] = (const float(*)[4])ibuf->rect_float;
499  float(*offset3)[3] = (float(*)[3])gpu_matcap_3components;
500  for (int i = 0; i < ibuf->x * ibuf->y; i++, offset4++, offset3++) {
501  copy_v3_v3(*offset3, *offset4);
502  }
503 
504  sli->gputexture = GPU_texture_create_2d("matcap", ibuf->x, ibuf->y, 1, GPU_R11F_G11F_B10F, NULL);
505  GPU_texture_update(sli->gputexture, GPU_DATA_FLOAT, gpu_matcap_3components);
506 
507  MEM_SAFE_FREE(gpu_matcap_3components);
508 }
509 
511 {
512  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
513  if (sl->flag & STUDIOLIGHT_TYPE_MATCAP) {
516  }
517  }
519 }
521 {
522  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
523  if (sl->flag & STUDIOLIGHT_TYPE_MATCAP) {
525  if (sl->matcap_specular.ibuf) {
527  }
528  }
529  }
531 }
532 
534 {
535  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
537  ImBuf *ibuf = sl->equirect_irradiance_buffer;
539  "studiolight_irradiance", ibuf->x, ibuf->y, 1, GPU_RGBA16F, ibuf->rect_float);
542  GPU_texture_wrap_mode(tex, true, true);
543  }
545 }
546 
547 static void studiolight_calculate_radiance(ImBuf *ibuf, float color[4], const float direction[3])
548 {
549  float uv[2];
550  direction_to_equirect(uv, direction);
551  nearest_interpolation_color_wrap(ibuf, NULL, color, uv[0] * ibuf->x, uv[1] * ibuf->y);
552 }
553 
555  float *colbuf,
556  const int index_x,
557  const int index_y,
558  const int index_z,
559  const float xsign,
560  const float ysign,
561  const float zsign)
562 {
563  ITER_PIXELS (
565  float direction[3];
566  direction[index_x] = xsign * (x - 0.5f);
567  direction[index_y] = ysign * (y - 0.5f);
568  direction[index_z] = zsign * 0.5f;
569  normalize_v3(direction);
570  studiolight_calculate_radiance(ibuf, pixel, direction);
571  }
573 }
574 
576 {
577  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
579  ImBuf *ibuf = sl->equirect_radiance_buffer;
580  if (ibuf) {
581  float *colbuf = MEM_malloc_arrayN(
582  square_i(STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE), sizeof(float[4]), __func__);
583 
584  /* front */
585  studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 2, 1, 1, -1, 1);
588 
589  /* back */
590  studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 2, 1, 1, 1, -1);
593 
594  /* left */
595  studiolight_calculate_radiance_buffer(ibuf, colbuf, 2, 1, 0, 1, -1, 1);
598 
599  /* right */
600  studiolight_calculate_radiance_buffer(ibuf, colbuf, 2, 1, 0, -1, -1, -1);
603 
604  /* top */
605  studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 1, 2, -1, -1, 1);
608 
609  /* bottom */
610  studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 1, 2, 1, -1, -1);
613 
614 #if 0
616  "/tmp/studiolight_radiance_left.png",
617  IB_rectfloat);
619  "/tmp/studiolight_radiance_right.png",
620  IB_rectfloat);
622  "/tmp/studiolight_radiance_front.png",
623  IB_rectfloat);
625  "/tmp/studiolight_radiance_back.png",
626  IB_rectfloat);
628  "/tmp/studiolight_radiance_bottom.png",
629  IB_rectfloat);
631  "/tmp/studiolight_radiance_top.png",
632  IB_rectfloat);
633 #endif
634  MEM_freeN(colbuf);
635  }
636  }
638 }
639 
640 /*
641  * Spherical Harmonics
642  */
643 BLI_INLINE float area_element(float x, float y)
644 {
645  return atan2(x * y, sqrtf(x * x + y * y + 1));
646 }
647 
648 BLI_INLINE float texel_solid_angle(float x, float y, float halfpix)
649 {
650  float v1x = (x - halfpix) * 2.0f - 1.0f;
651  float v1y = (y - halfpix) * 2.0f - 1.0f;
652  float v2x = (x + halfpix) * 2.0f - 1.0f;
653  float v2y = (y + halfpix) * 2.0f - 1.0f;
654 
655  return area_element(v1x, v1y) - area_element(v1x, v2y) - area_element(v2x, v1y) +
656  area_element(v2x, v2y);
657 }
658 
660  float normal[3], float *weight, int face, float x, float y)
661 {
662  const float halfpix = 0.5f / STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE;
664  *weight = texel_solid_angle(x, y, halfpix);
665 }
666 
668 {
669  float weight_accum = 0.0f;
670  memset(sh, 0, sizeof(float[3]) * STUDIOLIGHT_SH_COEFS_LEN);
671 
672  for (int face = 0; face < 6; face++) {
673  ITER_PIXELS (float,
675  4,
678  float color[3], cubevec[3], weight;
679  studiolight_calculate_cubemap_vector_weight(cubevec, &weight, face, x, y);
680  mul_v3_v3fl(color, pixel, weight);
681  weight_accum += weight;
682 
683  int i = 0;
684  /* L0 */
685  madd_v3_v3fl(sh[i++], color, 0.2822095f);
686 #if STUDIOLIGHT_SH_BANDS > 1 /* L1 */
687  const float nx = cubevec[0];
688  const float ny = cubevec[1];
689  const float nz = cubevec[2];
690  madd_v3_v3fl(sh[i++], color, -0.488603f * nz);
691  madd_v3_v3fl(sh[i++], color, 0.488603f * ny);
692  madd_v3_v3fl(sh[i++], color, -0.488603f * nx);
693 #endif
694 #if STUDIOLIGHT_SH_BANDS > 2 /* L2 */
695  const float nx2 = SQUARE(nx);
696  const float ny2 = SQUARE(ny);
697  const float nz2 = SQUARE(nz);
698  madd_v3_v3fl(sh[i++], color, 1.092548f * nx * nz);
699  madd_v3_v3fl(sh[i++], color, -1.092548f * nz * ny);
700  madd_v3_v3fl(sh[i++], color, 0.315392f * (3.0f * ny2 - 1.0f));
701  madd_v3_v3fl(sh[i++], color, 1.092548f * nx * ny);
702  madd_v3_v3fl(sh[i++], color, 0.546274f * (nx2 - nz2));
703 #endif
704  /* Bypass L3 Because final irradiance does not need it. */
705 #if STUDIOLIGHT_SH_BANDS > 4 /* L4 */
706  const float nx4 = SQUARE(nx2);
707  const float ny4 = SQUARE(ny2);
708  const float nz4 = SQUARE(nz2);
709  madd_v3_v3fl(sh[i++], color, 2.5033429417967046f * nx * nz * (nx2 - nz2));
710  madd_v3_v3fl(sh[i++], color, -1.7701307697799304f * nz * ny * (3.0f * nx2 - nz2));
711  madd_v3_v3fl(sh[i++], color, 0.9461746957575601f * nz * nx * (-1.0f + 7.0f * ny2));
712  madd_v3_v3fl(sh[i++], color, -0.6690465435572892f * nz * ny * (-3.0f + 7.0f * ny2));
713  madd_v3_v3fl(sh[i++], color, (105.0f * ny4 - 90.0f * ny2 + 9.0f) / 28.359261614f);
714  madd_v3_v3fl(sh[i++], color, -0.6690465435572892f * nx * ny * (-3.0f + 7.0f * ny2));
715  madd_v3_v3fl(sh[i++], color, 0.9461746957575601f * (nx2 - nz2) * (-1.0f + 7.0f * ny2));
716  madd_v3_v3fl(sh[i++], color, -1.7701307697799304f * nx * ny * (nx2 - 3.0f * nz2));
717  madd_v3_v3fl(sh[i++], color, 0.6258357354491761f * (nx4 - 6.0f * nz2 * nx2 + nz4));
718 #endif
719  }
721  }
722 
723  /* The sum of solid angle should be equal to the solid angle of the sphere (4 PI),
724  * so normalize in order to make our weightAccum exactly match 4 PI. */
725  for (int i = 0; i < STUDIOLIGHT_SH_COEFS_LEN; i++) {
726  mul_v3_fl(sh[i], M_PI * 4.0f / weight_accum);
727  }
728 }
729 
730 /* Take monochrome SH as input */
731 static float studiolight_spherical_harmonics_lambda_get(float *sh, float max_laplacian)
732 {
733  /* From Peter-Pike Sloan's Stupid SH Tricks http://www.ppsloan.org/publications/StupidSH36.pdf
734  */
735  float table_l[STUDIOLIGHT_SH_BANDS];
736  float table_b[STUDIOLIGHT_SH_BANDS];
737 
738  float lambda = 0.0f;
739 
740  table_l[0] = 0.0f;
741  table_b[0] = 0.0f;
742  int index = 1;
743  for (int level = 1; level < STUDIOLIGHT_SH_BANDS; level++) {
744  table_l[level] = (float)(square_i(level) * square_i(level + 1));
745 
746  float b = 0.0f;
747  for (int m = -1; m <= level; m++) {
748  b += square_f(sh[index++]);
749  }
750  table_b[level] = b;
751  }
752 
753  float squared_lamplacian = 0.0f;
754  for (int level = 1; level < STUDIOLIGHT_SH_BANDS; level++) {
755  squared_lamplacian += table_l[level] * table_b[level];
756  }
757 
758  const float target_squared_laplacian = max_laplacian * max_laplacian;
759  if (squared_lamplacian <= target_squared_laplacian) {
760  return lambda;
761  }
762 
763  const int no_iterations = 10000000;
764  for (int i = 0; i < no_iterations; i++) {
765  float f = 0.0f;
766  float fd = 0.0f;
767 
768  for (int level = 1; level < STUDIOLIGHT_SH_BANDS; level++) {
769  f += table_l[level] * table_b[level] / square_f(1.0f + lambda * table_l[level]);
770  fd += (2.0f * square_f(table_l[level]) * table_b[level]) /
771  cube_f(1.0f + lambda * table_l[level]);
772  }
773 
774  f = target_squared_laplacian - f;
775 
776  float delta = -f / fd;
777  lambda += delta;
778 
779  if (fabsf(delta) < 1e-6f) {
780  break;
781  }
782  }
783 
784  return lambda;
785 }
786 
787 static void studiolight_spherical_harmonics_apply_windowing(float (*sh)[3], float max_laplacian)
788 {
789  if (max_laplacian <= 0.0f) {
790  return;
791  }
792 
793  float sh_r[STUDIOLIGHT_SH_COEFS_LEN];
794  float sh_g[STUDIOLIGHT_SH_COEFS_LEN];
795  float sh_b[STUDIOLIGHT_SH_COEFS_LEN];
796  for (int i = 0; i < STUDIOLIGHT_SH_COEFS_LEN; i++) {
797  sh_r[i] = sh[i][0];
798  sh_g[i] = sh[i][1];
799  sh_b[i] = sh[i][2];
800  }
801  float lambda_r = studiolight_spherical_harmonics_lambda_get(sh_r, max_laplacian);
802  float lambda_g = studiolight_spherical_harmonics_lambda_get(sh_g, max_laplacian);
803  float lambda_b = studiolight_spherical_harmonics_lambda_get(sh_b, max_laplacian);
804 
805  /* Apply windowing lambda */
806  int index = 0;
807  for (int level = 0; level < STUDIOLIGHT_SH_BANDS; level++) {
808  float s[3];
809  const int level_sq = square_i(level);
810  const int level_1_sq = square_i(level + 1.0f);
811  s[0] = 1.0f / (1.0f + lambda_r * level_sq * level_1_sq);
812  s[1] = 1.0f / (1.0f + lambda_g * level_sq * level_1_sq);
813  s[2] = 1.0f / (1.0f + lambda_b * level_sq * level_1_sq);
814 
815  for (int m = -1; m <= level; m++) {
816  mul_v3_v3(sh[index++], s);
817  }
818  }
819 }
820 
822  const float normal[3], float sh0, float sh1, float sh2, float sh3)
823 {
824  /* Use Geomerics non-linear SH. */
825  /* http://www.geomerics.com/wp-content/uploads/2015/08/CEDEC_Geomerics_ReconstructingDiffuseLighting1.pdf
826  */
827  float R0 = sh0 * M_1_PI;
828 
829  float R1[3] = {-sh3, sh2, -sh1};
830  mul_v3_fl(R1, 0.5f * M_1_PI * 1.5f); /* 1.5f is to improve the contrast a bit. */
831  float lenR1 = len_v3(R1);
832  mul_v3_fl(R1, 1.0f / lenR1);
833  float q = 0.5f * (1.0f + dot_v3v3(R1, normal));
834 
835  float p = 1.0f + 2.0f * lenR1 / R0;
836  float a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0);
837 
838  return R0 * (a + (1.0f - a) * (p + 1.0f) * powf(q, p));
839 }
840 
842  float color[3],
843  const float normal[3])
844 {
845 #if STUDIOLIGHT_SH_BANDS == 2
846  float(*sh)[3] = (float(*)[3])sl->spherical_harmonics_coefs;
847  for (int i = 0; i < 3; i++) {
849  normal, sh[0][i], sh[1][i], sh[2][i], sh[3][i]);
850  }
851 #else
852  /* L0 */
853  mul_v3_v3fl(color, sl->spherical_harmonics_coefs[0], 0.282095f);
854 # if STUDIOLIGHT_SH_BANDS > 1 /* L1 */
855  const float nx = normal[0];
856  const float ny = normal[1];
857  const float nz = normal[2];
858  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[1], -0.488603f * nz);
859  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[2], 0.488603f * ny);
860  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[3], -0.488603f * nx);
861 # endif
862 # if STUDIOLIGHT_SH_BANDS > 2 /* L2 */
863  const float nx2 = SQUARE(nx);
864  const float ny2 = SQUARE(ny);
865  const float nz2 = SQUARE(nz);
866  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[4], 1.092548f * nx * nz);
867  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[5], -1.092548f * nz * ny);
868  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[6], 0.315392f * (3.0f * ny2 - 1.0f));
869  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[7], -1.092548 * nx * ny);
870  madd_v3_v3fl(color, sl->spherical_harmonics_coefs[8], 0.546274 * (nx2 - nz2));
871 # endif
872  /* L3 coefs are 0 */
873 # if STUDIOLIGHT_SH_BANDS > 4 /* L4 */
874  const float nx4 = SQUARE(nx2);
875  const float ny4 = SQUARE(ny2);
876  const float nz4 = SQUARE(nz2);
877  madd_v3_v3fl(
878  color, sl->spherical_harmonics_coefs[9], 2.5033429417967046f * nx * nz * (nx2 - nz2));
881  -1.7701307697799304f * nz * ny * (3.0f * nx2 - nz2));
884  0.9461746957575601f * nz * nx * (-1.0f + 7.0f * ny2));
887  -0.6690465435572892f * nz * ny * (-3.0f + 7.0f * ny2));
890  (105.0f * ny4 - 90.0f * ny2 + 9.0f) / 28.359261614f);
893  -0.6690465435572892f * nx * ny * (-3.0f + 7.0f * ny2));
896  0.9461746957575601f * (nx2 - nz2) * (-1.0f + 7.0f * ny2));
899  -1.7701307697799304f * nx * ny * (nx2 - 3.0f * nz2));
902  0.6258357354491761f * (nx4 - 6.0f * nz2 * nx2 + nz4));
903 # endif
904 #endif
905 }
906 
907 /* This modify the radiance into irradiance. */
909 {
910  static const float sl_sh_band_factors[5] = {
911  1.0f,
912  2.0f / 3.0f,
913  1.0f / 4.0f,
914  0.0f,
915  -1.0f / 24.0f,
916  };
917 
918  int index = 0, dst_idx = 0;
919  for (int band = 0; band < STUDIOLIGHT_SH_BANDS; band++) {
920  const int last_band = square_i(band + 1) - square_i(band);
921  for (int m = 0; m < last_band; m++) {
922  /* Skip L3 */
923  if (band != 3) {
924  mul_v3_v3fl(sl->spherical_harmonics_coefs[dst_idx++], sh[index], sl_sh_band_factors[band]);
925  }
926  index++;
927  }
928  }
929 }
930 
932 {
933  /* init light to black */
934  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
936 
937  float sh_coefs[STUDIOLIGHT_SH_COEFS_LEN][3];
941 
942  if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
943  FILE *fp = BLI_fopen(sl->path_sh_cache, "wb");
944  if (fp) {
945  fwrite(sl->spherical_harmonics_coefs, sizeof(sl->spherical_harmonics_coefs), 1, fp);
946  fclose(fp);
947  }
948  }
949  }
951 }
952 
954  const float normal[3],
955  float color[3],
956  int xoffset,
957  int yoffset,
958  int zoffset,
959  float zsign)
960 {
961  if (radiance_buffer == NULL) {
962  return;
963  }
964 
965  float accum[3] = {0.0f, 0.0f, 0.0f};
966  float accum_weight = 0.00001f;
967  ITER_PIXELS (float,
968  radiance_buffer->rect_float,
969  4,
972  float direction[3];
973  direction[zoffset] = zsign * 0.5f;
974  direction[xoffset] = x - 0.5f;
975  direction[yoffset] = y - 0.5f;
976  normalize_v3(direction);
977  float weight = dot_v3v3(direction, normal) > 0.95f ? 1.0f : 0.0f;
978  // float solid_angle = texel_solid_angle(x, y, texel_size[0] * 0.5f);
979  madd_v3_v3fl(accum, pixel, weight);
980  accum_weight += weight;
981  }
983 
984  madd_v3_v3fl(color, accum, 1.0f / accum_weight);
985 }
986 
987 static float brdf_approx(float spec_color, float roughness, float NV)
988 {
989  /* Very rough own approx. We don't need it to be correct, just fast.
990  * Just simulate fresnel effect with roughness attenuation. */
991  float fresnel = exp2(-8.35f * NV) * (1.0f - roughness);
992  return spec_color * (1.0f - fresnel) + fresnel;
993 }
994 
995 /* NL need to be unclamped. w in [0..1] range. */
996 static float wrapped_lighting(float NL, float w)
997 {
998  float w_1 = w + 1.0f;
999  return max_ff((NL + w) / (w_1 * w_1), 0.0f);
1000 }
1001 
1002 static float blinn_specular(const float L[3],
1003  const float I[3],
1004  const float N[3],
1005  const float R[3],
1006  float NL,
1007  float roughness,
1008  float wrap)
1009 {
1010  float half_dir[3];
1011  float wrapped_NL = dot_v3v3(L, R);
1012  add_v3_v3v3(half_dir, L, I);
1013  normalize_v3(half_dir);
1014  float spec_angle = max_ff(dot_v3v3(half_dir, N), 0.0f);
1015 
1016  float gloss = 1.0f - roughness;
1017  /* Reduce gloss for smooth light. (simulate bigger light) */
1018  gloss *= 1.0f - wrap;
1019  float shininess = exp2(10.0f * gloss + 1.0f);
1020 
1021  /* Pi is already divided in the light power.
1022  * normalization_factor = (shininess + 8.0) / (8.0 * M_PI) */
1023  float normalization_factor = shininess * 0.125f + 1.0f;
1024  float spec_light = powf(spec_angle, shininess) * max_ff(NL, 0.0f) * normalization_factor;
1025 
1026  /* Simulate Env. light. */
1027  float w = wrap * (1.0 - roughness) + roughness;
1028  float spec_env = wrapped_lighting(wrapped_NL, w);
1029 
1030  float w2 = wrap * wrap;
1031 
1032  return spec_light * (1.0 - w2) + spec_env * w2;
1033 }
1034 
1035 /* Keep in sync with the glsl shader function get_world_lighting() */
1036 static void studiolight_lights_eval(StudioLight *sl, float color[3], const float normal[3])
1037 {
1038  float R[3], I[3] = {0.0f, 0.0f, 1.0f}, N[3] = {normal[0], normal[2], -normal[1]};
1039  const float roughness = 0.5f;
1040  const float diffuse_color = 0.8f;
1041  const float specular_color = brdf_approx(0.05f, roughness, N[2]);
1042  float diff_light[3], spec_light[3];
1043 
1044  /* Ambient lighting */
1045  copy_v3_v3(diff_light, sl->light_ambient);
1046  copy_v3_v3(spec_light, sl->light_ambient);
1047 
1048  reflect_v3_v3v3(R, I, N);
1049  for (int i = 0; i < STUDIOLIGHT_MAX_LIGHT; i++) {
1050  SolidLight *light = &sl->light[i];
1051  if (light->flag) {
1052  /* Diffuse lighting */
1053  float NL = dot_v3v3(light->vec, N);
1054  float diff = wrapped_lighting(NL, light->smooth);
1055  madd_v3_v3fl(diff_light, light->col, diff);
1056  /* Specular lighting */
1057  float spec = blinn_specular(light->vec, I, N, R, NL, roughness, light->smooth);
1058  madd_v3_v3fl(spec_light, light->spec, spec);
1059  }
1060  }
1061 
1062  /* Multiply result by surface colors. */
1063  mul_v3_fl(diff_light, diffuse_color * (1.0 - specular_color));
1064  mul_v3_fl(spec_light, specular_color);
1065 
1066  add_v3_v3v3(color, diff_light, spec_light);
1067 }
1068 
1070 {
1071 #ifdef STUDIOLIGHT_LOAD_CACHED_FILES
1072  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
1073  ImBuf *ibuf = NULL;
1074  ibuf = IMB_loadiffname(sl->path_irr_cache, 0, NULL);
1075  if (ibuf) {
1076  IMB_float_from_rect(ibuf);
1077  sl->equirect_irradiance_buffer = ibuf;
1079  return true;
1080  }
1081  }
1082 #else
1083  UNUSED_VARS(sl);
1084 #endif
1085  return false;
1086 }
1087 
1089 {
1090 #ifdef STUDIOLIGHT_LOAD_CACHED_FILES
1091  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
1092  FILE *fp = BLI_fopen(sl->path_sh_cache, "rb");
1093  if (fp) {
1094  if (fread((void *)(sl->spherical_harmonics_coefs),
1095  sizeof(sl->spherical_harmonics_coefs),
1096  1,
1097  fp)) {
1099  fclose(fp);
1100  return true;
1101  }
1102  fclose(fp);
1103  }
1104  }
1105 #else
1106  UNUSED_VARS(sl);
1107 #endif
1108  return false;
1109 }
1110 
1112 {
1113  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
1115 
1117  STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT * sizeof(float[4]),
1118  __func__);
1119 
1120  ITER_PIXELS (float,
1121  colbuf,
1122  4,
1125  float dir[3];
1126  equirect_to_direction(dir, x, y);
1127  studiolight_spherical_harmonics_eval(sl, pixel, dir);
1128  pixel[3] = 1.0f;
1129  }
1131 
1133  colbuf,
1136  4);
1137  }
1139 }
1140 
1141 static StudioLight *studiolight_add_file(const char *path, int flag)
1142 {
1143  char filename[FILE_MAXFILE];
1144  BLI_split_file_part(path, filename, FILE_MAXFILE);
1145 
1146  if ((((flag & STUDIOLIGHT_TYPE_STUDIO) != 0) && BLI_path_extension_check(filename, ".sl")) ||
1149  BLI_strncpy(sl->name, filename, FILE_MAXFILE);
1150  BLI_strncpy(sl->path, path, FILE_MAXFILE);
1151 
1152  if ((flag & STUDIOLIGHT_TYPE_STUDIO) != 0) {
1154  }
1155  else {
1156  sl->path_irr_cache = BLI_string_joinN(path, ".irr");
1157  sl->path_sh_cache = BLI_string_joinN(path, ".sh2");
1158  }
1159  BLI_addtail(&studiolights, sl);
1160  return sl;
1161  }
1162  return NULL;
1163 }
1164 
1165 static void studiolight_add_files_from_datafolder(const int folder_id,
1166  const char *subfolder,
1167  int flag)
1168 {
1169  struct direntry *dirs;
1170  const char *folder = BKE_appdir_folder_id(folder_id, subfolder);
1171  if (folder) {
1172  const uint dirs_num = BLI_filelist_dir_contents(folder, &dirs);
1173  int i;
1174  for (i = 0; i < dirs_num; i++) {
1175  if (dirs[i].type & S_IFREG) {
1176  studiolight_add_file(dirs[i].path, flag);
1177  }
1178  }
1179  BLI_filelist_free(dirs, dirs_num);
1180  dirs = NULL;
1181  }
1182 }
1183 
1185 {
1186  /* Internal studiolights before external studio lights */
1187  if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
1188  return 1;
1189  }
1190  return 0;
1191 }
1192 
1193 static int studiolight_cmp(const void *a, const void *b)
1194 {
1195  const StudioLight *sl1 = a;
1196  const StudioLight *sl2 = b;
1197 
1198  const int flagorder1 = studiolight_flag_cmp_order(sl1);
1199  const int flagorder2 = studiolight_flag_cmp_order(sl2);
1200 
1201  if (flagorder1 < flagorder2) {
1202  return -1;
1203  }
1204  if (flagorder1 > flagorder2) {
1205  return 1;
1206  }
1207 
1208  return BLI_strcasecmp(sl1->name, sl2->name);
1209 }
1210 
1211 /* icons */
1212 
1213 /* Takes normalized uvs as parameter (range from 0 to 1).
1214  * inner_edge and outer_edge are distances (from the center)
1215  * in uv space for the alpha mask falloff. */
1216 static uint alpha_circle_mask(float u, float v, float inner_edge, float outer_edge)
1217 {
1218  /* Coords from center. */
1219  const float co[2] = {u - 0.5f, v - 0.5f};
1220  float dist = len_v2(co);
1221  float alpha = 1.0f + (inner_edge - dist) / (outer_edge - inner_edge);
1222  uint mask = (uint)floorf(255.0f * min_ff(max_ff(alpha, 0.0f), 1.0f));
1223  return mask << 24;
1224 }
1225 
1226 /* Percentage of the icon that the preview sphere covers. */
1227 #define STUDIOLIGHT_DIAMETER 0.95f
1228 /* Rescale coord around (0.5, 0.5) by STUDIOLIGHT_DIAMETER. */
1229 #define RESCALE_COORD(x) (x / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f)
1230 
1231 /* Remaps normalized UV [0..1] to a sphere normal around (0.5, 0.5) */
1232 static void sphere_normal_from_uv(float normal[3], float u, float v)
1233 {
1234  normal[0] = u * 2.0f - 1.0f;
1235  normal[1] = v * 2.0f - 1.0f;
1236  float dist = len_v2(normal);
1237  normal[2] = sqrtf(1.0f - square_f(dist));
1238 }
1239 
1240 static void studiolight_radiance_preview(uint *icon_buffer, StudioLight *sl)
1241 {
1243 
1245  float dy = RESCALE_COORD(y);
1246  float dx = RESCALE_COORD(x);
1247 
1248  uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
1249  if (alphamask != 0) {
1250  float normal[3], direction[3], color[4];
1251  const float incoming[3] = {0.0f, 0.0f, -1.0f};
1252  sphere_normal_from_uv(normal, dx, dy);
1253  reflect_v3_v3v3(direction, incoming, normal);
1254  /* We want to see horizon not poles. */
1255  SWAP(float, direction[1], direction[2]);
1256  direction[1] = -direction[1];
1257 
1259 
1260  *pixel = rgb_to_cpack(linearrgb_to_srgb(color[0]),
1262  linearrgb_to_srgb(color[2])) |
1263  alphamask;
1264  }
1265  else {
1266  *pixel = 0x0;
1267  }
1268  }
1270 }
1271 
1272 static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool flipped)
1273 {
1275 
1276  ImBuf *diffuse_buffer = sl->matcap_diffuse.ibuf;
1277  ImBuf *specular_buffer = sl->matcap_specular.ibuf;
1278 
1280  float dy = RESCALE_COORD(y);
1281  float dx = RESCALE_COORD(x);
1282  if (flipped) {
1283  dx = 1.0f - dx;
1284  }
1285 
1286  float color[4];
1287  float u = dx * diffuse_buffer->x - 1.0f;
1288  float v = dy * diffuse_buffer->y - 1.0f;
1289  nearest_interpolation_color(diffuse_buffer, NULL, color, u, v);
1290 
1291  if (specular_buffer) {
1292  float specular[4];
1293  nearest_interpolation_color(specular_buffer, NULL, specular, u, v);
1295  }
1296 
1297  uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
1298 
1299  *pixel = rgb_to_cpack(linearrgb_to_srgb(color[0]),
1301  linearrgb_to_srgb(color[2])) |
1302  alphamask;
1303  }
1305 }
1306 
1307 static void studiolight_irradiance_preview(uint *icon_buffer, StudioLight *sl)
1308 {
1310  float dy = RESCALE_COORD(y);
1311  float dx = RESCALE_COORD(x);
1312 
1313  uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
1314  if (alphamask != 0) {
1315  float normal[3], color[3];
1316  sphere_normal_from_uv(normal, dx, dy);
1317  /* We want to see horizon not poles. */
1318  SWAP(float, normal[1], normal[2]);
1319  normal[1] = -normal[1];
1320 
1322 
1323  *pixel = rgb_to_cpack(linearrgb_to_srgb(color[0]),
1325  linearrgb_to_srgb(color[2])) |
1326  alphamask;
1327  }
1328  else {
1329  *pixel = 0x0;
1330  }
1331  }
1333 }
1334 
1335 void BKE_studiolight_default(SolidLight lights[4], float light_ambient[3])
1336 {
1337  copy_v3_fl3(light_ambient, 0.0, 0.0, 0.0);
1338 
1339  lights[0].flag = 1;
1340  lights[0].smooth = 0.526620f;
1341  lights[0].col[0] = 0.033103f;
1342  lights[0].col[1] = 0.033103f;
1343  lights[0].col[2] = 0.033103f;
1344  lights[0].spec[0] = 0.266761f;
1345  lights[0].spec[1] = 0.266761f;
1346  lights[0].spec[2] = 0.266761f;
1347  lights[0].vec[0] = -0.352546f;
1348  lights[0].vec[1] = 0.170931f;
1349  lights[0].vec[2] = -0.920051f;
1350 
1351  lights[1].flag = 1;
1352  lights[1].smooth = 0.000000f;
1353  lights[1].col[0] = 0.521083f;
1354  lights[1].col[1] = 0.538226f;
1355  lights[1].col[2] = 0.538226f;
1356  lights[1].spec[0] = 0.599030f;
1357  lights[1].spec[1] = 0.599030f;
1358  lights[1].spec[2] = 0.599030f;
1359  lights[1].vec[0] = -0.408163f;
1360  lights[1].vec[1] = 0.346939f;
1361  lights[1].vec[2] = 0.844415f;
1362 
1363  lights[2].flag = 1;
1364  lights[2].smooth = 0.478261f;
1365  lights[2].col[0] = 0.038403f;
1366  lights[2].col[1] = 0.034357f;
1367  lights[2].col[2] = 0.049530f;
1368  lights[2].spec[0] = 0.106102f;
1369  lights[2].spec[1] = 0.125981f;
1370  lights[2].spec[2] = 0.158523f;
1371  lights[2].vec[0] = 0.521739f;
1372  lights[2].vec[1] = 0.826087f;
1373  lights[2].vec[2] = 0.212999f;
1374 
1375  lights[3].flag = 1;
1376  lights[3].smooth = 0.200000f;
1377  lights[3].col[0] = 0.090838f;
1378  lights[3].col[1] = 0.082080f;
1379  lights[3].col[2] = 0.072255f;
1380  lights[3].spec[0] = 0.106535f;
1381  lights[3].spec[1] = 0.084771f;
1382  lights[3].spec[2] = 0.066080f;
1383  lights[3].vec[0] = 0.624519f;
1384  lights[3].vec[1] = -0.562067f;
1385  lights[3].vec[2] = -0.542269f;
1386 }
1387 
1389 {
1390  /* Add default studio light */
1394  BLI_strncpy(sl->name, "Default", FILE_MAXFILE);
1395 
1396  BLI_addtail(&studiolights, sl);
1397 
1398  /* Go over the preset folder and add a studio-light for every image with its path. */
1399  /* For portable installs (where USER and SYSTEM paths are the same),
1400  * only go over LOCAL data-files once. */
1401  /* Also reserve icon space for it. */
1413  }
1422 
1423  /* sort studio lights on filename. */
1425 
1427 }
1428 
1430 {
1431  struct StudioLight *sl;
1432  while ((sl = BLI_pophead(&studiolights))) {
1433  studiolight_free(sl);
1434  }
1435 }
1436 
1438 {
1439  const char *default_name = "";
1440 
1441  if (flag & STUDIOLIGHT_TYPE_WORLD) {
1442  default_name = STUDIOLIGHT_WORLD_DEFAULT;
1443  }
1444  else if (flag & STUDIOLIGHT_TYPE_MATCAP) {
1445  default_name = STUDIOLIGHT_MATCAP_DEFAULT;
1446  }
1447 
1449  if ((sl->flag & flag) && STREQ(sl->name, default_name)) {
1450  return sl;
1451  }
1452  }
1453 
1455  if (sl->flag & flag) {
1456  return sl;
1457  }
1458  }
1459  return NULL;
1460 }
1461 
1462 struct StudioLight *BKE_studiolight_find(const char *name, int flag)
1463 {
1465  if (STREQLEN(sl->name, name, FILE_MAXFILE)) {
1466  if (sl->flag & flag) {
1467  return sl;
1468  }
1469 
1470  /* flags do not match, so use default */
1472  }
1473  }
1474  /* When not found, use the default studio light */
1476 }
1477 
1479 {
1481  if (sl->index == index) {
1482  return sl;
1483  }
1484  }
1485  /* When not found, use the default studio light */
1487 }
1488 
1490 {
1491  return &studiolights;
1492 }
1493 
1494 void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type)
1495 {
1496  switch (icon_id_type) {
1498  default: {
1499  studiolight_radiance_preview(icon_buffer, sl);
1500  break;
1501  }
1503  studiolight_irradiance_preview(icon_buffer, sl);
1504  break;
1505  }
1507  studiolight_matcap_preview(icon_buffer, sl, false);
1508  break;
1509  }
1511  studiolight_matcap_preview(icon_buffer, sl, true);
1512  break;
1513  }
1514  }
1515 }
1516 
1518 {
1519  if ((sl->flag & flag) == flag) {
1520  return;
1521  }
1522 
1523  if (flag & STUDIOLIGHT_EXTERNAL_IMAGE_LOADED) {
1525  }
1528  }
1532  }
1533  }
1536  }
1539  }
1543  }
1544  }
1547  }
1550  }
1551 }
1552 
1553 /*
1554  * Python API Functions.
1555  */
1556 
1558 {
1559  if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
1560  BLI_remlink(&studiolights, sl);
1561  studiolight_free(sl);
1562  }
1563 }
1564 
1565 StudioLight *BKE_studiolight_load(const char *path, int type)
1566 {
1568  return sl;
1569 }
1570 
1572  const SolidLight light[4],
1573  const float light_ambient[3])
1574 {
1578 
1579  char filename[FILE_MAXFILE];
1580  BLI_split_file_part(path, filename, FILE_MAXFILE);
1581  STRNCPY(sl->path, path);
1582  STRNCPY(sl->name, filename);
1583 
1584  memcpy(sl->light, light, sizeof(*light) * 4);
1585  memcpy(sl->light_ambient, light_ambient, sizeof(*light_ambient) * 3);
1586 
1588 
1589  BLI_addtail(&studiolights, sl);
1590  return sl;
1591 }
1592 
1594 {
1595  static StudioLight sl = {0};
1597 
1598  memcpy(sl.light, U.light_param, sizeof(*sl.light) * 4);
1599  memcpy(sl.light_ambient, U.light_ambient, sizeof(*sl.light_ambient) * 3);
1600 
1601  return &sl;
1602 }
1603 
1605 {
1608 }
1609 
1611  StudioLightFreeFunction *free_function,
1612  void *data)
1613 {
1614  sl->free_function = free_function;
1615  sl->free_function_data = data;
1616 }
1617 
1619 {
1620  BLI_assert(sl != NULL);
1621  if (sl->icon_id_radiance == icon_id) {
1622  sl->icon_id_radiance = 0;
1623  }
1624  if (sl->icon_id_irradiance == icon_id) {
1625  sl->icon_id_irradiance = 0;
1626  }
1627  if (sl->icon_id_matcap == icon_id) {
1628  sl->icon_id_matcap = 0;
1629  }
1630  if (sl->icon_id_matcap_flipped == icon_id) {
1631  sl->icon_id_matcap_flipped = 0;
1632  }
1633 }
typedef float(TangentPoint)[2]
bool BKE_appdir_app_is_portable_install(void)
Definition: appdir.c:404
const char * BKE_appdir_folder_id(int folder_id, const char *subfolder)
Definition: appdir.c:672
@ BLENDER_USER_DATAFILES
Definition: BKE_appdir.h:158
@ BLENDER_SYSTEM_DATAFILES
Definition: BKE_appdir.h:163
int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type)
Definition: icons.cc:1005
#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:46
#define BLI_INLINE
A dynamically sized string ADT.
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_dynstr.c:50
int BLI_dynstr_get_len(const DynStr *ds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_dynstr.c:235
char * BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_dynstr.c:256
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
Definition: BLI_dynstr.c:281
File and directory operations.
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:906
unsigned int BLI_filelist_dir_contents(const char *dir, struct direntry **r_filelist)
Definition: BLI_filelist.c:218
void BLI_file_free_lines(struct LinkNode *lines)
Definition: storage.c:564
void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries)
Definition: BLI_filelist.c:420
struct LinkNode * BLI_file_read_as_lines(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:518
Some types for dealing with directories.
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:221
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
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:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
#define M_1_PI
Definition: BLI_math_base.h:41
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:20
unsigned int rgb_to_cpack(float r, float g, float b)
Definition: math_color.c:348
float linearrgb_to_srgb(float c)
Definition: math_color.c:412
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:926
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:691
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:1326
#define FILE_MAXFILE
bool BLI_path_extension_check(const char *str, const char *ext) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1299
void BLI_split_file_part(const char *string, char *file, size_t filelen)
Definition: path_util.c:1495
#define STRNCPY(dst, src)
Definition: BLI_string.h:483
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:623
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
#define BLI_string_joinN(...)
unsigned int uint
Definition: BLI_sys_types.h:67
#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 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
_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
void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat, bool use_clamp)
Definition: gpu_texture.cc:546
struct GPUTexture GPUTexture
Definition: GPU_texture.h:17
@ GPU_DATA_FLOAT
Definition: GPU_texture.h:171
void GPU_texture_update(GPUTexture *tex, eGPUDataFormat data_format, const void *data)
Definition: gpu_texture.cc:444
void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter)
Definition: gpu_texture.cc:518
GPUTexture * GPU_texture_create_2d(const char *name, int w, int h, int mip_len, eGPUTextureFormat format, const float *data)
Definition: gpu_texture.cc:291
@ GPU_R11F_G11F_B10F
Definition: GPU_texture.h:118
void IMB_float_from_rect(struct ImBuf *ibuf)
Definition: divers.c:805
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:409
struct ImBuf * IMB_allocFromBufferOwn(unsigned int *rect, float *rectf, unsigned int w, unsigned int h, unsigned int channels)
Definition: allocimbuf.c:415
struct ImBuf * IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_SPACE])
Definition: readimage.c:209
void nearest_interpolation_color(const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
Definition: imageprocess.c:278
void nearest_interpolation_color_wrap(const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
Definition: imageprocess.c:289
struct ImBuf * IMB_allocFromBuffer(const unsigned int *rect, const float *rectf, unsigned int w, unsigned int h, unsigned int channels)
Definition: allocimbuf.c:447
bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags)
Definition: writeimage.c:22
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:43
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))
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a color
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 sinf(x)
Definition: cuda/compat.h:102
#define cosf(x)
Definition: cuda/compat.h:101
#define powf(x, y)
Definition: cuda/compat.h:103
#define NL
float texel_size[2]
Definition: eevee_effects.c:27
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img GPU_RGBA16F
#define str(s)
void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
@ IMB_FTYPE_OPENEXR
IconTextureDrawCall normal
ccl_gpu_kernel_postfix ccl_global float int int int int sh
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
#define N
#define R
#define L
#define atan2f(x, y)
Definition: metal/compat.h:227
#define floorf(x)
Definition: metal/compat.h:224
#define acosf(x)
Definition: metal/compat.h:222
#define fabsf(x)
Definition: metal/compat.h:219
#define sqrtf(x)
Definition: metal/compat.h:243
static unsigned a[3]
Definition: RandGen.cpp:78
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 struct PartialUpdateUser * wrap(PartialUpdateUserImpl *user)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static const pxr::TfToken roughness("roughness", pxr::TfToken::Immortal)
static const pxr::TfToken specular("specular", pxr::TfToken::Immortal)
static const pxr::TfToken diffuse_color("diffuseColor", pxr::TfToken::Immortal)
#define I
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:520
#define STUDIOLIGHT_FILE_VERSION
Definition: studiolight.c:170
static const char * STUDIOLIGHT_LIGHTS_FOLDER
Definition: studiolight.c:51
static void studiolight_radiance_preview(uint *icon_buffer, StudioLight *sl)
Definition: studiolight.c:1240
#define WRITE_IVAL(str, id, val)
Definition: studiolight.c:221
void BKE_studiolight_remove(StudioLight *sl)
Definition: studiolight.c:1557
#define STUDIOLIGHT_PASSNAME_DIFFUSE
Definition: studiolight.c:40
#define STUDIOLIGHT_SH_WINDOWING
Definition: studiolight.c:43
static float * studiolight_multilayer_convert_pass(ImBuf *ibuf, float *rect, const unsigned int channels)
Definition: studiolight.c:345
static void * studiolight_multilayer_addview(void *UNUSED(base), const char *UNUSED(view_name))
Definition: studiolight.c:333
struct StudioLight * BKE_studiolight_findindex(int index, int flag)
Definition: studiolight.c:1478
static void studiolight_irradiance_preview(uint *icon_buffer, StudioLight *sl)
Definition: studiolight.c:1307
static const char * STUDIOLIGHT_MATCAP_DEFAULT
Definition: studiolight.c:56
static void studiolight_spherical_harmonics_calculate_coefficients(StudioLight *sl, float(*sh)[3])
Definition: studiolight.c:667
static struct StudioLight * studiolight_create(int flag)
Definition: studiolight.c:141
#define WRITE_SOLIDLIGHT(str, sl, i)
Definition: studiolight.c:230
static bool studiolight_load_irradiance_equirect_image(StudioLight *sl)
Definition: studiolight.c:1069
static void studiolight_lights_eval(StudioLight *sl, float color[3], const float normal[3])
Definition: studiolight.c:1036
static int last_studiolight_id
Definition: studiolight.c:36
static int studiolight_cmp(const void *a, const void *b)
Definition: studiolight.c:1193
static void studiolight_calculate_cubemap_vector_weight(float normal[3], float *weight, int face, float x, float y)
Definition: studiolight.c:659
#define ITER_PIXELS(type, src, channels, width, height)
Definition: studiolight.c:73
static int studiolight_flag_cmp_order(const StudioLight *sl)
Definition: studiolight.c:1184
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:554
static void cube_face_uv_to_direction(float r_dir[3], float x, float y, int face)
Definition: studiolight.c:310
static StudioLight * studiolight_add_file(const char *path, int flag)
Definition: studiolight.c:1141
static ListBase studiolights
Definition: studiolight.c:35
static bool studiolight_load_spherical_harmonics_coefficients(StudioLight *sl)
Definition: studiolight.c:1088
struct ListBase * BKE_studiolight_listbase(void)
Definition: studiolight.c:1489
static void studiolight_calculate_radiance(ImBuf *ibuf, float color[4], const float direction[3])
Definition: studiolight.c:547
StudioLight * BKE_studiolight_load(const char *path, int type)
Definition: studiolight.c:1565
static void studiolight_spherical_harmonics_apply_windowing(float(*sh)[3], float max_laplacian)
Definition: studiolight.c:787
StudioLight * BKE_studiolight_create(const char *path, const SolidLight light[4], const float light_ambient[3])
Definition: studiolight.c:1571
BLI_INLINE float texel_solid_angle(float x, float y, float halfpix)
Definition: studiolight.c:648
static void studiolight_load_equirect_image(StudioLight *sl)
Definition: studiolight.c:395
void BKE_studiolight_unset_icon_id(StudioLight *sl, int icon_id)
Definition: studiolight.c:1618
static uint alpha_circle_mask(float u, float v, float inner_edge, float outer_edge)
Definition: studiolight.c:1216
static void studiolight_calculate_radiance_cubemap_buffers(StudioLight *sl)
Definition: studiolight.c:575
static void studiolight_create_matcap_gputexture(StudioLightImage *sli)
Definition: studiolight.c:492
static void UNUSED_FUNCTION() direction_to_cube_face_uv(float r_uv[2], int *r_face, const float dir[3])
Definition: studiolight.c:284
static void sphere_normal_from_uv(float normal[3], float u, float v)
Definition: studiolight.c:1232
#define STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT
Definition: studiolight.c:38
static void * studiolight_multilayer_addlayer(void *base, const char *UNUSED(layer_name))
Definition: studiolight.c:337
void BKE_studiolight_set_free_function(StudioLight *sl, StudioLightFreeFunction *free_function, void *data)
Definition: studiolight.c:1610
#define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE
Definition: studiolight.c:37
static void studiolight_add_files_from_datafolder(const int folder_id, const char *subfolder, int flag)
Definition: studiolight.c:1165
#define WRITE_VEC3(str, id, val)
Definition: studiolight.c:223
BLI_INLINE float area_element(float x, float y)
Definition: studiolight.c:643
void BKE_studiolight_default(SolidLight lights[4], float light_ambient[3])
Definition: studiolight.c:1335
static void studiolight_calculate_diffuse_light(StudioLight *sl)
Definition: studiolight.c:931
#define ITER_PIXELS_END
Definition: studiolight.c:83
static void studiolight_calculate_irradiance_equirect_image(StudioLight *sl)
Definition: studiolight.c:1111
static void studiolight_load_solid_light(StudioLight *sl)
Definition: studiolight.c:202
void BKE_studiolight_init(void)
Definition: studiolight.c:1388
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:370
static float wrapped_lighting(float NL, float w)
Definition: studiolight.c:996
static void studiolight_free(struct StudioLight *sl)
Definition: studiolight.c:106
#define STUDIOLIGHT_DELETE_ICON(s)
#define STUDIOLIGHT_PASSNAME_SPECULAR
Definition: studiolight.c:41
static const char * STUDIOLIGHT_WORLD_FOLDER
Definition: studiolight.c:52
static void studiolight_spherical_harmonics_apply_band_factors(StudioLight *sl, float(*sh)[3])
Definition: studiolight.c:908
static void studiolight_create_matcap_diffuse_gputexture(StudioLight *sl)
Definition: studiolight.c:510
struct StudioLight * BKE_studiolight_find(const char *name, int flag)
Definition: studiolight.c:1462
#define READ_VEC3(id, val, lines)
Definition: studiolight.c:186
void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
Definition: studiolight.c:1517
#define IMB_SAFE_FREE(p)
Definition: studiolight.c:90
static float studiolight_spherical_harmonics_lambda_get(float *sh, float max_laplacian)
Definition: studiolight.c:731
#define STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH
Definition: studiolight.c:39
static const char * STUDIOLIGHT_MATCAP_FOLDER
Definition: studiolight.c:53
#define RESCALE_COORD(x)
Definition: studiolight.c:1229
static void studiolight_create_equirect_radiance_gputexture(StudioLight *sl)
Definition: studiolight.c:477
static float brdf_approx(float spec_color, float roughness, float NV)
Definition: studiolight.c:987
BLI_INLINE void studiolight_spherical_harmonics_eval(StudioLight *sl, float color[3], const float normal[3])
Definition: studiolight.c:841
#define GPU_TEXTURE_SAFE_FREE(p)
Definition: studiolight.c:98
static void direction_to_equirect(float r[2], const float dir[3])
Definition: studiolight.c:268
static float studiolight_spherical_harmonics_geomerics_eval(const float normal[3], float sh0, float sh1, float sh2, float sh3)
Definition: studiolight.c:821
static void studiolight_write_solid_light(StudioLight *sl)
Definition: studiolight.c:239
struct StudioLight * BKE_studiolight_find_default(int flag)
Definition: studiolight.c:1437
static const char * STUDIOLIGHT_WORLD_DEFAULT
Definition: studiolight.c:55
static void studiolight_create_equirect_irradiance_gputexture(StudioLight *sl)
Definition: studiolight.c:533
StudioLight * BKE_studiolight_studio_edit_get(void)
Definition: studiolight.c:1593
void BKE_studiolight_free(void)
Definition: studiolight.c:1429
static void equirect_to_direction(float r[3], float u, float v)
Definition: studiolight.c:274
#define READ_SOLIDLIGHT(sl, i, lines)
Definition: studiolight.c:193
static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool flipped)
Definition: studiolight.c:1272
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:1002
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:953
void BKE_studiolight_refresh(void)
Definition: studiolight.c:1604
void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type)
Definition: studiolight.c:1494