From 44069cb8a16a16f9382f6c40669318e459cbf41d Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Sun, 1 May 2016 22:56:11 +0200 Subject: [PATCH 4/4] Cycles: Convert textures from arbitrary color spaces to Scene Linear space This commit replaces the very limited option of choosing between "Color", which would apply an inverse sRGB transform to byte textures and no transformation to float textures, and "Non-Color Data", which wouldn't transform anything. The new system allows the user to select any OCIO color space in the texture node, and Cycles will properly convert it into Scene Linear space. For backwards compatibility, a "Default" option is also offered, which chooses between the default_byte and default_float OCIO role, just like "Color" did before. The obvious way to implement that is to convert textures while loading, but that would either waste precision when converting from a narrower to a wider color space or require a higher bit depth and therefore more memory. So, instead of converting while loading, the texture is converted at render time. On the CPU that could be implemented via OCIO, but not on GPUs. So, instead of directly using OCIO, the transformation is modeled as a 1D transfer function followed by a matrix multiplication, both of which are determined via OCIO before the rendering starts. Although OCIO allows to create transformations that can't be described with this model, the common texture color spaces like sRGB, AdobeRGB, PhotoPro, DCI-P3, ACEScg or Rec.2020 can all be accurately modeled with it. To avoid a potential slowdown, the most common case of sRGB Texture -> Linear sRGB Scene Space is directly implemented in the kernel and detected by the ImageManager. --- intern/cycles/blender/blender_mesh.cpp | 8 +- intern/cycles/blender/blender_session.cpp | 10 ++ intern/cycles/blender/blender_session.h | 1 + intern/cycles/blender/blender_shader.cpp | 12 +- intern/cycles/kernel/kernel_globals.h | 8 ++ intern/cycles/kernel/kernel_types.h | 5 +- intern/cycles/kernel/svm/svm_image.h | 48 +++---- intern/cycles/render/image.cpp | 140 ++++++++++++++++----- intern/cycles/render/image.h | 31 ++++- intern/cycles/render/mesh.cpp | 1 + intern/cycles/render/nodes.cpp | 74 ++++------- intern/cycles/render/nodes.h | 14 +-- intern/cycles/render/scene.cpp | 4 +- intern/cycles/util/util_math.h | 10 ++ intern/cycles/util/util_transform.h | 8 ++ source/blender/blenloader/intern/versioning_270.c | 31 +++++ source/blender/editors/include/UI_interface.h | 2 +- .../editors/interface/interface_templates.c | 4 +- source/blender/editors/space_clip/clip_buttons.c | 2 +- source/blender/editors/space_image/image_buttons.c | 2 +- source/blender/editors/space_node/drawnode.c | 8 +- source/blender/makesdna/DNA_color_types.h | 6 + source/blender/makesdna/DNA_node_types.h | 6 +- source/blender/makesrna/intern/rna_color.c | 67 ++++++++++ source/blender/makesrna/intern/rna_nodetree.c | 31 ++--- source/blender/makesrna/intern/rna_ui_api.c | 1 + .../shader/nodes/node_shader_tex_environment.c | 6 +- .../nodes/shader/nodes/node_shader_tex_image.c | 10 +- source/blenderplayer/bad_level_call_stubs/stubs.c | 2 +- 29 files changed, 383 insertions(+), 169 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 3fc0a91..434af3c 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -296,8 +296,9 @@ static void create_mesh_volume_attribute(BL::Object& b_ob, Attribute *attr = mesh->attributes.add(std); VoxelAttribute *volume_data = attr->data_voxel(); - bool is_float, is_linear; + bool is_float; bool animated = false; + int colorspace; volume_data->manager = image_manager; volume_data->slot = image_manager->add_image( @@ -306,10 +307,11 @@ static void create_mesh_volume_attribute(BL::Object& b_ob, animated, frame, is_float, - is_linear, + 0, INTERPOLATION_LINEAR, EXTENSION_CLIP, - true); + true, + colorspace); } static void create_mesh_volume_attributes(Scene *scene, diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 7a5243d..c99ff7d 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -127,6 +127,9 @@ void BlenderSession::create_session() scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5, _6, _7); scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2, _3); scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2, _3); + scene->image_manager->color_to_scene_linear_cb = function_bind(&BlenderSession::color_to_scene_linear, this, _1, _2); + scene->image_manager->default_byte_colorspace = b_engine.default_colorspace(false); + scene->image_manager->default_float_colorspace = b_engine.default_colorspace(true); /* create session */ session = new Session(session_params); @@ -1332,6 +1335,13 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void return false; } +float3 BlenderSession::color_to_scene_linear(int colorspace, float3 color) +{ + float c[3] = {color.x, color.y, color.z}; + b_engine.color_to_scene_linear(colorspace, c); + return make_float3(c[0], c[1], c[2]); +} + void BlenderSession::update_resumable_tile_manager(int num_samples) { const int num_resumable_chunks = BlenderSession::num_resumable_chunks, diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index 66a6945..4e16122 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -148,6 +148,7 @@ protected: void builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels); bool builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels); bool builtin_image_float_pixels(const string &builtin_name, void *builtin_data, float *pixels); + float3 color_to_scene_linear(int colorspace, float3 color); /* Update tile manager to reflect resumable render settings. */ void update_resumable_tile_manager(int num_samples); diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 3f919bc..7f688c1 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -701,7 +701,11 @@ static ShaderNode *add_node(Scene *scene, get_image_extension(b_image_node)); } } - image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()]; + image->colorspace = b_image_node.colorspace_settings().name(); + if(image->colorspace == BL::ColorManagedTextureColorspaceSettings::name_DEFAULT) { + /* Auto-detect the colorspace. */ + image->colorspace = -1; + } image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()]; image->interpolation = get_image_interpolation(b_image_node); image->extension = get_image_extension(b_image_node); @@ -747,7 +751,11 @@ static ShaderNode *add_node(Scene *scene, EXTENSION_REPEAT); } } - env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()]; + env->colorspace = b_env_node.colorspace_settings().name(); + if(env->colorspace == BL::ColorManagedTextureColorspaceSettings::name_DEFAULT) { + /* Auto-detect the colorspace. */ + env->colorspace = -1; + } env->interpolation = get_image_interpolation(b_env_node); env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()]; BL::TexMapping b_texture_mapping(b_env_node.texture_mapping()); diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h index 52e718f..4c36b25 100644 --- a/intern/cycles/kernel/kernel_globals.h +++ b/intern/cycles/kernel/kernel_globals.h @@ -129,5 +129,13 @@ ccl_device float lookup_table_read_2D(KernelGlobals *kg, float x, float y, int o return (1.0f - t)*data0 + t*data1; } +ccl_device float4 lookup_table_read_float4(KernelGlobals *kg, int offset) +{ + return make_float4(kernel_tex_fetch(__lookup_table, offset), + kernel_tex_fetch(__lookup_table, offset+1), + kernel_tex_fetch(__lookup_table, offset+2), + kernel_tex_fetch(__lookup_table, offset+3)); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index a7ba171..7d714cf 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -40,6 +40,8 @@ CCL_NAMESPACE_BEGIN #define FILTER_TABLE_SIZE 1024 #define RAMP_TABLE_SIZE 256 #define SHUTTER_TABLE_SIZE 256 +#define COLORSPACE_TABLE_SIZE 256 +#define NUM_COLORSPACES 254 #define PARTICLE_SIZE 5 #define TIME_INVALID FLT_MAX @@ -1143,7 +1145,8 @@ typedef struct KernelCurves { typedef struct KernelTables { int beckmann_offset; - int pad1, pad2, pad3; + int colorspace_offset; + int pad1, pad2; } KernelTables; typedef struct KernelData { diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h index 07ab2f2..5b1fd7e 100644 --- a/intern/cycles/kernel/svm/svm_image.h +++ b/intern/cycles/kernel/svm/svm_image.h @@ -57,7 +57,7 @@ ccl_device_inline float svm_image_texture_frac(float x, int *ix) return x - (float)i; } -ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb, uint use_alpha) +ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint colorspace, uint use_alpha) { uint4 info = kernel_tex_fetch(__tex_image_packed_info, id); uint width = info.x; @@ -122,18 +122,12 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, } } - if(srgb) { - r.x = color_srgb_to_scene_linear(r.x); - r.y = color_srgb_to_scene_linear(r.y); - r.z = color_srgb_to_scene_linear(r.z); - } - - return r; + return color_to_scene_linear(kg, colorspace, r); } #else -ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb, uint use_alpha) +ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint colorspace, uint use_alpha) { #ifdef __KERNEL_CPU__ # ifdef __KERNEL_SSE2__ @@ -326,11 +320,6 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, r_ssef = min(r_ssef, ssef(1.0f)); r.w = alpha; } - - if(srgb) { - r_ssef = color_srgb_to_scene_linear(r_ssef); - r.w = alpha; - } #else if(use_alpha && r.w != 1.0f && r.w != 0.0f) { float invw = 1.0f/r.w; @@ -344,17 +333,10 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, r.z = min(r.z, 1.0f); } } - - if(srgb) { - r.x = color_srgb_to_scene_linear(r.x); - r.y = color_srgb_to_scene_linear(r.y); - r.z = color_srgb_to_scene_linear(r.z); - } #endif - return r; + return color_to_scene_linear(kg, colorspace, r); } - #endif /* Remap coordnate from 0..1 box to -1..-1 */ @@ -366,9 +348,9 @@ ccl_device_inline float3 texco_remap_square(float3 co) ccl_device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) { uint id = node.y; - uint co_offset, out_offset, alpha_offset, srgb; + uint co_offset, out_offset, alpha_offset, colorspace; - decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &srgb); + decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &colorspace); float3 co = stack_load_float3(stack, co_offset); float2 tex_co; @@ -384,7 +366,7 @@ ccl_device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *sta else { tex_co = make_float2(co.x, co.y); } - float4 f = svm_image_texture(kg, id, tex_co.x, tex_co.y, srgb, use_alpha); + float4 f = svm_image_texture(kg, id, tex_co.x, tex_co.y, colorspace, use_alpha); if(stack_valid(out_offset)) stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z)); @@ -462,8 +444,8 @@ ccl_device void svm_node_tex_image_box(KernelGlobals *kg, ShaderData *sd, float } /* now fetch textures */ - uint co_offset, out_offset, alpha_offset, srgb; - decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &srgb); + uint co_offset, out_offset, alpha_offset, colorspace; + decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &colorspace); float3 co = stack_load_float3(stack, co_offset); uint id = node.y; @@ -472,11 +454,11 @@ ccl_device void svm_node_tex_image_box(KernelGlobals *kg, ShaderData *sd, float uint use_alpha = stack_valid(alpha_offset); if(weight.x > 0.0f) - f += weight.x*svm_image_texture(kg, id, co.y, co.z, srgb, use_alpha); + f += weight.x*svm_image_texture(kg, id, co.y, co.z, colorspace, use_alpha); if(weight.y > 0.0f) - f += weight.y*svm_image_texture(kg, id, co.x, co.z, srgb, use_alpha); + f += weight.y*svm_image_texture(kg, id, co.x, co.z, colorspace, use_alpha); if(weight.z > 0.0f) - f += weight.z*svm_image_texture(kg, id, co.y, co.x, srgb, use_alpha); + f += weight.z*svm_image_texture(kg, id, co.y, co.x, colorspace, use_alpha); if(stack_valid(out_offset)) stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z)); @@ -487,10 +469,10 @@ ccl_device void svm_node_tex_image_box(KernelGlobals *kg, ShaderData *sd, float ccl_device void svm_node_tex_environment(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) { uint id = node.y; - uint co_offset, out_offset, alpha_offset, srgb; + uint co_offset, out_offset, alpha_offset, colorspace; uint projection = node.w; - decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &srgb); + decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &colorspace); float3 co = stack_load_float3(stack, co_offset); float2 uv; @@ -503,7 +485,7 @@ ccl_device void svm_node_tex_environment(KernelGlobals *kg, ShaderData *sd, floa uv = direction_to_mirrorball(co); uint use_alpha = stack_valid(alpha_offset); - float4 f = svm_image_texture(kg, id, uv.x, uv.y, srgb, use_alpha); + float4 f = svm_image_texture(kg, id, uv.x, uv.y, colorspace, use_alpha); if(stack_valid(out_offset)) stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z)); diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index c0cbf0a..e61a437 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -17,6 +17,7 @@ #include "device.h" #include "image.h" #include "scene.h" +#include "tables.h" #include "util_foreach.h" #include "util_image.h" @@ -70,6 +71,8 @@ ImageManager::ImageManager(const DeviceInfo& info) tex_image_byte_start = 0; assert(0); } + + color_space_table = TABLE_OFFSET_INVALID; } ImageManager::~ImageManager() @@ -107,10 +110,9 @@ bool ImageManager::set_animation_frame_update(int frame) return false; } -bool ImageManager::is_float_image(const string& filename, void *builtin_data, bool& is_linear) +bool ImageManager::is_float_image(const string& filename, void *builtin_data) { bool is_float = false; - is_linear = false; if(builtin_data) { if(builtin_image_info_cb) { @@ -118,9 +120,6 @@ bool ImageManager::is_float_image(const string& filename, void *builtin_data, bo builtin_image_info_cb(filename, builtin_data, is_float, width, height, depth, channels); } - if(is_float) - is_linear = true; - return is_float; } @@ -134,33 +133,14 @@ bool ImageManager::is_float_image(const string& filename, void *builtin_data, bo * if any take up more than one byte, we'll need a float texture slot */ if(spec.format.basesize() > 1) { is_float = true; - is_linear = true; } for(size_t channel = 0; channel < spec.channelformats.size(); channel++) { if(spec.channelformats[channel].basesize() > 1) { is_float = true; - is_linear = true; } } - /* basic color space detection, not great but better than nothing - * before we do OpenColorIO integration */ - if(is_float) { - string colorspace = spec.get_string_attribute("oiio:ColorSpace"); - - is_linear = !(colorspace == "sRGB" || - colorspace == "GammaCorrected" || - (colorspace == "" && - (strcmp(in->format_name(), "png") == 0 || - strcmp(in->format_name(), "tiff") == 0 || - strcmp(in->format_name(), "dpx") == 0 || - strcmp(in->format_name(), "jpeg2000") == 0))); - } - else { - is_linear = false; - } - in->close(); } @@ -187,16 +167,21 @@ int ImageManager::add_image(const string& filename, bool animated, float frame, bool& is_float, - bool& is_linear, + int colorspace_index, InterpolationType interpolation, ExtensionType extension, - bool use_alpha) + bool use_alpha, + int &colorspace_slot) { Image *img; size_t slot; /* load image info and find out if we need a float texture */ - is_float = (pack_images)? false: is_float_image(filename, builtin_data, is_linear); + is_float = (pack_images)? false: is_float_image(filename, builtin_data); + + if(colorspace_index == -1) { + colorspace_index = is_float? default_float_colorspace: default_byte_colorspace; + } if(is_float) { /* find existing image */ @@ -249,6 +234,7 @@ int ImageManager::add_image(const string& filename, img->extension = extension; img->users = 1; img->use_alpha = use_alpha; + img->colorspace = colorspace_index; float_images[slot] = img; } @@ -302,12 +288,27 @@ int ImageManager::add_image(const string& filename, img->extension = extension; img->users = 1; img->use_alpha = use_alpha; + img->colorspace = colorspace_index; images[slot] = img; slot += tex_image_byte_start; } + if(colorspace_slots.find(colorspace_index) == colorspace_slots.end()) { + /* We haven't assigned a slot to this colorspace yet, so do it now. */ + ColorSpace colorspace; + colorspace.index = colorspace_index; + create_colorspace(&colorspace); + /* Some hardcoded colorspaces don't need to be stored explicitly, but are just assigned a special slot. */ + if(colorspace.slot == -1) { + colorspace.slot = color_spaces.size(); + color_spaces.push_back(colorspace); + } + colorspace_slots[colorspace_index] = colorspace.slot; + } + colorspace_slot = colorspace_slots[colorspace_index]; + need_update = true; return slot; @@ -834,7 +835,7 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, int sl } } -void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress& progress) +void ImageManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) { if(!need_update) return; @@ -872,6 +873,32 @@ void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress& if(pack_images) device_pack_images(device, dscene, progress); + if(color_space_table != TABLE_OFFSET_INVALID) { + scene->lookup_tables->remove_table(color_space_table); + } + if(color_spaces.size() > 0) { + vector packed_colorspaces; + for(size_t slot = 0; slot < color_spaces.size(); slot++) { + ColorSpace &colorspace = color_spaces[slot]; + assert(colorspace.transfer != NULL); + for(int i = 0; i < 4; i++) { + packed_colorspaces.push_back(colorspace.matrix[i].x); + packed_colorspaces.push_back(colorspace.matrix[i].y); + packed_colorspaces.push_back(colorspace.matrix[i].z); + packed_colorspaces.push_back(colorspace.matrix[i].w); + } + for(int i = 0; i < COLORSPACE_TABLE_SIZE; i++) { + packed_colorspaces.push_back(colorspace.transfer[i]); + } + } + color_space_table = scene->lookup_tables->add_table(dscene, packed_colorspaces); + } + else { + color_space_table = TABLE_OFFSET_INVALID; + } + KernelTables *ktables = &dscene->data.tables; + ktables->colorspace_offset = color_space_table; + need_update = false; } @@ -968,7 +995,7 @@ void ImageManager::device_free_builtin(Device *device, DeviceScene *dscene) device_free_image(device, dscene, slot); } -void ImageManager::device_free(Device *device, DeviceScene *dscene) +void ImageManager::device_free(Device *device, DeviceScene *dscene, Scene *scene) { for(size_t slot = 0; slot < images.size(); slot++) device_free_image(device, dscene, slot + tex_image_byte_start); @@ -981,9 +1008,64 @@ void ImageManager::device_free(Device *device, DeviceScene *dscene) dscene->tex_image_packed.clear(); dscene->tex_image_packed_info.clear(); + if(color_space_table != TABLE_OFFSET_INVALID) { + scene->lookup_tables->remove_table(color_space_table); + color_space_table = TABLE_OFFSET_INVALID; + } + images.clear(); float_images.clear(); } +void ImageManager::create_colorspace(ColorSpace *colorspace) +{ + colorspace->slot = -1; + + if(colorspace->index == 0) { + colorspace->transfer = NULL; + colorspace->slot = NUM_COLORSPACES; + return; + } + + float3 r_lin = color_to_scene_linear_cb(colorspace->index, make_float3(1.0f, 0.0f, 0.0f)); + float3 g_lin = color_to_scene_linear_cb(colorspace->index, make_float3(0.0f, 1.0f, 0.0f)); + float3 b_lin = color_to_scene_linear_cb(colorspace->index, make_float3(0.0f, 0.0f, 1.0f)); + + colorspace->matrix.x = make_float4(r_lin.x, r_lin.y, r_lin.z, 0.0f); + colorspace->matrix.y = make_float4(g_lin.x, g_lin.y, g_lin.z, 0.0f); + colorspace->matrix.z = make_float4(b_lin.x, b_lin.y, b_lin.z, 0.0f); + colorspace->matrix.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f); + + Transform inv = transform_inverse(colorspace->matrix); + colorspace->transfer = new float[COLORSPACE_TABLE_SIZE]; + + bool is_noop = true, is_srgb = true; + if(!transform_is_identity(colorspace->matrix)) { + /* There's a transformation matrix involved, so we have to run the full transform. + * TODO(lukas): Optimize for linear colorspaces that need a matrix transform, but no transfer curve. */ + is_noop = false; + is_srgb = false; + } + + for(int i = 0; i < COLORSPACE_TABLE_SIZE; i++) { + float x = ((float) i) / (COLORSPACE_TABLE_SIZE - 1); + float tf = average(transform_point(&inv, color_to_scene_linear_cb(colorspace->index, make_float3(x, x, x)))); + colorspace->transfer[i] = tf; + if(fabsf(tf - x) > 1e-6f) { + is_noop = false; + } + if(fabsf(tf - color_srgb_to_linear(x)) > 1e-6f) { + is_srgb = false; + } + } + + if(is_noop || is_srgb) { + /* This colorspace is one of the optimized cases, so we don't need the transfer curve and just set a fixed index to flag it. */ + delete[] colorspace->transfer; + colorspace->transfer = NULL; + colorspace->slot = is_noop? NUM_COLORSPACES: NUM_COLORSPACES+1; + } +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 64798d7..4283b20 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -20,14 +20,17 @@ #include "device.h" #include "device_memory.h" +#include "util_map.h" #include "util_string.h" #include "util_thread.h" +#include "util_transform.h" #include "util_vector.h" CCL_NAMESPACE_BEGIN class Device; class DeviceScene; +class Scene; class Progress; class ImageManager { @@ -40,10 +43,11 @@ public: bool animated, float frame, bool& is_float, - bool& is_linear, + int colorspace, InterpolationType interpolation, ExtensionType extension, - bool use_alpha); + bool use_alpha, + int &colorspace_slot); void remove_image(int slot); void remove_image(const string& filename, void *builtin_data, @@ -53,11 +57,11 @@ public: void *builtin_data, InterpolationType interpolation, ExtensionType extension); - bool is_float_image(const string& filename, void *builtin_data, bool& is_linear); + bool is_float_image(const string& filename, void *builtin_data); - void device_update(Device *device, DeviceScene *dscene, Progress& progress); + void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); void device_update_slot(Device *device, DeviceScene *dscene, int slot, Progress *progress); - void device_free(Device *device, DeviceScene *dscene); + void device_free(Device *device, DeviceScene *dscene, Scene *scene); void device_free_builtin(Device *device, DeviceScene *dscene); void set_osl_texture_system(void *texture_system); @@ -69,11 +73,13 @@ public: function builtin_image_info_cb; function builtin_image_pixels_cb; function builtin_image_float_pixels_cb; + function color_to_scene_linear_cb; struct Image { string filename; void *builtin_data; + string colorspace; bool use_alpha; bool need_load; bool animated; @@ -84,6 +90,15 @@ public: int users; }; + struct ColorSpace { + int index; + float *transfer; + Transform matrix; + int slot; + }; + + int default_float_colorspace, default_byte_colorspace; + private: int tex_num_byte_images; int tex_num_float_images; @@ -93,9 +108,15 @@ private: vector images; vector float_images; + vector color_spaces; + map colorspace_slots; + size_t color_space_table; + void *osl_texture_system; bool pack_images; + void create_colorspace(ColorSpace *colorspace); + bool file_load_image(Image *img, device_vector& tex_img); bool file_load_float_image(Image *img, device_vector& tex_img); diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index cc85192..ce8a96d 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -1207,6 +1207,7 @@ void MeshManager::device_update_displacement_images(Device *device, */ image_manager->device_update(device, dscene, + scene, progress); return; } diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index c78f236..d4bf95f 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -162,16 +162,6 @@ void TextureMapping::compile(OSLCompiler &compiler) /* Image Texture */ -static ShaderEnum color_space_init() -{ - ShaderEnum enm; - - enm.insert("None", 0); - enm.insert("Color", 1); - - return enm; -} - static ShaderEnum image_projection_init() { ShaderEnum enm; @@ -199,7 +189,6 @@ static const char* get_osl_interpolation_parameter(InterpolationType interpolati } } -ShaderEnum ImageTextureNode::color_space_enum = color_space_init(); ShaderEnum ImageTextureNode::projection_enum = image_projection_init(); ImageTextureNode::ImageTextureNode() @@ -208,11 +197,9 @@ ImageTextureNode::ImageTextureNode() image_manager = NULL; slot = -1; is_float = -1; - is_linear = false; use_alpha = true; filename = ""; builtin_data = NULL; - color_space = ustring("Color"); projection = ustring("Flat"); interpolation = INTERPOLATION_LINEAR; extension = EXTENSION_REPEAT; @@ -240,7 +227,6 @@ ShaderNode *ImageTextureNode::clone() const node->image_manager = NULL; node->slot = -1; node->is_float = -1; - node->is_linear = false; return node; } @@ -273,10 +259,11 @@ void ImageTextureNode::compile(SVMCompiler& compiler) animated, 0, is_float_bool, - is_linear, + colorspace, interpolation, extension, - use_alpha); + use_alpha, + colorspace_slot); is_float = (int)is_float_bool; } @@ -288,7 +275,6 @@ void ImageTextureNode::compile(SVMCompiler& compiler) if(slot != -1) { compiler.stack_assign(vector_in); - int srgb = (is_linear || color_space != "Color")? 0: 1; int vector_offset = vector_in->stack_offset; if(!tex_mapping.skip()) { @@ -303,7 +289,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler) vector_offset, color_out->stack_offset, alpha_out->stack_offset, - srgb), + colorspace_slot), projection_enum[projection]); } else { @@ -313,7 +299,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler) vector_offset, color_out->stack_offset, alpha_out->stack_offset, - srgb), + colorspace_slot), __float_as_int(projection_blend)); } @@ -342,7 +328,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler) image_manager = compiler.image_manager; if(is_float == -1) { if(builtin_data == NULL) { - is_float = (int)image_manager->is_float_image(filename, NULL, is_linear); + is_float = (int)image_manager->is_float_image(filename, NULL); } else { bool is_float_bool; @@ -351,10 +337,11 @@ void ImageTextureNode::compile(OSLCompiler& compiler) animated, 0, is_float_bool, - is_linear, + colorspace, interpolation, extension, - use_alpha); + use_alpha, + colorspace_slot); is_float = (int)is_float_bool; } } @@ -371,10 +358,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler) */ compiler.parameter("filename", string_printf("@%d", slot).c_str()); } - if(is_linear || color_space != "Color") - compiler.parameter("color_space", "Linear"); - else - compiler.parameter("color_space", "sRGB"); + compiler.parameter("colorspace", colorspace_slot); compiler.parameter("projection", projection); compiler.parameter("projection_blend", projection_blend); compiler.parameter("is_float", is_float); @@ -409,7 +393,6 @@ static ShaderEnum env_projection_init() return enm; } -ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init(); ShaderEnum EnvironmentTextureNode::projection_enum = env_projection_init(); EnvironmentTextureNode::EnvironmentTextureNode() @@ -418,11 +401,9 @@ EnvironmentTextureNode::EnvironmentTextureNode() image_manager = NULL; slot = -1; is_float = -1; - is_linear = false; use_alpha = true; filename = ""; builtin_data = NULL; - color_space = ustring("Color"); interpolation = INTERPOLATION_LINEAR; projection = ustring("Equirectangular"); animated = false; @@ -448,7 +429,6 @@ ShaderNode *EnvironmentTextureNode::clone() const node->image_manager = NULL; node->slot = -1; node->is_float = -1; - node->is_linear = false; return node; } @@ -479,10 +459,11 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler) animated, 0, is_float_bool, - is_linear, + colorspace, interpolation, EXTENSION_REPEAT, - use_alpha); + use_alpha, + colorspace_slot); is_float = (int)is_float_bool; } @@ -494,7 +475,6 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler) if(slot != -1) { compiler.stack_assign(vector_in); - int srgb = (is_linear || color_space != "Color")? 0: 1; int vector_offset = vector_in->stack_offset; if(!tex_mapping.skip()) { @@ -508,7 +488,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler) vector_offset, color_out->stack_offset, alpha_out->stack_offset, - srgb), + colorspace_slot), projection_enum[projection]); if(vector_offset != vector_in->stack_offset) @@ -539,7 +519,7 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler) image_manager = compiler.image_manager; if(is_float == -1) { if(builtin_data == NULL) { - is_float = (int)image_manager->is_float_image(filename, NULL, is_linear); + is_float = (int)image_manager->is_float_image(filename, NULL); } else { bool is_float_bool; @@ -548,10 +528,11 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler) animated, 0, is_float_bool, - is_linear, + colorspace, interpolation, EXTENSION_REPEAT, - use_alpha); + use_alpha, + colorspace_slot); is_float = (int)is_float_bool; } } @@ -563,10 +544,7 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler) compiler.parameter("filename", string_printf("@%d", slot).c_str()); } compiler.parameter("projection", projection); - if(is_linear || color_space != "Color") - compiler.parameter("color_space", "Linear"); - else - compiler.parameter("color_space", "sRGB"); + compiler.parameter("colorspace", colorspace_slot); compiler.parameter("interpolation", get_osl_interpolation_parameter(interpolation)); @@ -1440,13 +1418,14 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign(color_out); if(slot == -1) { - bool is_float, is_linear; + bool is_float; + int colorspace_slot; slot = image_manager->add_image(filename, builtin_data, false, 0, - is_float, is_linear, + is_float, 0, interpolation, EXTENSION_CLIP, - true); + true, colorspace_slot); } if(slot != -1) { @@ -1488,13 +1467,14 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler) if(use_density || use_color) { if(slot == -1) { - bool is_float, is_linear; + bool is_float; + int colorspace_slot; slot = image_manager->add_image(filename, builtin_data, false, 0, - is_float, is_linear, + is_float, 0, interpolation, EXTENSION_CLIP, - true); + true, colorspace_slot); } if(slot != -1) { diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 0b3ab68..0ef2db4 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -110,18 +110,17 @@ public: ImageManager *image_manager; int is_float; - bool is_linear; + int colorspace; + int colorspace_slot; bool use_alpha; string filename; void *builtin_data; - ustring color_space; ustring projection; InterpolationType interpolation; ExtensionType extension; float projection_blend; bool animated; - static ShaderEnum color_space_enum; static ShaderEnum projection_enum; virtual bool equals(const ShaderNode *other) { @@ -130,7 +129,7 @@ public: use_alpha == image_node->use_alpha && filename == image_node->filename && builtin_data == image_node->builtin_data && - color_space == image_node->color_space && + colorspace == image_node->colorspace && projection == image_node->projection && interpolation == image_node->interpolation && extension == image_node->extension && @@ -149,16 +148,15 @@ public: ImageManager *image_manager; int is_float; - bool is_linear; + int colorspace; + int colorspace_slot; bool use_alpha; string filename; void *builtin_data; - ustring color_space; ustring projection; InterpolationType interpolation; bool animated; - static ShaderEnum color_space_enum; static ShaderEnum projection_enum; virtual bool equals(const ShaderNode *other) { @@ -167,7 +165,7 @@ public: use_alpha == env_node->use_alpha && filename == env_node->filename && builtin_data == env_node->builtin_data && - color_space == env_node->color_space && + colorspace == env_node->colorspace && projection == env_node->projection && interpolation == env_node->interpolation && animated == env_node->animated; diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index b0052c3..d60fcd7 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -107,7 +107,7 @@ void Scene::free_memory(bool final) bake_manager->device_free(device, &dscene); if(!params.persistent_data || final) - image_manager->device_free(device, &dscene); + image_manager->device_free(device, &dscene, this); else image_manager->device_free_builtin(device, &dscene); @@ -187,7 +187,7 @@ void Scene::device_update(Device *device_, Progress& progress) if(progress.get_cancel() || device->have_error()) return; progress.set_status("Updating Images"); - image_manager->device_update(device, &dscene, progress); + image_manager->device_update(device, &dscene, this, progress); if(progress.get_cancel() || device->have_error()) return; diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 046ee0a..1c87d1d 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -606,6 +606,16 @@ ccl_device_inline float3 fabs(float3 a) #endif } +ccl_device_inline float4 fabs(float4 a) +{ +#ifdef __KERNEL_SSE__ + __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)); + return _mm_and_ps(a.m128, mask); +#else + return make_float4(fabsf(a.x), fabsf(a.y), fabsf(a.z), fabsf(a.w)); +#endif +} + #endif ccl_device_inline float3 float2_to_float3(const float2 a) diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index f01db64..3c96da5 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -241,6 +241,14 @@ ccl_device_inline Transform transform_identity() return transform_scale(1.0f, 1.0f, 1.0f); } +ccl_device_inline bool transform_is_identity(const Transform& A) +{ + return (average(fabs(A.x - make_float4(1.0f, 0.0f, 0.0f, 0.0f))) < 1e-6f) + && (average(fabs(A.y - make_float4(0.0f, 1.0f, 0.0f, 0.0f))) < 1e-6f) + && (average(fabs(A.z - make_float4(0.0f, 0.0f, 1.0f, 0.0f))) < 1e-6f) + && (average(fabs(A.w - make_float4(0.0f, 0.0f, 0.0f, 1.0f))) < 1e-6f); +} + ccl_device_inline bool operator==(const Transform& A, const Transform& B) { return memcmp(&A, &B, sizeof(Transform)) == 0; diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 54b2582..6cc2ae1 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -73,6 +73,8 @@ #include "MEM_guardedalloc.h" +#include "IMB_colormanagement.h" + static void do_version_constraints_radians_degrees_270_1(ListBase *lb) { bConstraint *con; @@ -1101,4 +1103,33 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } + + { + if (!DNA_struct_elem_find(fd->filesdna, "NodeTexImage", "ColorManagedColorspaceSettings", "colorspace_settings")) { + FOREACH_NODETREE(main, ntree, id) { + bNode *node; + + for (node = ntree->nodes.first; node; node = node->next) { + if (node->type == SH_NODE_TEX_IMAGE) { + NodeTexImage *data = node->storage; + const char* name; + if(data->color_space == SHD_COLORSPACE_COLOR) + name = "Default"; + else + name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_RAW); + BLI_strncpy(data->colorspace_settings.name, name, sizeof(data->colorspace_settings.name)); + } + else if (node->type == SH_NODE_TEX_ENVIRONMENT) { + NodeTexEnvironment *data = node->storage; + const char* name; + if(data->color_space == SHD_COLORSPACE_COLOR) + name = "Default"; + else + name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_RAW); + BLI_strncpy(data->colorspace_settings.name, name, sizeof(data->colorspace_settings.name)); + } + } + } FOREACH_NODETREE_END + } + } } diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9aad340..f01c311 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -958,7 +958,7 @@ void uiTemplateTrack(struct uiLayout *layout, struct PointerRNA *ptr, const char void uiTemplateMarker(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, PointerRNA *userptr, PointerRNA *trackptr, int cmpact); void uiTemplateMovieclipInformation(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr); -void uiTemplateColorspaceSettings(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname); +void uiTemplateColorspaceSettings(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, int drawlabel); void uiTemplateColormanagedViewSettings(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname); /* items */ diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index a47d608..974d621 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -3714,7 +3714,7 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr) /********************************* Color management *************************************/ -void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char *propname) +void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char *propname, int drawlabel) { PropertyRNA *prop; PointerRNA colorspace_settings_ptr; @@ -3729,7 +3729,7 @@ void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char colorspace_settings_ptr = RNA_property_pointer_get(ptr, prop); - uiItemR(layout, &colorspace_settings_ptr, "name", 0, IFACE_("Color Space"), ICON_NONE); + uiItemR(layout, &colorspace_settings_ptr, "name", 0, drawlabel? IFACE_("Color Space"): "", ICON_NONE); } void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr, const char *propname) diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index 0378c68..61c9d17 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -123,7 +123,7 @@ void uiTemplateMovieClip(uiLayout *layout, bContext *C, PointerRNA *ptr, const c uiItemO(row, "", ICON_FILE_REFRESH, "clip.reload"); col = uiLayoutColumn(layout, false); - uiTemplateColorspaceSettings(col, &clipptr, "colorspace_settings"); + uiTemplateColorspaceSettings(col, &clipptr, "colorspace_settings", true); } } diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index a2db682..5eb981b 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -947,7 +947,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char } col = uiLayoutColumn(layout, false); - uiTemplateColorspaceSettings(col, &imaptr, "colorspace_settings"); + uiTemplateColorspaceSettings(col, &imaptr, "colorspace_settings", true); uiItemR(col, &imaptr, "use_view_as_render", 0, NULL, ICON_NONE); if (ima->source != IMA_SRC_GENERATED) { diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index b2f3306..2430413 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -829,7 +829,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA uiLayoutSetContextPointer(layout, "image_user", &iuserptr); uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); - uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); + uiTemplateColorspaceSettings(layout, ptr, "colorspace_settings", false); uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); @@ -861,7 +861,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr); - uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); + uiTemplateColorspaceSettings(layout, ptr, "colorspace_settings", false); uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); } @@ -903,7 +903,7 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P uiTemplateImageInfo(layout, C, ima, iuserptr.data); } - uiItemR(layout, ptr, "color_space", 0, IFACE_("Color Space"), ICON_NONE); + uiTemplateColorspaceSettings(layout, ptr, "colorspace_settings", false); uiItemR(layout, ptr, "interpolation", 0, IFACE_("Interpolation"), ICON_NONE); uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE); } @@ -2032,7 +2032,7 @@ static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, Point clipptr = RNA_pointer_get(ptr, "clip"); - uiTemplateColorspaceSettings(layout, &clipptr, "colorspace_settings"); + uiTemplateColorspaceSettings(layout, &clipptr, "colorspace_settings", true); } static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, PointerRNA *ptr) diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h index c9a5e05..052d6a4 100644 --- a/source/blender/makesdna/DNA_color_types.h +++ b/source/blender/makesdna/DNA_color_types.h @@ -185,4 +185,10 @@ enum { COLORMANAGE_VIEW_USE_CURVES = (1 << 0) }; +enum { + COLORSPACE_NONE = 0, + COLORSPACE_DEFAULT, + COLORSPACE_NUM +}; + #endif diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index c75a019..a847055 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -727,7 +727,8 @@ typedef struct NodeTexSky { typedef struct NodeTexImage { NodeTexBase base; ImageUser iuser; - int color_space; + ColorManagedColorspaceSettings colorspace_settings; + int color_space; /* Deprecated, only needed for backward compatibility */ int projection; float projection_blend; int interpolation; @@ -748,7 +749,8 @@ typedef struct NodeTexBrick { typedef struct NodeTexEnvironment { NodeTexBase base; ImageUser iuser; - int color_space; + ColorManagedColorspaceSettings colorspace_settings; + int color_space; /* Deprecated, only needed for backward compatibility */ int projection; int interpolation; int pad; diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 021bc60..5a46357 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -573,6 +573,49 @@ static EnumPropertyItem *rna_ColorManagedColorspaceSettings_colorspace_itemf( return items; } +static int rna_ColorManagedTextureColorspaceSettings_colorspace_get(struct PointerRNA *ptr) +{ + ColorManagedColorspaceSettings *colorspace = (ColorManagedColorspaceSettings *) ptr->data; + + if(strcmp(colorspace->name, "Default")) + return IMB_colormanagement_colorspace_get_named_index(colorspace->name); + else + return COLORSPACE_DEFAULT; +} + +static void rna_ColorManagedTextureColorspaceSettings_colorspace_set(struct PointerRNA *ptr, int value) +{ + ColorManagedColorspaceSettings *colorspace = (ColorManagedColorspaceSettings *) ptr->data; + + if(value == COLORSPACE_DEFAULT) + BLI_strncpy(colorspace->name, "Default", sizeof(colorspace->name)); + else { + const char *name = IMB_colormanagement_colorspace_get_indexed_name(value); + + if (name && name[0]) { + BLI_strncpy(colorspace->name, name, sizeof(colorspace->name)); + } + } +} + +static EnumPropertyItem *rna_ColorManagedTextureColorspaceSettings_colorspace_itemf( + bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + EnumPropertyItem *items = NULL; + int totitem = 0; + + static EnumPropertyItem default_color_space = + {COLORSPACE_DEFAULT, "DEFAULT", 0, "Default", "Use the default byte or float colorspace depending on the file format"}; + + IMB_colormanagement_colorspace_items_add(&items, &totitem); + RNA_enum_item_add(&items, &totitem, &default_color_space); + RNA_enum_item_end(&items, &totitem); + + *r_free = true; + + return items; +} + static void rna_ColorManagedColorspaceSettings_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { ID *id = ptr->id.data; @@ -655,6 +698,11 @@ static char *rna_ColorManagedInputColorspaceSettings_path(PointerRNA *UNUSED(ptr return BLI_sprintfN("colorspace_settings"); } +static char *rna_ColorManagedTextureColorspaceSettings_path(PointerRNA *UNUSED(ptr)) +{ + return BLI_sprintfN("colorspace_settings"); +} + static void rna_ColorManagement_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { ID *id = ptr->id.data; @@ -1087,6 +1135,12 @@ static void rna_def_colormanage(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem texture_color_space_items[] = { + {0, "NONE", 0, "None", "Do not perform any color transform on load, treat colors as in scene linear space already"}, + {COLORSPACE_DEFAULT, "DEFAULT", 0, "Default", "Use the default byte or float colorspace depending on the file format"}, + {0, NULL, 0, NULL, NULL} + }; + /* ** Display Settings ** */ srna = RNA_def_struct(brna, "ColorManagedDisplaySettings", NULL); RNA_def_struct_path_func(srna, "rna_ColorManagedDisplaySettings_path"); @@ -1160,6 +1214,19 @@ static void rna_def_colormanage(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Input Color Space", "Color space of the image or movie on disk"); RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagedColorspaceSettings_reload_update"); + srna = RNA_def_struct(brna, "ColorManagedTextureColorspaceSettings", NULL); + RNA_def_struct_path_func(srna, "rna_ColorManagedTextureColorspaceSettings_path"); + RNA_def_struct_ui_text(srna, "ColorManagedTextureColorspaceSettings", "Texture color space settings"); + + prop = RNA_def_property(srna, "name", PROP_ENUM, PROP_NONE); + RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT); + RNA_def_property_enum_items(prop, texture_color_space_items); + RNA_def_property_enum_funcs(prop, "rna_ColorManagedTextureColorspaceSettings_colorspace_get", + "rna_ColorManagedTextureColorspaceSettings_colorspace_set", + "rna_ColorManagedTextureColorspaceSettings_colorspace_itemf"); + RNA_def_property_ui_text(prop, "Texture Color Space", "Color space of the texture on disk"); + RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagedColorspaceSettings_reload_update"); + // srna = RNA_def_struct(brna, "ColorManagedSequencerColorspaceSettings", NULL); RNA_def_struct_path_func(srna, "rna_ColorManagedSequencerColorspaceSettings_path"); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index ccbabb2..4fd800a 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -3635,15 +3635,6 @@ static void def_sh_tex_sky(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } -static const EnumPropertyItem sh_tex_prop_color_space_items[] = { - {SHD_COLORSPACE_COLOR, "COLOR", 0, "Color", - "Image contains color data, and will be converted to linear color for rendering"}, - {SHD_COLORSPACE_NONE, "NONE", 0, "Non-Color Data", - "Image contains non-color data, for example a displacement or normal map, " - "and will not be converted"}, - {0, NULL, 0, NULL, NULL} -}; - static const EnumPropertyItem sh_tex_prop_interpolation_items[] = { {SHD_INTERP_LINEAR, "Linear", 0, "Linear", "Linear interpolation"}, @@ -3678,12 +3669,6 @@ static void def_sh_tex_environment(StructRNA *srna) RNA_def_struct_sdna_from(srna, "NodeTexEnvironment", "storage"); def_sh_tex(srna); - prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, sh_tex_prop_color_space_items); - RNA_def_property_enum_default(prop, SHD_COLORSPACE_COLOR); - RNA_def_property_ui_text(prop, "Color Space", "Image file color space"); - RNA_def_property_update(prop, 0, "rna_Node_update"); - prop = RNA_def_property(srna, "projection", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_projection_items); RNA_def_property_ui_text(prop, "Projection", "Projection of the input image"); @@ -3694,6 +3679,11 @@ static void def_sh_tex_environment(StructRNA *srna) RNA_def_property_ui_text(prop, "Interpolation", "Texture interpolation"); RNA_def_property_update(prop, 0, "rna_Node_update"); + prop = RNA_def_property(srna, "colorspace_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "colorspace_settings"); + RNA_def_property_struct_type(prop, "ColorManagedTextureColorspaceSettings"); + RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings"); + prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "iuser"); @@ -3735,12 +3725,6 @@ static void def_sh_tex_image(StructRNA *srna) RNA_def_struct_sdna_from(srna, "NodeTexImage", "storage"); def_sh_tex(srna); - prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, sh_tex_prop_color_space_items); - RNA_def_property_enum_default(prop, SHD_COLORSPACE_COLOR); - RNA_def_property_ui_text(prop, "Color Space", "Image file color space"); - RNA_def_property_update(prop, 0, "rna_Node_update"); - prop = RNA_def_property(srna, "projection", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_projection_items); RNA_def_property_ui_text(prop, "Projection", "Method to project 2D image on object with a 3D texture vector"); @@ -3760,6 +3744,11 @@ static void def_sh_tex_image(StructRNA *srna) RNA_def_property_ui_text(prop, "Extension", "How the image is extrapolated past its original bounds"); RNA_def_property_update(prop, 0, "rna_Node_update"); + prop = RNA_def_property(srna, "colorspace_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "colorspace_settings"); + RNA_def_property_struct_type(prop, "ColorManagedTextureColorspaceSettings"); + RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings"); + prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "iuser"); diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 80777f5..ac1acbb 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -900,6 +900,7 @@ void RNA_api_ui_layout(StructRNA *srna) func = RNA_def_function(srna, "template_colorspace_settings", "uiTemplateColorspaceSettings"); RNA_def_function_ui_description(func, "Item. A widget to control input color space settings."); api_ui_item_rna_common(func); + RNA_def_boolean(func, "draw_label", true, "", "Draw a label with the property name in front of the enum"); func = RNA_def_function(srna, "template_colormanaged_view_settings", "uiTemplateColormanagedViewSettings"); RNA_def_function_ui_description(func, "Item. A widget to control color managed view settings settings."); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c index 292221c..15d6acb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c @@ -44,7 +44,8 @@ static void node_shader_init_tex_environment(bNodeTree *UNUSED(ntree), bNode *no NodeTexEnvironment *tex = MEM_callocN(sizeof(NodeTexEnvironment), "NodeTexEnvironment"); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); - tex->color_space = SHD_COLORSPACE_COLOR; + BKE_color_managed_colorspace_settings_init(&tex->colorspace_settings); + BLI_strncpy(tex->colorspace_settings.name, "Default", sizeof(tex->colorspace_settings.name)); tex->projection = SHD_PROJ_EQUIRECTANGULAR; tex->iuser.frames = 1; tex->iuser.sfra = 1; @@ -59,7 +60,8 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeE Image *ima = (Image *)node->id; ImageUser *iuser = NULL; NodeTexImage *tex = node->storage; - int isdata = tex->color_space == SHD_COLORSPACE_NONE; + /* TODO(lukas): Do proper color space detection here. */ + int isdata = false; if (!ima) return GPU_stack_link(mat, "node_tex_environment_empty", in, out); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c index f0a8cda..d711bfe 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c @@ -45,7 +45,8 @@ static void node_shader_init_tex_image(bNodeTree *UNUSED(ntree), bNode *node) NodeTexImage *tex = MEM_callocN(sizeof(NodeTexImage), "NodeTexImage"); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); - tex->color_space = SHD_COLORSPACE_COLOR; + BKE_color_managed_colorspace_settings_init(&tex->colorspace_settings); + BLI_strncpy(tex->colorspace_settings.name, "Default", sizeof(tex->colorspace_settings.name)); tex->iuser.frames = 1; tex->iuser.sfra = 1; tex->iuser.fie_ima = 2; @@ -59,7 +60,8 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat Image *ima = (Image *)node->id; ImageUser *iuser = NULL; NodeTexImage *tex = node->storage; - int isdata = tex->color_space == SHD_COLORSPACE_NONE; + /* TODO(lukas): Do proper color space detection here. */ + int isdata = false; if (!ima) return GPU_stack_link(mat, "node_tex_image_empty", in, out); @@ -72,8 +74,8 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata)); ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); - if ((tex->color_space == SHD_COLORSPACE_COLOR) && - ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 && + /* TODO(lukas): Do proper color space detection here. */ + if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 && GPU_material_do_color_management(mat)) { GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link); diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 78a6ad2..61ff6cb 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -612,7 +612,7 @@ void uiTemplateMovieclipInformation(struct uiLayout *layout, struct PointerRNA * void uiTemplateTrack(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname) RET_NONE void uiTemplateMarker(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, PointerRNA *userptr, PointerRNA *trackptr, int compact) RET_NONE void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, int color_management) RET_NONE -void uiTemplateColorspaceSettings(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname) RET_NONE +void uiTemplateColorspaceSettings(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, int drawlabel) RET_NONE void uiTemplateColormanagedViewSettings(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname) RET_NONE void uiTemplateComponentMenu(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name) RET_NONE void uiTemplateNodeSocket(struct uiLayout *layout, struct bContext *C, float *color) RET_NONE -- 1.9.1