From d3c4248946f65d287f18b3d6488cd450dfb6d81d Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 11 May 2018 16:55:14 +0200 Subject: [PATCH] Workbench: StudioLight HDRI's The Studio lights are now loaded from disk. The location is `datafiles/studiolights` they need to be JPG for now. JPG cannot store HDRI color range but they are clamped inside the Workbench engine for speed reason. I didn't select JP2K as it might not be enabled. Users can add upto 20 HDRI files. This limitation is inside the RNA_space.c Currently the icons are calculated when you first open the selection box for the HDRI's. We could add them to a background rendering later. I added 2 test files a sky texture rendered in Cycles and an HDRI from cloud.blender.org. --- release/datafiles/studiolights/sl01.jpg | Bin 0 -> 7314 bytes release/datafiles/studiolights/sl02.jpg | Bin 0 -> 49661 bytes source/blender/blenkernel/BKE_icons.h | 4 + source/blender/blenkernel/BKE_studiolight.h | 73 +++++ source/blender/blenkernel/CMakeLists.txt | 2 + source/blender/blenkernel/intern/icons.c | 11 + .../blender/blenkernel/intern/studiolight.c | 297 ++++++++++++++++++ source/blender/draw/DRW_engine.h | 1 - .../engines/workbench/workbench_materials.c | 5 +- .../engines/workbench/workbench_private.h | 5 +- .../engines/workbench/workbench_studiolight.c | 117 +------ source/blender/editors/include/UI_icons.h | 7 - .../editors/interface/interface_icons.c | 34 +- source/blender/makesdna/DNA_view3d_types.h | 3 +- source/blender/makesrna/intern/rna_space.c | 75 ++++- .../windowmanager/intern/wm_init_exit.c | 4 +- source/creator/CMakeLists.txt | 8 + 17 files changed, 496 insertions(+), 150 deletions(-) create mode 100644 release/datafiles/studiolights/sl01.jpg create mode 100644 release/datafiles/studiolights/sl02.jpg create mode 100644 source/blender/blenkernel/BKE_studiolight.h create mode 100644 source/blender/blenkernel/intern/studiolight.c diff --git a/release/datafiles/studiolights/sl01.jpg b/release/datafiles/studiolights/sl01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cd007bade683b641d56e153c823010bdd2ce34e7 GIT binary patch literal 7314 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 literal 0 HcmV?d00001 diff --git a/release/datafiles/studiolights/sl02.jpg b/release/datafiles/studiolights/sl02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1c9ce99a0d86f2563542aefe53c586cc8c9218f8 GIT binary patch literal 49661 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

LLH(l9N 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 literal 0 HcmV?d00001 diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h index 766704b8f9c..e54531bdb0e 100644 --- a/source/blender/blenkernel/BKE_icons.h +++ b/source/blender/blenkernel/BKE_icons.h @@ -43,6 +43,7 @@ enum { ICON_DATA_PREVIEW, /** 2D triangles: obj is #Icon_Geom */ ICON_DATA_GEOM, + ICON_DATA_STUDIOLIGHT, }; struct Icon { @@ -77,6 +78,7 @@ typedef struct Icon Icon; struct ImBuf; struct PreviewImage; struct ID; +struct StudioLight; enum eIconSizes; @@ -158,6 +160,8 @@ struct ImBuf *BKE_icon_geom_rasterize( const struct Icon_Geom *geom, const unsigned int size_x, const unsigned int size_y); +int BKE_icon_ensure_studio_light(struct StudioLight *sl); + #define ICON_RENDER_DEFAULT_HEIGHT 32 #endif /* __BKE_ICONS_H__ */ diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h new file mode 100644 index 00000000000..c65e9050157 --- /dev/null +++ b/source/blender/blenkernel/BKE_studiolight.h @@ -0,0 +1,73 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2006-2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_STUDIOLIGHT_H__ +#define __BKE_STUDIOLIGHT_H__ + +/** \file BKE_studiolight.h + * \ingroup bke + * + * Studio lighting for the 3dview + */ + +#include "BLI_sys_types.h" + +#include "DNA_space_types.h" + +#define STUDIOLIGHT_X_POS 0 +#define STUDIOLIGHT_X_NEG 1 +#define STUDIOLIGHT_Y_POS 2 +#define STUDIOLIGHT_Y_NEG 3 +#define STUDIOLIGHT_Z_POS 4 +#define STUDIOLIGHT_Z_NEG 5 + +enum StudioLightFlag +{ + STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED = (1 << 0), + STUDIOLIGHT_EXTERNAL_FILE = (1 << 1), +} StudioLightFlag; + +typedef struct StudioLight +{ + struct StudioLight *next, *prev; + int flag; + char name[FILE_MAXFILE]; + char path[FILE_MAX]; + int icon_id; + int index; + float diffuse_light[6][3]; +} StudioLight; + +void BKE_studiolight_init(void); +void BKE_studiolight_free(void); +struct StudioLight *BKE_studiolight_find(const char* name); +struct StudioLight *BKE_studiolight_findindex(int index); +unsigned int *BKE_studiolight_preview(StudioLight *sl, int icon_size); +const struct ListBase *BKE_studiolight_listbase(void); +void BKE_studiolight_ensure_flag(StudioLight *sl, int flag); + +#endif /* __BKE_STUDIOLIGHT_H__ */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 37e08cedb10..d5ce6f2f94d 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -185,6 +185,7 @@ set(SRC intern/softbody.c intern/sound.c intern/speaker.c + intern/studiolight.c intern/subsurf_ccg.c intern/suggestions.c intern/text.c @@ -303,6 +304,7 @@ set(SRC BKE_softbody.h BKE_sound.h BKE_speaker.h + BKE_studiolight.h BKE_subsurf.h BKE_suggestions.h BKE_text.h diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index f1f343faac8..61c05c2500d 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -56,6 +56,7 @@ #include "BKE_icons.h" #include "BKE_global.h" /* only for G.background test */ +#include "BKE_studiolight.h" #include "BLI_sys_types.h" // for intptr_t support @@ -802,3 +803,13 @@ struct Icon_Geom *BKE_icon_geom_from_file(const char *filename) } /** \} */ + +/** \name Studio Light Icon + * \{ */ +int BKE_icon_ensure_studio_light(struct StudioLight *sl) { + int icon_id = get_next_free_id(); + icon_create(icon_id, ICON_DATA_STUDIOLIGHT, sl); + return icon_id; +} +/** \} */ + diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c new file mode 100644 index 00000000000..9bc678a1820 --- /dev/null +++ b/source/blender/blenkernel/intern/studiolight.c @@ -0,0 +1,297 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2006-2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/blenkernel/intern/studiolight.c + * \ingroup bke + */ + +#include "BKE_studiolight.h" + +#include "BKE_appdir.h" +#include "BKE_icons.h" + +#include "BLI_fileops.h" +#include "BLI_fileops_types.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "DNA_listBase.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "MEM_guardedalloc.h" + + +/* Statics */ +static ListBase studiolights; +static const char *STUDIO_LIGHT_FOLDER = "studiolights/"; + +/* FUNCTIONS */ +static void studiolight_free(struct StudioLight *sl) +{ + MEM_freeN(sl); +} + +static struct StudioLight *studiolight_create(void) +{ + struct StudioLight *sl = MEM_callocN(sizeof(*sl), __func__); + sl->path[0] = 0x00; + sl->name[0] = 0x00; + sl->flag = 0; + sl->index = BLI_listbase_count(&studiolights); + sl->icon_id = BKE_icon_ensure_studio_light(sl); + return sl; +} + +static void direction_to_equirectangular(float r[2], const float dir[3]) +{ + r[0] = (atan2f(dir[1], dir[0]) - M_PI) / -(M_PI * 2); + r[1] = (acosf(dir[2] / 1.0) - M_PI) / -M_PI; +} + +static void studiolight_calculate_directional_diffuse_light(ImBuf *ibuf, float color[4], const float start[3], const float v1[3], const float v2[3], int steps) +{ + float uv[2]; + float dir[3]; + float col[4]; + float v11[3]; + float v12[3]; + float totcol[4]; + + zero_v4(totcol); + for (int x = 0; x < steps ; x++) { + float xf = (float)x / (float)steps; + mul_v3_v3fl(v11, v1, xf); + for (int y = 0; y < steps; y++) { + float yf = (float)y / (float)steps; + /* start + x/steps*v1 + y/steps*v2 */ + mul_v3_v3fl(v12, v2, yf); + add_v3_v3v3(dir, start, v11); + add_v3_v3(dir, v12); + /* normalize */ + normalize_v3(dir); + + /* sample */ + direction_to_equirectangular(uv, dir); + nearest_interpolation_color_wrap(ibuf, NULL, col, uv[0] * ibuf->x, uv[1] * ibuf->y); + add_v3_v3(totcol, col); + } + } + mul_v3_v3fl(color, totcol, 1.0/(steps*steps)); +} + +static void studiolight_calculate_diffuse_light(StudioLight *sl) +{ + const int steps = 16; + float start[3]; + float v1[3]; + float v2[3]; + + /* init light to black */ + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_POS], 0.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_NEG], 0.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_POS], 0.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_NEG], 0.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_POS], 0.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_NEG], 0.0f); + + if (sl->flag &= STUDIOLIGHT_EXTERNAL_FILE) { + ImBuf* ibuf = NULL; + ibuf = IMB_loadiffname(sl->path, 0, NULL); + if (ibuf) { + IMB_float_from_rect(ibuf); + + copy_v3_fl3(start, -1.0f, -1.0f, -1.0f); + copy_v3_fl3(v1, 0.0f, 2.0f, 0.0f); + copy_v3_fl3(v2, 0.0f, 0.0f, 2.0f); + studiolight_calculate_directional_diffuse_light(ibuf, sl->diffuse_light[STUDIOLIGHT_Z_NEG], start, v1, v2, steps); + copy_v3_fl3(start, 1.0f, -1.0f, -1.0f); + studiolight_calculate_directional_diffuse_light(ibuf, sl->diffuse_light[STUDIOLIGHT_Z_POS], start, v1, v2, steps); + + copy_v3_fl3(start, -1.0f, -1.0f, -1.0f); + copy_v3_fl3(v1, 2.0f, 0.0f, 0.0f); + copy_v3_fl3(v2, 0.0f, 0.0f, 2.0f); + studiolight_calculate_directional_diffuse_light(ibuf, sl->diffuse_light[STUDIOLIGHT_X_POS], start, v1, v2, steps); + copy_v3_fl3(start, -1.0f, 1.0f, -1.0f); + studiolight_calculate_directional_diffuse_light(ibuf, sl->diffuse_light[STUDIOLIGHT_X_NEG], start, v1, v2, steps); + + copy_v3_fl3(start, -1.0f, -1.0f, -1.0f); + copy_v3_fl3(v1, 2.0f, 0.0f, 0.0f); + copy_v3_fl3(v2, 0.0f, 2.0f, 0.0f); + studiolight_calculate_directional_diffuse_light(ibuf, sl->diffuse_light[STUDIOLIGHT_Y_NEG], start, v1, v2, steps); + copy_v3_fl3(start, -1.0f, -1.0f, 1.0f); + studiolight_calculate_directional_diffuse_light(ibuf, sl->diffuse_light[STUDIOLIGHT_Y_POS], start, v1, v2, steps); + + IMB_freeImBuf(ibuf); + } + } + sl->flag |= STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED; +} + + +/* API */ +void BKE_studiolight_init(void) +{ + StudioLight *sl; + /* go over the preset folder and add a studiolight for every image with its path */ + /* order studio lights by name */ + /* Also reserve icon space for it. */ + /* Add default studio light */ + sl = studiolight_create(); + BLI_strncpy(sl->name, "INTERNAL_01\0", FILE_MAXFILE); + sl->flag = STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED; + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_POS], 0.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_NEG], 0.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_POS], 0.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_NEG], 0.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_POS], 1.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_NEG], 0.0f); + BLI_addtail(&studiolights, sl); + + struct direntry *dir; + const char *folder = BKE_appdir_folder_id(BLENDER_DATAFILES, STUDIO_LIGHT_FOLDER); + unsigned int totfile = BLI_filelist_dir_contents(folder, &dir); + int i; + for (i = 0; i < totfile; i++) { + if ((dir[i].type & S_IFREG)) { + const char *filename = dir[i].relname; + const char *path = dir[i].path; + if (BLI_testextensie(filename, ".jpg")) { + sl = studiolight_create(); + sl->flag = STUDIOLIGHT_EXTERNAL_FILE; + BLI_strncpy(sl->name, filename, FILE_MAXFILE); + BLI_strncpy(sl->path, path, FILE_MAXFILE); + BLI_addtail(&studiolights, sl); + } + } + } + BLI_filelist_free(dir, totfile); + dir = NULL; +} + +void BKE_studiolight_free(void) +{ + struct StudioLight *sl; + while((sl = (StudioLight*)BLI_pophead(&studiolights))) + { + studiolight_free(sl); + } +} + +struct StudioLight *BKE_studiolight_find(const char* name) +{ + LISTBASE_FOREACH(StudioLight *, sl, &studiolights) { + if (STREQLEN(sl->name, name, FILE_MAXFILE)) { + return sl; + } + } + /* When not found, use the default studio light */ + return (StudioLight*)studiolights.first; +} + +struct StudioLight *BKE_studiolight_findindex(int index) +{ + LISTBASE_FOREACH(StudioLight *, sl, &studiolights) { + if (sl->index == index) { + return sl; + } + } + /* When not found, use the default studio light */ + return (StudioLight*)studiolights.first; +} + +const struct ListBase *BKE_studiolight_listbase(void) +{ + return &studiolights; +} + +unsigned int *BKE_studiolight_preview(StudioLight *sl, int icon_size) +{ + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED); + + uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__); + int icon_center = icon_size / 2; + float sphere_radius = icon_center * 0.9; + + int offset = 0; + for (int y = 0; y < icon_size; y++) { + float dy = y - icon_center; + for (int x = 0; x < icon_size; x++) { + float dx = x - icon_center; + /* calculate aliasing */ + float alias = 0; + const float alias_step = 0.333; + for (float ay = dy - 0.5; ay < dy + 0.5; ay += alias_step) { + for (float ax = dx - 0.5; ax < dx + 0.5; ax += alias_step) { + if (sqrt(ay * ay + ax * ax) < sphere_radius) { + alias += alias_step * alias_step; + } + } + } + uint pixelresult = 0x0; + uint alias_i = clamp_i(alias * 256, 0, 255); + if (alias_i != 0) { + /* calculate normal */ + uint alias_mask = alias_i << 24; + float normal[3]; + normal[0] = dx / sphere_radius; + normal[1] = dy / sphere_radius; + normal[2] = sqrt(-(normal[0] * normal[0]) - (normal[1] * normal[1]) + 1); + normalize_v3(normal); + + float color[3]; + mul_v3_v3fl(color, sl->diffuse_light[STUDIOLIGHT_X_POS], clamp_f(normal[0], 0.0, 1.0)); + interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_X_NEG], clamp_f(-normal[0], 0.0, 1.0)); + interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_Y_POS], clamp_f(normal[1], 0.0, 1.0)); + interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_Y_NEG], clamp_f(-normal[1], 0.0, 1.0)); + interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_Z_POS], clamp_f(normal[2], 0.0, 1.0)); + + pixelresult = rgb_to_cpack( + linearrgb_to_srgb(color[0]), + linearrgb_to_srgb(color[1]), + linearrgb_to_srgb(color[2])) | alias_mask; + } + rect[offset++] = pixelresult; + } + } + return rect; +} + +void BKE_studiolight_ensure_flag(StudioLight *sl, int flag) +{ + if (sl->flag & flag){ + return; + } + + if ((flag & STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED)) { + studiolight_calculate_diffuse_light(sl); + } +} diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index a1a2a36e75a..524a94e5886 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -135,5 +135,4 @@ void DRW_opengl_context_disable(void); void DRW_deferred_shader_remove(struct GPUMaterial *mat); -uint *WORKBENCH_generate_studiolight_preview(int studiolight_id, int icon_size); #endif /* __DRW_ENGINE_H__ */ diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 0fee42619c3..680ac264233 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -338,6 +338,7 @@ void workbench_materials_cache_init(WORKBENCH_Data *vedata) if (v3d) { wpd->shading = v3d->shading; wpd->drawtype = v3d->drawtype; + wpd->studio_light = BKE_studiolight_find(wpd->shading.studio_light); } else { /* XXX: We should get the default shading from the view layer, after we implemented the render callback */ @@ -346,7 +347,9 @@ void workbench_materials_cache_init(WORKBENCH_Data *vedata) wpd->shading.shadow_intensity = 0.5; copy_v3_fl(wpd->shading.single_color, 0.8f); wpd->drawtype = OB_SOLID; + wpd->studio_light = BKE_studiolight_findindex(0); } + BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED); select_deferred_shaders(wpd); /* Deferred Mix Pass */ @@ -360,7 +363,7 @@ void workbench_materials_cache_init(WORKBENCH_Data *vedata) srgb_to_linearrgb_v3_v3(wd->background_color_high, wd->background_color_high); srgb_to_linearrgb_v3_v3(wd->background_color_low, wd->background_color_low); - studiolight_update_world(wpd->shading.studio_light, wd); + studiolight_update_world(wpd->studio_light, wd); wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), NULL); DRW_uniformbuffer_update(wpd->world_ubo, &wpd->world_data); diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 7a646d056b5..dde62302f62 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -27,6 +27,8 @@ #define __WORKBENCH_PRIVATE_H__ +#include "BKE_studiolight.h" + #include "DNA_image_types.h" #include "DNA_view3d_types.h" @@ -81,6 +83,7 @@ typedef struct WORKBENCH_PrivateData { struct GPUShader *prepass_texture_sh; struct GPUShader *composite_sh; View3DShading shading; + StudioLight *studio_light; int drawtype; struct GPUUniformBuffer *world_ubo; struct DRWShadingGroup *shadow_shgrp; @@ -127,6 +130,6 @@ void workbench_materials_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob void workbench_materials_cache_finish(WORKBENCH_Data *vedata); /* workbench_studiolight.c */ -void studiolight_update_world(int studio_light, WORKBENCH_UBO_World *wd); +void studiolight_update_world(StudioLight *sl, WORKBENCH_UBO_World *wd); #endif diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c index 5b1d4432ca7..f7d107ea403 100644 --- a/source/blender/draw/engines/workbench/workbench_studiolight.c +++ b/source/blender/draw/engines/workbench/workbench_studiolight.c @@ -22,118 +22,19 @@ /** \file workbench_studiolight.c * \ingroup draw_engine */ +#include "BKE_studiolight.h" + #include "DRW_engine.h" #include "workbench_private.h" #include "BLI_math.h" - -#define STUDIOLIGHT_X_POS 0 -#define STUDIOLIGHT_X_NEG 1 -#define STUDIOLIGHT_Y_POS 2 -#define STUDIOLIGHT_Y_NEG 3 -#define STUDIOLIGHT_Z_POS 4 -#define STUDIOLIGHT_Z_NEG 5 - -const float studiolights[][6][3] = { - { - {1.0, 0.8, 0.6}, - {1.0, 0.6, 0.6}, - {0.9, 0.9, 1.0}, - {0.05, 0.025, 0.025}, - {0.8, 0.8, 0.75}, - {1.0, 0.95, 0.8}, - }, - { - {0.0, 0.0, 0.0}, - {0.0, 0.0, 0.0}, - {0.0, 0.0, 0.0}, - {0.0, 0.0, 0.0}, - {0.8, 0.8, 1.0}, - {0.0, 0.0, 0.0}, - }, - { - {0.4, 0.3, 0.8}, - {0.4, 0.3, 0.8}, - {0.8, 0.8, 0.2}, - {0.0, 0.0, 0.0}, - {0.4, 0.4, 0.8}, - {0.0, 0.0, 0.0}, - }, - { - {0.2, 0.2, 0.0}, - {0.8, 0.2, 0.0}, - {0.8, 0.2, 0.0}, - {0.2, 0.2, 0.0}, - {0.8, 0.6, 0.4}, - {0.0, 0.0, 0.0}, - }, - { - {0.8, 0.2, 0.0}, - {0.8, 0.2, 0.0}, - {0.8, 0.6, 0.0}, - {0.2, 0.2, 0.0}, - {1.0, 0.5, 0.0}, - {0.0, 0.0, 0.0}, - }, -}; - -void studiolight_update_world(int studio_light, WORKBENCH_UBO_World *wd) +void studiolight_update_world(StudioLight *sl, WORKBENCH_UBO_World *wd) { - copy_v3_v3(wd->diffuse_light_x_pos, studiolights[studio_light][STUDIOLIGHT_X_POS]); - copy_v3_v3(wd->diffuse_light_x_neg, studiolights[studio_light][STUDIOLIGHT_X_NEG]); - copy_v3_v3(wd->diffuse_light_y_pos, studiolights[studio_light][STUDIOLIGHT_Y_POS]); - copy_v3_v3(wd->diffuse_light_y_neg, studiolights[studio_light][STUDIOLIGHT_Y_NEG]); - copy_v3_v3(wd->diffuse_light_z_pos, studiolights[studio_light][STUDIOLIGHT_Z_POS]); - copy_v3_v3(wd->diffuse_light_z_neg, studiolights[studio_light][STUDIOLIGHT_Z_NEG]); -} - -uint *WORKBENCH_generate_studiolight_preview(int studiolight_id, int icon_size) -{ - uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__); - int icon_center = icon_size / 2; - float sphere_radius = icon_center * 0.9; - - int offset = 0; - for (int y = 0; y < icon_size; y++) { - float dy = y - icon_center; - for (int x = 0; x < icon_size; x++) { - float dx = x - icon_center; - /* calculate aliasing */ - float alias = 0; - const float alias_step = 0.2; - for (float ay = dy - 0.5; ay < dy + 0.5; ay += alias_step) { - for (float ax = dx - 0.5; ax < dx + 0.5; ax += alias_step) { - if (sqrt(ay * ay + ax * ax) < sphere_radius) { - alias += alias_step * alias_step; - } - } - } - uint pixelresult = 0x0; - uint alias_i = clamp_i(alias * 256, 0, 255); - if (alias_i != 0) { - /* calculate normal */ - uint alias_mask = alias_i << 24; - float normal[3]; - normal[0] = dx / sphere_radius; - normal[1] = dy / sphere_radius; - normal[2] = sqrt(-(normal[0] * normal[0]) - (normal[1] * normal[1]) + 1); - normalize_v3(normal); - - float color[3]; - mul_v3_v3fl(color, studiolights[studiolight_id][STUDIOLIGHT_X_POS], clamp_f(normal[0], 0.0, 1.0)); - interp_v3_v3v3(color, color, studiolights[studiolight_id][STUDIOLIGHT_X_NEG], clamp_f(-normal[0], 0.0, 1.0)); - interp_v3_v3v3(color, color, studiolights[studiolight_id][STUDIOLIGHT_Y_POS], clamp_f(normal[1], 0.0, 1.0)); - interp_v3_v3v3(color, color, studiolights[studiolight_id][STUDIOLIGHT_Y_NEG], clamp_f(-normal[1], 0.0, 1.0)); - interp_v3_v3v3(color, color, studiolights[studiolight_id][STUDIOLIGHT_Z_POS], clamp_f(normal[2], 0.0, 1.0)); - - pixelresult = rgb_to_cpack( - linearrgb_to_srgb(color[0]), - linearrgb_to_srgb(color[1]), - linearrgb_to_srgb(color[2])) | alias_mask; - } - rect[offset++] = pixelresult; - } - } - return rect; + copy_v3_v3(wd->diffuse_light_x_pos, sl->diffuse_light[STUDIOLIGHT_X_POS]); + copy_v3_v3(wd->diffuse_light_x_neg, sl->diffuse_light[STUDIOLIGHT_X_NEG]); + copy_v3_v3(wd->diffuse_light_y_pos, sl->diffuse_light[STUDIOLIGHT_Y_POS]); + copy_v3_v3(wd->diffuse_light_y_neg, sl->diffuse_light[STUDIOLIGHT_Y_NEG]); + copy_v3_v3(wd->diffuse_light_z_pos, sl->diffuse_light[STUDIOLIGHT_Z_POS]); + copy_v3_v3(wd->diffuse_light_z_neg, sl->diffuse_light[STUDIOLIGHT_Z_NEG]); } diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index b0ee6773e7a..6a9067ef95d 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -1031,10 +1031,3 @@ DEF_VICO(COLORSET_17_VEC) DEF_VICO(COLORSET_18_VEC) DEF_VICO(COLORSET_19_VEC) DEF_VICO(COLORSET_20_VEC) - - /* Studio lighting presets */ -DEF_ICON(STUDIOLIGHT_01) -DEF_ICON(STUDIOLIGHT_02) -DEF_ICON(STUDIOLIGHT_03) -DEF_ICON(STUDIOLIGHT_04) -DEF_ICON(STUDIOLIGHT_05) diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index afd57fdcd05..9f5c2005878 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -58,6 +58,7 @@ #include "BKE_global.h" #include "BKE_icons.h" #include "BKE_appdir.h" +#include "BKE_studiolight.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -493,23 +494,6 @@ static void init_matcap_icons(void) } -static void init_studio_light_icons(void) -{ - /* dynamic allocation now, tucking datatoc pointers in DrawInfo */ -#define INIT_STUDIOLIGHT_ICON(icon_id, studiolight_id) \ - { \ - DrawInfo *di; \ - di = def_internal_icon(NULL, icon_id, 0, 0, 96, ICON_TYPE_BUFFER); \ - di->data.buffer.image->rect = WORKBENCH_generate_studiolight_preview(studiolight_id, 96); \ - } (void)0 - - INIT_STUDIOLIGHT_ICON(ICON_STUDIOLIGHT_01, 0); - INIT_STUDIOLIGHT_ICON(ICON_STUDIOLIGHT_02, 1); - INIT_STUDIOLIGHT_ICON(ICON_STUDIOLIGHT_03, 2); - INIT_STUDIOLIGHT_ICON(ICON_STUDIOLIGHT_04, 3); - INIT_STUDIOLIGHT_ICON(ICON_STUDIOLIGHT_05, 4); - -} static void init_internal_icons(void) { // bTheme *btheme = UI_GetTheme(); @@ -779,8 +763,9 @@ void UI_icons_free_drawinfo(void *drawinfo) /** * #Icon.data_type and #Icon.obj */ -static DrawInfo *icon_create_drawinfo(int icon_data_type) +static DrawInfo *icon_create_drawinfo(Icon *icon) { + int icon_data_type = icon->obj_type; DrawInfo *di = NULL; di = MEM_callocN(sizeof(DrawInfo), "di_icon"); @@ -791,6 +776,16 @@ static DrawInfo *icon_create_drawinfo(int icon_data_type) else if (icon_data_type == ICON_DATA_GEOM) { di->type = ICON_TYPE_GEOM; } + else if (icon_data_type == ICON_DATA_STUDIOLIGHT) { + const int STUDIOLIGHT_SIZE = 96; + StudioLight *sl = icon->obj; + di->type = ICON_TYPE_BUFFER; + IconImage *img = MEM_mallocN(sizeof(IconImage), __func__); + img->w = STUDIOLIGHT_SIZE; + img->h = STUDIOLIGHT_SIZE; + img->rect = BKE_studiolight_preview(sl, STUDIOLIGHT_SIZE); + di->data.buffer.image = img; + } else { BLI_assert(0); } @@ -803,7 +798,7 @@ static DrawInfo *icon_ensure_drawinfo(Icon *icon) if (icon->drawinfo) { return icon->drawinfo; } - DrawInfo *di = icon_create_drawinfo(icon->obj_type); + DrawInfo *di = icon_create_drawinfo(icon); icon->drawinfo = di; icon->drawinfo_free = UI_icons_free_drawinfo; return di; @@ -856,7 +851,6 @@ void UI_icons_init(int first_dyn_id) init_internal_icons(); init_brush_icons(); init_matcap_icons(); - init_studio_light_icons(); #endif } diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index cf078bc203d..8a92ad25c92 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -138,7 +138,8 @@ typedef struct View3DShading { short color_type; short light; - short studio_light; + char pad[2]; + char studio_light[256]; /* FILE_MAXFILE */ float shadow_intensity; float single_color[3]; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 124a0477f4c..d8c3fdd7a64 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -35,6 +35,7 @@ #include "BKE_key.h" #include "BKE_movieclip.h" #include "BKE_node.h" +#include "BKE_studiolight.h" #include "DNA_action_types.h" #include "DNA_key_types.h" @@ -191,6 +192,31 @@ const EnumPropertyItem rna_enum_viewport_lighting_items[] = { {0, NULL, 0, NULL, NULL} }; +static const EnumPropertyItem rna_enum_studio_light_items[] = { + {0, "STUDIOLIGHT_01", 0, "", ""}, + {1, "STUDIOLIGHT_02", 0, "", ""}, + {2, "STUDIOLIGHT_03", 0, "", ""}, + {3, "STUDIOLIGHT_04", 0, "", ""}, + {4, "STUDIOLIGHT_05", 0, "", ""}, + {5, "STUDIOLIGHT_06", 0, "", ""}, + {6, "STUDIOLIGHT_07", 0, "", ""}, + {7, "STUDIOLIGHT_08", 0, "", ""}, + {8, "STUDIOLIGHT_09", 0, "", ""}, + {9, "STUDIOLIGHT_10", 0, "", ""}, + {10, "STUDIOLIGHT_11", 0, "", ""}, + {11, "STUDIOLIGHT_12", 0, "", ""}, + {12, "STUDIOLIGHT_13", 0, "", ""}, + {13, "STUDIOLIGHT_14", 0, "", ""}, + {14, "STUDIOLIGHT_15", 0, "", ""}, + {15, "STUDIOLIGHT_16", 0, "", ""}, + {16, "STUDIOLIGHT_17", 0, "", ""}, + {17, "STUDIOLIGHT_18", 0, "", ""}, + {18, "STUDIOLIGHT_19", 0, "", ""}, + {19, "STUDIOLIGHT_20", 0, "", ""}, + {0, NULL, 0, NULL, NULL} +}; +#define NUM_STUDIO_LIGHT_ITEMS 20 + const EnumPropertyItem rna_enum_clip_editor_mode_items[] = { {SC_MODE_TRACKING, "TRACKING", ICON_ANIM_DATA, "Tracking", "Show tracking and solving tools"}, {SC_MODE_MASKEDIT, "MASK", ICON_MOD_MASK, "Mask", "Show mask editing tools"}, @@ -705,6 +731,42 @@ static const EnumPropertyItem *rna_3DViewShading_type_itemf( return item; } +static int rna_View3DShading_studio_light_get(PointerRNA *ptr) +{ + /* XXX: should be stored as string */ + View3D *v3d = (View3D *)ptr->data; + StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light); + return sl->index; +} + +static void rna_View3DShading_studio_light_set(PointerRNA *ptr, int value) +{ + /* XXX: should be stored as string */ + View3D *v3d = (View3D *)ptr->data; + StudioLight *sl = BKE_studiolight_findindex(value); + BLI_strncpy(v3d->shading.studio_light, sl->name, FILE_MAXFILE); +} + +static const EnumPropertyItem *rna_View3DShading_studio_light_itemf( + bContext *UNUSED(C), PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), bool *r_free) +{ + EnumPropertyItem *item = NULL; + int totitem = 0; + + /* XXX: add studio lights */ + LISTBASE_FOREACH(StudioLight*, sl, BKE_studiolight_listbase()) { + if (totitem < NUM_STUDIO_LIGHT_ITEMS) { + RNA_enum_items_add_value(&item, &totitem, rna_enum_studio_light_items, totitem); + item[totitem-1].icon = sl->icon_id; + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + return item; +} + static const EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf( bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *UNUSED(r_free)) @@ -2156,14 +2218,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) {V3D_SHADING_RANDOM_COLOR, "RANDOM", 0, "Random", "Show random object color"}, {0, NULL, 0, NULL, NULL} }; - static const EnumPropertyItem studio_lighting_items[] = { - {0, "01", ICON_STUDIOLIGHT_01, "", ""}, - {1, "02", ICON_STUDIOLIGHT_02, "", ""}, - {2, "03", ICON_STUDIOLIGHT_03, "", ""}, - {3, "04", ICON_STUDIOLIGHT_04, "", ""}, - {4, "05", ICON_STUDIOLIGHT_05, "", ""}, - {0, NULL, 0, NULL, NULL} - }; srna = RNA_def_struct(brna, "View3DShading", NULL); RNA_def_struct_sdna(srna, "View3D"); @@ -2192,8 +2246,9 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "studio_light", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "shading.studio_light"); - RNA_def_property_enum_items(prop, studio_lighting_items); + RNA_def_property_enum_items(prop, rna_enum_studio_light_items); + RNA_def_property_enum_default(prop, 0); + RNA_def_property_enum_funcs(prop, "rna_View3DShading_studio_light_get", "rna_View3DShading_studio_light_set", "rna_View3DShading_studio_light_itemf"); RNA_def_property_ui_text(prop, "Studiolight", "Studio lighting setup"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 5813fc95e13..1dd2185b982 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -75,6 +75,7 @@ #include "BKE_addon.h" #include "BKE_appdir.h" #include "BKE_sequencer.h" /* free seq clipboard */ +#include "BKE_studiolight.h" #include "BKE_material.h" /* clear_matcopybuf */ #include "BKE_tracking.h" /* free tracking clipboard */ #include "BKE_mask.h" /* free mask clipboard */ @@ -250,6 +251,7 @@ void WM_init(bContext *C, int argc, const char **argv) WM_init_opengl(); UI_init(); + BKE_studiolight_init(); } else { /* Note: Currently only inits icons, which we now want in background mode too @@ -259,7 +261,6 @@ void WM_init(bContext *C, int argc, const char **argv) BKE_icons_init(1); } - ED_spacemacros_init(); /* note: there is a bug where python needs initializing before loading the @@ -513,6 +514,7 @@ void WM_exit_ext(bContext *C, const bool do_python) GPU_pass_cache_free(); DRW_opengl_context_destroy(); } + BKE_studiolight_free(); #ifdef WITH_INTERNATIONAL BLF_free_unifont(); diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 585a2f58204..8240b27f2cf 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -413,6 +413,7 @@ install( DESTINATION ${TARGETDIR_VER}/datafiles ) + # helpful tip when using make if("${CMAKE_GENERATOR}" MATCHES ".*Makefiles.*") # message after building. @@ -979,6 +980,13 @@ unset(_icon_names) unset(_icon_files) unset(_f) +# ----------------------------------------------------------------------------- +# Studio Lights +install( + DIRECTORY + ${CMAKE_SOURCE_DIR}/release/datafiles/studiolights + DESTINATION ${TARGETDIR_VER}/datafiles +) # ----------------------------------------------------------------------------- # Setup link libs