Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
authorGaia Clary <gaia.clary@machinimatrix.org>2019-05-22 23:35:40 +0300
committerGaia Clary <gaia.clary@machinimatrix.org>2019-05-22 23:35:40 +0300
commit4755c2345854dd97234de2438e00008311537dde (patch)
tree3f7f5a029c50fda39630bdb6ef518f925df01f18 /intern
parent43e6bb85cee0802887eae9489a2bd73836daf41d (diff)
parentb471e48c305b6fdee69a862b50547a59dd368c4d (diff)
Merge branch 'master' into collada
Diffstat (limited to 'intern')
-rw-r--r--intern/cycles/blender/addon/__init__.py10
-rw-r--r--intern/cycles/blender/addon/properties.py55
-rw-r--r--intern/cycles/blender/addon/ui.py149
-rw-r--r--intern/cycles/blender/blender_camera.cpp34
-rw-r--r--intern/cycles/blender/blender_mesh.cpp5
-rw-r--r--intern/cycles/blender/blender_object.cpp6
-rw-r--r--intern/cycles/blender/blender_python.cpp10
-rw-r--r--intern/cycles/blender/blender_session.cpp18
-rw-r--r--intern/cycles/blender/blender_shader.cpp50
-rw-r--r--intern/cycles/blender/blender_util.h16
-rw-r--r--intern/cycles/device/device_cpu.cpp2
-rw-r--r--intern/cycles/kernel/kernel_emission.h5
-rw-r--r--intern/cycles/kernel/kernel_shader.h2
-rw-r--r--intern/cycles/kernel/kernel_types.h2
-rw-r--r--intern/cycles/kernel/osl/osl_globals.h11
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp419
-rw-r--r--intern/cycles/kernel/osl/osl_services.h51
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp1
-rw-r--r--intern/cycles/kernel/shaders/node_environment_texture.osl12
-rw-r--r--intern/cycles/kernel/shaders/node_ies_light.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_image_texture.osl54
-rw-r--r--intern/cycles/kernel/svm/svm_image.h33
-rw-r--r--intern/cycles/kernel/svm/svm_types.h10
-rw-r--r--intern/cycles/render/CMakeLists.txt2
-rw-r--r--intern/cycles/render/colorspace.cpp410
-rw-r--r--intern/cycles/render/colorspace.h68
-rw-r--r--intern/cycles/render/graph.cpp37
-rw-r--r--intern/cycles/render/graph.h9
-rw-r--r--intern/cycles/render/image.cpp179
-rw-r--r--intern/cycles/render/image.h43
-rw-r--r--intern/cycles/render/light.cpp30
-rw-r--r--intern/cycles/render/light.h2
-rw-r--r--intern/cycles/render/nodes.cpp236
-rw-r--r--intern/cycles/render/nodes.h59
-rw-r--r--intern/cycles/render/osl.cpp95
-rw-r--r--intern/cycles/render/osl.h19
-rw-r--r--intern/cycles/render/shader.cpp6
-rw-r--r--intern/cycles/util/util_aligned_malloc.h15
-rw-r--r--intern/cycles/util/util_color.h6
-rw-r--r--intern/cycles/util/util_image.h1
-rw-r--r--intern/cycles/util/util_map.h7
-rw-r--r--intern/cycles/util/util_math.h20
-rw-r--r--intern/cycles/util/util_texture.h12
-rw-r--r--intern/ghost/GHOST_C-api.h13
-rw-r--r--intern/ghost/GHOST_ISystem.h13
-rw-r--r--intern/ghost/GHOST_Rect.h1
-rw-r--r--intern/ghost/GHOST_Types.h5
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp12
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerX11.cpp2
-rw-r--r--intern/ghost/intern/GHOST_DropTargetWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_DropTargetX11.h2
-rw-r--r--intern/ghost/intern/GHOST_EventPrinter.cpp4
-rw-r--r--intern/ghost/intern/GHOST_ImeWin32.cpp4
-rw-r--r--intern/ghost/intern/GHOST_ImeWin32.h8
-rw-r--r--intern/ghost/intern/GHOST_System.cpp10
-rw-r--r--intern/ghost/intern/GHOST_System.h11
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.h7
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm56
-rw-r--r--intern/ghost/intern/GHOST_SystemNULL.h7
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsUnix.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.cpp12
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.h5
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp12
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h6
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp5
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h7
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp2
-rw-r--r--intern/opencolorio/fallback_impl.cc23
-rw-r--r--intern/opencolorio/ocio_capi.cc8
-rw-r--r--intern/opencolorio/ocio_capi.h5
-rw-r--r--intern/opencolorio/ocio_impl.cc83
-rw-r--r--intern/opencolorio/ocio_impl.h12
72 files changed, 1739 insertions, 815 deletions
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index 93a1271b4b4..776a73dabd8 100644
--- a/intern/cycles/blender/addon/__init__.py
+++ b/intern/cycles/blender/addon/__init__.py
@@ -87,16 +87,16 @@ class CyclesRender(bpy.types.RenderEngine):
engine.bake(self, depsgraph, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result)
# viewport render
- def view_update(self, context):
+ def view_update(self, context, depsgraph):
if not self.session:
engine.create(self, context.blend_data,
context.region, context.space_data, context.region_data)
- engine.reset(self, context.blend_data, context.depsgraph)
- engine.sync(self, context.depsgraph, context.blend_data)
+ engine.reset(self, context.blend_data, depsgraph)
+ engine.sync(self, depsgraph, context.blend_data)
- def view_draw(self, context):
- engine.draw(self, context.depsgraph, context.region, context.space_data, context.region_data)
+ def view_draw(self, context, depsgraph):
+ engine.draw(self, depsgraph, context.region, context.space_data, context.region_data)
def update_script_node(self, node):
if engine.with_osl():
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 6da88a769f5..d9e145c8b75 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -68,11 +68,6 @@ enum_filter_types = (
('BLACKMAN_HARRIS', "Blackman-Harris", "Blackman-Harris filter"),
)
-enum_aperture_types = (
- ('RADIUS', "Radius", "Directly change the size of the aperture"),
- ('FSTOP', "F-stop", "Change the size of the aperture by f-stop"),
-)
-
enum_panorama_types = (
('EQUIRECTANGULAR', "Equirectangular", "Render the scene with a spherical camera, also known as Lat Long panorama"),
('FISHEYE_EQUIDISTANT', "Fisheye Equidistant", "Ideal for fulldomes, ignore the sensor dimensions"),
@@ -417,11 +412,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
min=0.0, max=10.0,
default=1.0,
)
- film_transparent: BoolProperty(
- name="Transparent",
- description="World background is transparent, for compositing the render over another background",
- default=False,
- )
film_transparent_glass: BoolProperty(
name="Transparent Glass",
description="Render transmissive surfaces as transparent, for compositing glass over another background",
@@ -747,49 +737,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
class CyclesCameraSettings(bpy.types.PropertyGroup):
- aperture_type: EnumProperty(
- name="Aperture Type",
- description="Use f-stop number or aperture radius",
- items=enum_aperture_types,
- default='RADIUS',
- )
- aperture_fstop: FloatProperty(
- name="Aperture f-stop",
- description="F-stop ratio (lower numbers give more defocus, higher numbers give a sharper image)",
- min=0.0, soft_min=0.1, soft_max=64.0,
- default=5.6,
- step=10,
- precision=1,
- )
- aperture_size: FloatProperty(
- name="Aperture Size",
- description="Radius of the aperture for depth of field (higher values give more defocus)",
- min=0.0, soft_max=10.0,
- default=0.0,
- step=1,
- precision=4,
- subtype='DISTANCE',
- )
- aperture_blades: IntProperty(
- name="Aperture Blades",
- description="Number of blades in aperture for polygonal bokeh (at least 3)",
- min=0, max=100,
- default=0,
- )
- aperture_rotation: FloatProperty(
- name="Aperture Rotation",
- description="Rotation of blades in aperture",
- soft_min=-pi, soft_max=pi,
- subtype='ANGLE',
- default=0,
- )
- aperture_ratio: FloatProperty(
- name="Aperture Ratio",
- description="Distortion to simulate anamorphic lens bokeh",
- min=0.01, soft_min=1.0, soft_max=2.0,
- default=1.0,
- precision=4,
- )
panorama_type: EnumProperty(
name="Panorama Type",
description="Distortion to use for the calculation",
@@ -1490,7 +1437,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
break
if not found_device:
- col = box.column(align=True);
+ col = box.column(align=True)
col.label(text="No compatible GPUs found for path tracing", icon='INFO')
col.label(text="Cycles will render on the CPU", icon='BLANK1')
return
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 0845f567056..a49efb3567f 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -57,7 +57,7 @@ def node_panel(cls):
node_cls.bl_space_type = 'NODE_EDITOR'
node_cls.bl_region_type = 'UI'
- node_cls.bl_category = "Node"
+ node_cls.bl_category = "Options"
if hasattr(node_cls, 'bl_parent_id'):
node_cls.bl_parent_id = 'NODE_' + node_cls.bl_parent_id
@@ -528,31 +528,32 @@ class CYCLES_RENDER_PT_film(CyclesButtonsPanel, Panel):
class CYCLES_RENDER_PT_film_transparency(CyclesButtonsPanel, Panel):
- bl_label = "Transparency"
+ bl_label = "Transparent"
bl_parent_id = "CYCLES_RENDER_PT_film"
def draw_header(self, context):
layout = self.layout
scene = context.scene
- cscene = scene.cycles
+ rd = scene.render
- layout.prop(cscene, "film_transparent", text="")
+ layout.prop(rd, "film_transparent", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
scene = context.scene
+ rd = scene.render
cscene = scene.cycles
- layout.active = cscene.film_transparent
+ layout.active = rd.film_transparent
col = layout.column()
col.prop(cscene, "film_transparent_glass", text="Transparent Glass")
sub = col.column()
- sub.active = cscene.film_transparent and cscene.film_transparent_glass
+ sub.active = rd.film_transparent and cscene.film_transparent_glass
sub.prop(cscene, "film_transparent_roughness", text="Roughness Threshold")
@@ -1015,20 +1016,27 @@ class CYCLES_CAMERA_PT_dof(CyclesButtonsPanel, Panel):
def poll(cls, context):
return context.camera and CyclesButtonsPanel.poll(context)
+ def draw_header(self, context):
+ cam = context.camera
+ dof = cam.dof
+ self.layout.prop(dof, "use_dof", text="")
+
def draw(self, context):
layout = self.layout
layout.use_property_split = True
cam = context.camera
+ dof = cam.dof
+ layout.active = dof.use_dof
split = layout.split()
col = split.column()
- col.prop(cam, "dof_object", text="Focus Object")
+ col.prop(dof, "focus_object", text="Focus Object")
sub = col.row()
- sub.active = cam.dof_object is None
- sub.prop(cam, "dof_distance", text="Distance")
+ sub.active = dof.focus_object is None
+ sub.prop(dof, "focus_distance", text="Distance")
class CYCLES_CAMERA_PT_dof_aperture(CyclesButtonsPanel, Panel):
@@ -1042,44 +1050,17 @@ class CYCLES_CAMERA_PT_dof_aperture(CyclesButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
cam = context.camera
- ccam = cam.cycles
-
- col = flow.column()
- col.prop(ccam, "aperture_type")
- if ccam.aperture_type == 'RADIUS':
- col.prop(ccam, "aperture_size", text="Size")
- elif ccam.aperture_type == 'FSTOP':
- col.prop(ccam, "aperture_fstop", text="Number")
- col.separator()
-
- col = flow.column()
- col.prop(ccam, "aperture_blades", text="Blades")
- col.prop(ccam, "aperture_rotation", text="Rotation")
- col.prop(ccam, "aperture_ratio", text="Ratio")
-
-
-class CYCLES_CAMERA_PT_dof_viewport(CyclesButtonsPanel, Panel):
- bl_label = "Viewport"
- bl_parent_id = "CYCLES_CAMERA_PT_dof"
-
- @classmethod
- def poll(cls, context):
- return context.camera and CyclesButtonsPanel.poll(context)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
+ dof = cam.dof
+ layout.active = dof.use_dof
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
- cam = context.camera
- dof_options = cam.gpu_dof
-
- sub = flow.column(align=True)
- sub.prop(dof_options, "fstop")
- sub.prop(dof_options, "blades")
+ col = flow.column()
+ col.prop(dof, "aperture_fstop")
+ col.prop(dof, "aperture_blades")
+ col.prop(dof, "aperture_rotation")
+ col.prop(dof, "aperture_ratio")
class CYCLES_PT_context_material(CyclesButtonsPanel, Panel):
@@ -1191,27 +1172,53 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
row.prop(cob, "motion_steps", text="Steps")
-class CYCLES_OBJECT_PT_cycles_settings(CyclesButtonsPanel, Panel):
- bl_label = "Cycles Settings"
+def has_geometry_visibility(ob):
+ return ob and ((ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LIGHT'}) or
+ (ob.instance_type == 'COLLECTION' and ob.instance_collection))
+
+
+class CYCLES_OBJECT_PT_visibility(CyclesButtonsPanel, Panel):
+ bl_label = "Visibility"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
- ob = context.object
- return (CyclesButtonsPanel.poll(context) and
- ob and ((ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LIGHT'}) or
- (ob.instance_type == 'COLLECTION' and ob.instance_collection)))
+ return CyclesButtonsPanel.poll(context) and (context.object)
def draw(self, context):
- pass
+ layout = self.layout
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+ layout = self.layout
+ ob = context.object
-class CYCLES_OBJECT_PT_cycles_settings_ray_visibility(CyclesButtonsPanel, Panel):
+ col = flow.column()
+ col.prop(ob, "hide_viewport", text="Show in Viewports", invert_checkbox=True)
+ col = flow.column()
+ col.prop(ob, "hide_render", text="Show in Renders", invert_checkbox=True)
+ col = flow.column()
+ col.prop(ob, "hide_select", text="Selectable", invert_checkbox=True)
+
+ if has_geometry_visibility(ob):
+ cob = ob.cycles
+ col = flow.column()
+ col.prop(cob, "is_shadow_catcher")
+ col = flow.column()
+ col.prop(cob, "is_holdout")
+
+
+class CYCLES_OBJECT_PT_visibility_ray_visibility(CyclesButtonsPanel, Panel):
bl_label = "Ray Visibility"
- bl_parent_id = "CYCLES_OBJECT_PT_cycles_settings"
+ bl_parent_id = "CYCLES_OBJECT_PT_visibility"
bl_context = "object"
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ return CyclesButtonsPanel.poll(context) and has_geometry_visibility(ob)
+
def draw(self, context):
layout = self.layout
layout.use_property_split = True
@@ -1241,19 +1248,16 @@ class CYCLES_OBJECT_PT_cycles_settings_ray_visibility(CyclesButtonsPanel, Panel)
layout.separator()
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- col = flow.column()
- col.prop(cob, "is_shadow_catcher")
- col = flow.column()
- col.prop(cob, "is_holdout")
-
-class CYCLES_OBJECT_PT_cycles_settings_performance(CyclesButtonsPanel, Panel):
- bl_label = "Performance"
- bl_parent_id = "CYCLES_OBJECT_PT_cycles_settings"
+class CYCLES_OBJECT_PT_visibility_culling(CyclesButtonsPanel, Panel):
+ bl_label = "Culling"
+ bl_parent_id = "CYCLES_OBJECT_PT_visibility"
bl_context = "object"
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ return CyclesButtonsPanel.poll(context) and has_geometry_visibility(ob)
def draw(self, context):
layout = self.layout
@@ -1341,8 +1345,14 @@ class CYCLES_LIGHT_PT_light(CyclesButtonsPanel, Panel):
col = layout.column()
- if light.type in {'POINT', 'SUN', 'SPOT'}:
+ col.prop(light, "color")
+ col.prop(light, "energy")
+ col.separator()
+
+ if light.type in {'POINT', 'SPOT'}:
col.prop(light, "shadow_soft_size", text="Size")
+ elif light.type == 'SUN':
+ col.prop(light, "angle")
elif light.type == 'AREA':
col.prop(light, "shape", text="Shape")
sub = col.column(align=True)
@@ -1384,8 +1394,7 @@ class CYCLES_LIGHT_PT_nodes(CyclesButtonsPanel, Panel):
layout = self.layout
light = context.light
- if not panel_node_draw(layout, light, 'OUTPUT_LIGHT', 'Surface'):
- layout.prop(light, "color")
+ panel_node_draw(layout, light, 'OUTPUT_LIGHT', 'Surface')
class CYCLES_LIGHT_PT_spot(CyclesButtonsPanel, Panel):
@@ -1714,7 +1723,7 @@ class CYCLES_MATERIAL_PT_settings_surface(CyclesButtonsPanel, Panel):
col = layout.column()
col.prop(cmat, "sample_as_light", text="Multiple Importance")
col.prop(cmat, "use_transparent_shadow")
- col.prop(cmat, "displacement_method", text="Displacement Method")
+ col.prop(cmat, "displacement_method", text="Displacement")
def draw(self, context):
self.draw_shared(self, context.material)
@@ -2087,6 +2096,7 @@ def get_panels():
'MATERIAL_PT_preview',
'NODE_DATA_PT_light',
'NODE_DATA_PT_spot',
+ 'OBJECT_PT_visibility',
'VIEWLAYER_PT_filter',
'VIEWLAYER_PT_layer_passes',
'RENDER_PT_post_processing',
@@ -2141,12 +2151,11 @@ classes = (
CYCLES_PT_post_processing,
CYCLES_CAMERA_PT_dof,
CYCLES_CAMERA_PT_dof_aperture,
- CYCLES_CAMERA_PT_dof_viewport,
CYCLES_PT_context_material,
CYCLES_OBJECT_PT_motion_blur,
- CYCLES_OBJECT_PT_cycles_settings,
- CYCLES_OBJECT_PT_cycles_settings_ray_visibility,
- CYCLES_OBJECT_PT_cycles_settings_performance,
+ CYCLES_OBJECT_PT_visibility,
+ CYCLES_OBJECT_PT_visibility_ray_visibility,
+ CYCLES_OBJECT_PT_visibility_culling,
CYCLES_LIGHT_PT_preview,
CYCLES_LIGHT_PT_light,
CYCLES_LIGHT_PT_nodes,
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
index b3bfaa992a9..92dc8a8a4c6 100644
--- a/intern/cycles/blender/blender_camera.cpp
+++ b/intern/cycles/blender/blender_camera.cpp
@@ -119,10 +119,10 @@ static float blender_camera_focal_distance(BL::RenderEngine &b_engine,
BL::Camera &b_camera,
BlenderCamera *bcam)
{
- BL::Object b_dof_object = b_camera.dof_object();
+ BL::Object b_dof_object = b_camera.dof().focus_object();
if (!b_dof_object)
- return b_camera.dof_distance();
+ return b_camera.dof().focus_distance();
/* for dof object, return distance along camera Z direction */
BL::Array<float, 16> b_ob_matrix;
@@ -191,26 +191,30 @@ static void blender_camera_from_object(BlenderCamera *bcam,
bcam->lens = b_camera.lens();
- /* allow f/stop number to change aperture_size but still
- * give manual control over aperture radius */
- int aperture_type = get_enum(ccamera, "aperture_type");
-
- if (aperture_type == 1) {
- float fstop = RNA_float_get(&ccamera, "aperture_fstop");
+ if (b_camera.dof().use_dof()) {
+ /* allow f/stop number to change aperture_size but still
+ * give manual control over aperture radius */
+ float fstop = b_camera.dof().aperture_fstop();
fstop = max(fstop, 1e-5f);
if (bcam->type == CAMERA_ORTHOGRAPHIC)
bcam->aperturesize = 1.0f / (2.0f * fstop);
else
bcam->aperturesize = (bcam->lens * 1e-3f) / (2.0f * fstop);
- }
- else
- bcam->aperturesize = RNA_float_get(&ccamera, "aperture_size");
- bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades");
- bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation");
- bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera, bcam);
- bcam->aperture_ratio = RNA_float_get(&ccamera, "aperture_ratio");
+ bcam->apertureblades = b_camera.dof().aperture_blades();
+ bcam->aperturerotation = b_camera.dof().aperture_rotation();
+ bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera, bcam);
+ bcam->aperture_ratio = b_camera.dof().aperture_ratio();
+ }
+ else {
+ /* DOF is turned of for the camera. */
+ bcam->aperturesize = 0.0f;
+ bcam->apertureblades = 0;
+ bcam->aperturerotation = 0.0f;
+ bcam->focaldistance = 0.0f;
+ bcam->aperture_ratio = 1.0f;
+ }
bcam->shift.x = b_engine.camera_shift_x(b_ob, bcam->use_spherical_stereo);
bcam->shift.y = b_camera.shift_y();
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index de594f4fb6c..2a5c163aaeb 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "render/colorspace.h"
#include "render/mesh.h"
#include "render/object.h"
#include "render/scene.h"
@@ -291,7 +292,6 @@ static void create_mesh_volume_attribute(
VoxelAttribute *volume_data = attr->data_voxel();
ImageMetaData metadata;
bool animated = false;
- bool use_alpha = true;
volume_data->manager = image_manager;
volume_data->slot = image_manager->add_image(Attribute::standard_name(std),
@@ -300,7 +300,8 @@ static void create_mesh_volume_attribute(
frame,
INTERPOLATION_LINEAR,
EXTENSION_CLIP,
- use_alpha,
+ IMAGE_ALPHA_AUTO,
+ u_colorspace_raw,
metadata);
}
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 00f53804e38..c07e896ab33 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -149,7 +149,7 @@ void BlenderSync::sync_light(BL::Object &b_parent,
// }
case BL::Light::type_SUN: {
BL::SunLight b_sun_light(b_light);
- light->size = b_sun_light.shadow_soft_size();
+ light->angle = b_sun_light.angle();
light->type = LIGHT_DISTANT;
break;
}
@@ -182,6 +182,10 @@ void BlenderSync::sync_light(BL::Object &b_parent,
}
}
+ /* strength */
+ light->strength = get_float3(b_light.color());
+ light->strength *= BL::PointLight(b_light).energy();
+
/* location and (inverted!) direction */
light->co = transform_get_column(&tfm, 3);
light->dir = -transform_get_column(&tfm, 2);
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
index ffd1c70a4e4..3ab8c8bd6d9 100644
--- a/intern/cycles/blender/blender_python.cpp
+++ b/intern/cycles/blender/blender_python.cpp
@@ -937,6 +937,15 @@ static PyObject *set_resumable_chunk_range_func(PyObject * /*self*/, PyObject *a
Py_RETURN_NONE;
}
+static PyObject *clear_resumable_chunk_func(PyObject * /*self*/, PyObject * /*value*/)
+{
+ VLOG(1) << "Clear resumable render";
+ BlenderSession::num_resumable_chunks = 0;
+ BlenderSession::current_resumable_chunk = 0;
+
+ Py_RETURN_NONE;
+}
+
static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*/)
{
BlenderSession::print_render_stats = true;
@@ -992,6 +1001,7 @@ static PyMethodDef methods[] = {
/* Resumable render */
{"set_resumable_chunk", set_resumable_chunk_func, METH_VARARGS, ""},
{"set_resumable_chunk_range", set_resumable_chunk_range_func, METH_VARARGS, ""},
+ {"clear_resumable_chunk", clear_resumable_chunk_func, METH_NOARGS, ""},
/* Compute Device selection */
{"get_device_types", get_device_types_func, METH_VARARGS, ""},
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index 3a7e5f02b1d..11b6a38c195 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -16,12 +16,13 @@
#include <stdlib.h>
+#include "device/device.h"
#include "render/background.h"
#include "render/buffers.h"
#include "render/camera.h"
-#include "device/device.h"
-#include "render/integrator.h"
+#include "render/colorspace.h"
#include "render/film.h"
+#include "render/integrator.h"
#include "render/light.h"
#include "render/mesh.h"
#include "render/object.h"
@@ -1158,6 +1159,12 @@ void BlenderSession::builtin_image_info(const string &builtin_name,
metadata.height = b_image.size()[1];
metadata.depth = 1;
metadata.channels = b_image.channels();
+
+ if (metadata.is_float) {
+ /* Float images are already converted on the Blender side,
+ * no need to do anything in Cycles. */
+ metadata.colorspace = u_colorspace_raw;
+ }
}
else if (b_id.is_a(&RNA_Object)) {
/* smoke volume data */
@@ -1433,7 +1440,12 @@ void BlenderSession::builtin_images_load()
{
/* Force builtin images to be loaded along with Blender data sync. This
* is needed because we may be reading from depsgraph evaluated data which
- * can be freed by Blender before Cycles reads it. */
+ * can be freed by Blender before Cycles reads it.
+ *
+ * TODO: the assumption that no further access to builtin image data will
+ * happen is really weak, and likely to break in the future. We should find
+ * a better solution to hand over the data directly to the image manager
+ * instead of through callbacks whose timing is difficult to control. */
ImageManager *manager = session->scene->image_manager;
Device *device = session->device;
manager->device_load_builtin(device, session->scene, session->progress);
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index d1f823bc2b8..13097f6bf8e 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -15,6 +15,7 @@
*/
#include "render/background.h"
+#include "render/colorspace.h"
#include "render/graph.h"
#include "render/light.h"
#include "render/nodes.h"
@@ -89,6 +90,12 @@ template<typename NodeType> static ExtensionType get_image_extension(NodeType &b
return (ExtensionType)validate_enum_value(value, EXTENSION_NUM_TYPES, EXTENSION_REPEAT);
}
+static ImageAlphaType get_image_alpha_type(BL::Image &b_image)
+{
+ int value = b_image.alpha_mode();
+ return (ImageAlphaType)validate_enum_value(value, IMAGE_ALPHA_NUM_TYPES, IMAGE_ALPHA_AUTO);
+}
+
/* Graph */
static BL::NodeSocket get_node_output(BL::Node &b_node, const string &name)
@@ -650,8 +657,11 @@ static ShaderNode *add_node(Scene *scene,
image->builtin_data = NULL;
}
+ PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
+ image->colorspace = get_enum_identifier(colorspace_ptr, "name");
+
image->animated = b_image_node.image_user().use_auto_refresh();
- image->use_alpha = b_image.use_alpha();
+ image->alpha_type = get_image_alpha_type(b_image);
/* TODO: restore */
/* TODO(sergey): Does not work properly when we change builtin type. */
@@ -661,11 +671,11 @@ static ShaderNode *add_node(Scene *scene,
image->builtin_data,
get_image_interpolation(b_image_node),
get_image_extension(b_image_node),
- image->use_alpha);
+ image->use_alpha,
+ image->colorspace);
}
#endif
}
- image->color_space = (NodeImageColorSpace)b_image_node.color_space();
image->projection = (NodeImageProjection)b_image_node.projection();
image->interpolation = get_image_interpolation(b_image_node);
image->extension = get_image_extension(b_image_node);
@@ -695,8 +705,11 @@ static ShaderNode *add_node(Scene *scene,
env->builtin_data = NULL;
}
+ PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
+ env->colorspace = get_enum_identifier(colorspace_ptr, "name");
+
env->animated = b_env_node.image_user().use_auto_refresh();
- env->use_alpha = b_image.use_alpha();
+ env->alpha_type = get_image_alpha_type(b_image);
/* TODO: restore */
/* TODO(sergey): Does not work properly when we change builtin type. */
@@ -706,11 +719,11 @@ static ShaderNode *add_node(Scene *scene,
env->builtin_data,
get_image_interpolation(b_env_node),
EXTENSION_REPEAT,
- env->use_alpha);
+ env->use_alpha,
+ env->colorspace);
}
#endif
}
- env->color_space = (NodeImageColorSpace)b_env_node.color_space();
env->interpolation = get_image_interpolation(b_env_node);
env->projection = (NodeEnvironmentProjection)b_env_node.projection();
BL::TexMapping b_texture_mapping(b_env_node.texture_mapping());
@@ -861,7 +874,8 @@ static ShaderNode *add_node(Scene *scene,
point_density->builtin_data,
point_density->interpolation,
EXTENSION_CLIP,
- true);
+ IMAGE_ALPHA_AUTO,
+ u_colorspace_raw);
}
node = point_density;
@@ -1346,16 +1360,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, bool update_all)
}
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
-
- /* when doing preview render check for BI's transparency settings,
- * this is so because Blender's preview render routines are not able
- * to tweak all cycles's settings depending on different circumstances
- */
- if (b_engine.is_preview() == false)
- background->transparent = get_boolean(cscene, "film_transparent");
- else
- background->transparent = b_scene.render().alpha_mode() ==
- BL::RenderSettings::alpha_mode_TRANSPARENT;
+ background->transparent = b_scene.render().film_transparent();
if (background->transparent) {
background->transparent_glass = get_boolean(cscene, "film_transparent_glass");
@@ -1401,16 +1406,9 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
}
else {
- float strength = 1.0f;
-
- if (b_light.type() == BL::Light::type_POINT || b_light.type() == BL::Light::type_SPOT ||
- b_light.type() == BL::Light::type_AREA) {
- strength = 100.0f;
- }
-
EmissionNode *emission = new EmissionNode();
- emission->color = get_float3(b_light.color());
- emission->strength = strength;
+ emission->color = make_float3(1.0f, 1.0f, 1.0f);
+ emission->strength = 1.0f;
graph->add(emission);
ShaderNode *out = graph->output();
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index 500634e7526..972d7296727 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -43,10 +43,10 @@ CCL_NAMESPACE_BEGIN
void python_thread_state_save(void **python_thread_state);
void python_thread_state_restore(void **python_thread_state);
-static inline BL::Mesh object_to_mesh(BL::BlendData &data,
+static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
BL::Object &object,
- BL::Depsgraph &depsgraph,
- bool calc_undeformed,
+ BL::Depsgraph & /*depsgraph*/,
+ bool /*calc_undeformed*/,
Mesh::SubdivisionType subdivision_type)
{
/* TODO: make this work with copy-on-write, modifiers are already evaluated. */
@@ -75,11 +75,11 @@ static inline BL::Mesh object_to_mesh(BL::BlendData &data,
* UV are not empty. */
if (mesh.is_editmode() ||
(mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) {
- mesh = data.meshes.new_from_object(depsgraph, object, false, false);
+ mesh = object.to_mesh();
}
}
else {
- mesh = data.meshes.new_from_object(depsgraph, object, true, calc_undeformed);
+ mesh = object.to_mesh();
}
#if 0
@@ -102,11 +102,13 @@ static inline BL::Mesh object_to_mesh(BL::BlendData &data,
return mesh;
}
-static inline void free_object_to_mesh(BL::BlendData &data, BL::Object &object, BL::Mesh &mesh)
+static inline void free_object_to_mesh(BL::BlendData & /*data*/,
+ BL::Object &object,
+ BL::Mesh &mesh)
{
/* Free mesh if we didn't just use the existing one. */
if (object.data().ptr.data != mesh.ptr.data) {
- data.meshes.remove(mesh, false, true, false);
+ object.to_mesh_clear();
}
}
diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index 837a8186064..dc9adcb1537 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -332,9 +332,11 @@ class CPUDevice : public Device {
if (DebugFlags().cpu.has_sse2() && system_cpu_support_sse2()) {
bvh_layout_mask |= BVH_LAYOUT_BVH4;
}
+#if defined(__x86_64__) || defined(_M_X64)
if (DebugFlags().cpu.has_avx2() && system_cpu_support_avx2()) {
bvh_layout_mask |= BVH_LAYOUT_BVH8;
}
+#endif
#ifdef WITH_EMBREE
bvh_layout_mask |= BVH_LAYOUT_EMBREE;
#endif /* WITH_EMBREE */
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index f2eaa7b50a5..34300543f91 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -90,6 +90,11 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
eval *= ls->eval_fac;
+ if (ls->lamp != LAMP_NONE) {
+ const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, ls->lamp);
+ eval *= make_float3(klight->strength[0], klight->strength[1], klight->strength[2]);
+ }
+
return eval;
}
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 351b623addb..c80124d3eb2 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -1092,7 +1092,7 @@ ccl_device void shader_eval_surface(KernelGlobals *kg,
#ifdef __OSL__
if (kg->osl) {
- if (sd->object == OBJECT_NONE) {
+ if (sd->object == OBJECT_NONE && sd->lamp == LAMP_NONE) {
OSLShader::eval_background(kg, sd, state, path_flag);
}
else {
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 0c6b4b401f0..18d2a216f72 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -1456,6 +1456,8 @@ typedef struct KernelLight {
int samples;
float max_bounces;
float random;
+ float strength[3];
+ float pad1;
Transform tfm;
Transform itfm;
union {
diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h
index 641c9967586..0e6c8d21534 100644
--- a/intern/cycles/kernel/osl/osl_globals.h
+++ b/intern/cycles/kernel/osl/osl_globals.h
@@ -21,10 +21,14 @@
# include <OSL/oslexec.h>
+# include <OpenImageIO/refcnt.h>
+# include <OpenImageIO/unordered_map_concurrent.h>
+
# include "util/util_map.h"
# include "util/util_param.h"
# include "util/util_thread.h"
# include "util/util_vector.h"
+# include "util/util_unique_ptr.h"
# ifndef WIN32
using std::isfinite;
@@ -33,6 +37,13 @@ using std::isfinite;
CCL_NAMESPACE_BEGIN
class OSLRenderServices;
+class ColorSpaceProcessor;
+
+/* OSL Globals
+ *
+ * Data needed by OSL render services, that is global to a rendering session.
+ * This includes all OSL shaders, name to attribute mapping and texture handles.
+ * */
struct OSLGlobals {
OSLGlobals()
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 6404690224a..08821ffa099 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -25,6 +25,7 @@
#include <string.h>
+#include "render/colorspace.h"
#include "render/mesh.h"
#include "render/object.h"
#include "render/scene.h"
@@ -55,10 +56,6 @@
#include "kernel/kernel_accumulate.h"
#include "kernel/kernel_shader.h"
-#ifdef WITH_PTEX
-# include <Ptexture.h>
-#endif
-
CCL_NAMESPACE_BEGIN
/* RenderServices implementation */
@@ -124,34 +121,17 @@ ustring OSLRenderServices::u_I("I");
ustring OSLRenderServices::u_u("u");
ustring OSLRenderServices::u_v("v");
ustring OSLRenderServices::u_empty;
-ustring OSLRenderServices::u_at_bevel("@bevel");
-ustring OSLRenderServices::u_at_ao("@ao");
-OSLRenderServices::OSLRenderServices()
+OSLRenderServices::OSLRenderServices(OSL::TextureSystem *texture_system)
+ : texture_system(texture_system)
{
- kernel_globals = NULL;
- osl_ts = NULL;
-
-#ifdef WITH_PTEX
- size_t maxmem = 16384 * 1024;
- ptex_cache = PtexCache::create(0, maxmem);
-#endif
}
OSLRenderServices::~OSLRenderServices()
{
- if (osl_ts) {
- VLOG(2) << "OSL texture system stats:\n" << osl_ts->getstats();
+ if (texture_system) {
+ VLOG(2) << "OSL texture system stats:\n" << texture_system->getstats();
}
-#ifdef WITH_PTEX
- ptex_cache->release();
-#endif
-}
-
-void OSLRenderServices::thread_init(KernelGlobals *kernel_globals_, OSL::TextureSystem *osl_ts_)
-{
- kernel_globals = kernel_globals_;
- osl_ts = osl_ts_;
}
bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg,
@@ -233,7 +213,8 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg,
ustring from,
float time)
{
- KernelGlobals *kg = kernel_globals;
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ KernelGlobals *kg = sd->osl_globals;
if (from == u_ndc) {
copy_matrix(result, kernel_data.cam.ndctoworld);
@@ -264,7 +245,8 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
ustring to,
float time)
{
- KernelGlobals *kg = kernel_globals;
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ KernelGlobals *kg = sd->osl_globals;
if (to == u_ndc) {
copy_matrix(result, kernel_data.cam.worldtondc);
@@ -354,7 +336,8 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result, ustring from)
{
- KernelGlobals *kg = kernel_globals;
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ KernelGlobals *kg = sd->osl_globals;
if (from == u_ndc) {
copy_matrix(result, kernel_data.cam.ndctoworld);
@@ -380,7 +363,8 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
OSL::Matrix44 &result,
ustring to)
{
- KernelGlobals *kg = kernel_globals;
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ KernelGlobals *kg = sd->osl_globals;
if (to == u_ndc) {
copy_matrix(result, kernel_data.cam.worldtondc);
@@ -956,19 +940,44 @@ bool OSLRenderServices::get_userdata(
TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(ustring filename)
{
- if (filename.length() && filename[0] == '@') {
- /* Dummy, we don't use texture handles for builtin textures but need
- * to tell the OSL runtime optimizer that this is a valid texture. */
+ OSLTextureHandleMap::iterator it = textures.find(filename);
+
+ /* For non-OIIO textures, just return a pointer to our own OSLTextureHandle. */
+ if (it != textures.end()) {
+ if (it->second->type != OSLTextureHandle::OIIO) {
+ return (TextureSystem::TextureHandle *)it->second.get();
+ }
+ }
+
+ /* Get handle from OpenImageIO. */
+ OSL::TextureSystem *ts = texture_system;
+ TextureSystem::TextureHandle *handle = ts->get_texture_handle(filename);
+ if (handle == NULL) {
return NULL;
}
- else {
- return texturesys()->get_texture_handle(filename);
+
+ /* Insert new OSLTextureHandle if needed. */
+ if (it == textures.end()) {
+ textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::OIIO));
+ it = textures.find(filename);
}
+
+ /* Assign OIIO texture handle and return. */
+ it->second->oiio_handle = handle;
+ return (TextureSystem::TextureHandle *)it->second.get();
}
bool OSLRenderServices::good(TextureSystem::TextureHandle *texture_handle)
{
- return texturesys()->good(texture_handle);
+ OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
+
+ if (handle->oiio_handle) {
+ OSL::TextureSystem *ts = texture_system;
+ return ts->good(handle->oiio_handle);
+ }
+ else {
+ return true;
+ }
}
bool OSLRenderServices::texture(ustring filename,
@@ -988,69 +997,28 @@ bool OSLRenderServices::texture(ustring filename,
float *dresultdt,
ustring *errormessage)
{
- OSL::TextureSystem *ts = osl_ts;
+ OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
+ OSLTextureHandle::Type texture_type = (handle) ? handle->type : OSLTextureHandle::OIIO;
ShaderData *sd = (ShaderData *)(sg->renderstate);
- KernelGlobals *kg = sd->osl_globals;
-
- if (texture_thread_info == NULL) {
- OSLThreadData *tdata = kg->osl_tdata;
- texture_thread_info = tdata->oiio_thread_info;
- }
-
-#ifdef WITH_PTEX
- /* todo: this is just a quick hack, only works with particular files and options */
- if (string_endswith(filename.string(), ".ptx")) {
- float2 uv;
- int faceid;
-
- if (!primitive_ptex(kg, sd, &uv, &faceid))
- return false;
-
- float u = uv.x;
- float v = uv.y;
- float dudx = 0.0f;
- float dvdx = 0.0f;
- float dudy = 0.0f;
- float dvdy = 0.0f;
-
- Ptex::String error;
- PtexPtr<PtexTexture> r(ptex_cache->get(filename.c_str(), error));
-
- if (!r) {
- // std::cerr << error.c_str() << std::endl;
- return false;
- }
-
- bool mipmaplerp = false;
- float sharpness = 1.0f;
- PtexFilter::Options opts(PtexFilter::f_bicubic, mipmaplerp, sharpness);
- PtexPtr<PtexFilter> f(PtexFilter::getFilter(r, opts));
-
- f->eval(result, options.firstchannel, nchannels, faceid, u, v, dudx, dvdx, dudy, dvdy);
-
- for (int c = r->numChannels(); c < nchannels; c++)
- result[c] = result[0];
-
- return true;
- }
-#endif
+ KernelGlobals *kernel_globals = sd->osl_globals;
bool status = false;
- if (filename.length() && filename[0] == '@') {
- if (filename == u_at_bevel) {
+ switch (texture_type) {
+ case OSLTextureHandle::BEVEL: {
/* Bevel shader hack. */
if (nchannels >= 3) {
PathState *state = sd->osl_path_state;
int num_samples = (int)s;
float radius = t;
- float3 N = svm_bevel(kg, sd, state, radius, num_samples);
+ float3 N = svm_bevel(kernel_globals, sd, state, radius, num_samples);
result[0] = N.x;
result[1] = N.y;
result[2] = N.z;
status = true;
}
+ break;
}
- else if (filename == u_at_ao) {
+ case OSLTextureHandle::AO: {
/* AO shader hack. */
PathState *state = sd->osl_path_state;
int num_samples = (int)s;
@@ -1066,19 +1034,13 @@ bool OSLRenderServices::texture(ustring filename,
if ((int)options.tblur) {
flags |= NODE_AO_GLOBAL_RADIUS;
}
- result[0] = svm_ao(kg, sd, N, state, radius, num_samples, flags);
+ result[0] = svm_ao(kernel_globals, sd, N, state, radius, num_samples, flags);
status = true;
+ break;
}
- else if (filename[1] == 'l') {
- /* IES light. */
- int slot = atoi(filename.c_str() + 2);
- result[0] = kernel_ies_interp(kg, slot, s, t);
- status = true;
- }
- else {
+ case OSLTextureHandle::SVM: {
/* Packed texture. */
- int slot = atoi(filename.c_str() + 2);
- float4 rgba = kernel_tex_image_interp(kg, slot, s, 1.0f - t);
+ float4 rgba = kernel_tex_image_interp(kernel_globals, handle->svm_slot, s, 1.0f - t);
result[0] = rgba[0];
if (nchannels > 1)
@@ -1088,37 +1050,62 @@ bool OSLRenderServices::texture(ustring filename,
if (nchannels > 3)
result[3] = rgba[3];
status = true;
+ break;
}
- }
- else {
- if (texture_handle != NULL) {
- status = ts->texture(texture_handle,
- texture_thread_info,
- options,
- s,
- t,
- dsdx,
- dtdx,
- dsdy,
- dtdy,
- nchannels,
- result,
- dresultds,
- dresultdt);
+ case OSLTextureHandle::IES: {
+ /* IES light. */
+ result[0] = kernel_ies_interp(kernel_globals, handle->svm_slot, s, t);
+ status = true;
+ break;
}
- else {
- status = ts->texture(filename,
- options,
- s,
- t,
- dsdx,
- dtdx,
- dsdy,
- dtdy,
- nchannels,
- result,
- dresultds,
- dresultdt);
+ case OSLTextureHandle::OIIO: {
+ /* OpenImageIO texture cache. */
+ OSL::TextureSystem *ts = texture_system;
+
+ if (handle && handle->oiio_handle) {
+ if (texture_thread_info == NULL) {
+ OSLThreadData *tdata = kernel_globals->osl_tdata;
+ texture_thread_info = tdata->oiio_thread_info;
+ }
+
+ status = ts->texture(handle->oiio_handle,
+ texture_thread_info,
+ options,
+ s,
+ t,
+ dsdx,
+ dtdx,
+ dsdy,
+ dtdy,
+ nchannels,
+ result,
+ dresultds,
+ dresultdt);
+ }
+ else {
+ status = ts->texture(filename,
+ options,
+ s,
+ t,
+ dsdx,
+ dtdx,
+ dsdy,
+ dtdy,
+ nchannels,
+ result,
+ dresultds,
+ dresultdt);
+ }
+
+ if (!status) {
+ /* This might be slow, but prevents error messages leak and
+ * other nasty stuff happening. */
+ ts->geterror();
+ }
+ else if (handle && handle->processor) {
+ ColorSpaceManager::to_scene_linear(handle->processor, result, nchannels);
+ }
+ break;
}
}
@@ -1131,11 +1118,6 @@ bool OSLRenderServices::texture(ustring filename,
if (nchannels == 4)
result[3] = 1.0f;
}
- /* This might be slow, but prevents error messages leak and
- * other nasty stuff happening.
- */
- string err = ts->geterror();
- (void)err;
}
return status;
@@ -1157,56 +1139,83 @@ bool OSLRenderServices::texture3d(ustring filename,
float *dresultdr,
ustring *errormessage)
{
- OSL::TextureSystem *ts = osl_ts;
- ShaderData *sd = (ShaderData *)(sg->renderstate);
- KernelGlobals *kg = sd->osl_globals;
+ OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
+ OSLTextureHandle::Type texture_type = (handle) ? handle->type : OSLTextureHandle::OIIO;
+ bool status = false;
- if (texture_thread_info == NULL) {
- OSLThreadData *tdata = kg->osl_tdata;
- texture_thread_info = tdata->oiio_thread_info;
- }
+ switch (texture_type) {
+ case OSLTextureHandle::SVM: {
+ /* Packed texture. */
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ KernelGlobals *kernel_globals = sd->osl_globals;
+ int slot = handle->svm_slot;
+ float4 rgba = kernel_tex_image_interp_3d(
+ kernel_globals, slot, P.x, P.y, P.z, INTERPOLATION_NONE);
- bool status;
- if (filename.length() && filename[0] == '@') {
- int slot = atoi(filename.c_str() + 1);
- float4 rgba = kernel_tex_image_interp_3d(kg, slot, P.x, P.y, P.z, INTERPOLATION_NONE);
+ result[0] = rgba[0];
+ if (nchannels > 1)
+ result[1] = rgba[1];
+ if (nchannels > 2)
+ result[2] = rgba[2];
+ if (nchannels > 3)
+ result[3] = rgba[3];
+ status = true;
+ break;
+ }
+ case OSLTextureHandle::OIIO: {
+ /* OpenImageIO texture cache. */
+ OSL::TextureSystem *ts = texture_system;
+
+ if (handle && handle->oiio_handle) {
+ if (texture_thread_info == NULL) {
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ KernelGlobals *kernel_globals = sd->osl_globals;
+ OSLThreadData *tdata = kernel_globals->osl_tdata;
+ texture_thread_info = tdata->oiio_thread_info;
+ }
- result[0] = rgba[0];
- if (nchannels > 1)
- result[1] = rgba[1];
- if (nchannels > 2)
- result[2] = rgba[2];
- if (nchannels > 3)
- result[3] = rgba[3];
- status = true;
- }
- else {
- if (texture_handle != NULL) {
- status = ts->texture3d(texture_handle,
- texture_thread_info,
- options,
- P,
- dPdx,
- dPdy,
- dPdz,
- nchannels,
- result,
- dresultds,
- dresultdt,
- dresultdr);
+ status = ts->texture3d(handle->oiio_handle,
+ texture_thread_info,
+ options,
+ P,
+ dPdx,
+ dPdy,
+ dPdz,
+ nchannels,
+ result,
+ dresultds,
+ dresultdt,
+ dresultdr);
+ }
+ else {
+ status = ts->texture3d(filename,
+ options,
+ P,
+ dPdx,
+ dPdy,
+ dPdz,
+ nchannels,
+ result,
+ dresultds,
+ dresultdt,
+ dresultdr);
+ }
+
+ if (!status) {
+ /* This might be slow, but prevents error messages leak and
+ * other nasty stuff happening. */
+ ts->geterror();
+ }
+ else if (handle && handle->processor) {
+ ColorSpaceManager::to_scene_linear(handle->processor, result, nchannels);
+ }
+ break;
}
- else {
- status = ts->texture3d(filename,
- options,
- P,
- dPdx,
- dPdy,
- dPdz,
- nchannels,
- result,
- dresultds,
- dresultdt,
- dresultdr);
+ case OSLTextureHandle::IES:
+ case OSLTextureHandle::AO:
+ case OSLTextureHandle::BEVEL: {
+ status = false;
+ break;
}
}
@@ -1219,18 +1228,13 @@ bool OSLRenderServices::texture3d(ustring filename,
if (nchannels == 4)
result[3] = 1.0f;
}
- /* This might be slow, but prevents error messages leak and
- * other nasty stuff happening.
- */
- string err = ts->geterror();
- (void)err;
}
return status;
}
bool OSLRenderServices::environment(ustring filename,
- TextureHandle *th,
+ TextureHandle *texture_handle,
TexturePerthread *thread_info,
TextureOpt &options,
OSL::ShaderGlobals *sg,
@@ -1243,21 +1247,33 @@ bool OSLRenderServices::environment(ustring filename,
float *dresultdt,
ustring *errormessage)
{
- OSL::TextureSystem *ts = osl_ts;
+ OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
+ OSL::TextureSystem *ts = texture_system;
+ bool status = false;
- if (thread_info == NULL) {
- ShaderData *sd = (ShaderData *)(sg->renderstate);
- KernelGlobals *kg = sd->osl_globals;
- OSLThreadData *tdata = kg->osl_tdata;
- thread_info = tdata->oiio_thread_info;
- }
+ if (handle && handle->oiio_handle) {
+ if (thread_info == NULL) {
+ ShaderData *sd = (ShaderData *)(sg->renderstate);
+ KernelGlobals *kernel_globals = sd->osl_globals;
+ OSLThreadData *tdata = kernel_globals->osl_tdata;
+ thread_info = tdata->oiio_thread_info;
+ }
- if (th == NULL) {
- th = ts->get_texture_handle(filename, thread_info);
+ status = ts->environment(handle->oiio_handle,
+ thread_info,
+ options,
+ R,
+ dRdx,
+ dRdy,
+ nchannels,
+ result,
+ dresultds,
+ dresultdt);
+ }
+ else {
+ status = ts->environment(
+ filename, options, R, dRdx, dRdy, nchannels, result, dresultds, dresultdt);
}
-
- bool status = ts->environment(
- th, thread_info, options, R, dRdx, dRdy, nchannels, result, dresultds, dresultdt);
if (!status) {
if (nchannels == 3 || nchannels == 4) {
@@ -1269,26 +1285,31 @@ bool OSLRenderServices::environment(ustring filename,
result[3] = 1.0f;
}
}
+ else if (handle && handle->processor) {
+ ColorSpaceManager::to_scene_linear(handle->processor, result, nchannels);
+ }
return status;
}
bool OSLRenderServices::get_texture_info(OSL::ShaderGlobals *sg,
ustring filename,
- TextureHandle *th,
+ TextureHandle *texture_handle,
int subimage,
ustring dataname,
TypeDesc datatype,
void *data)
{
- OSL::TextureSystem *ts = osl_ts;
- if (filename.length() && filename[0] == '@') {
- /* Special builtin textures. */
+ OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle;
+
+ /* No texture info for other texture types. */
+ if (handle && handle->type != OSLTextureHandle::OIIO) {
return false;
}
- else {
- return ts->get_texture_info(filename, subimage, dataname, datatype, data);
- }
+
+ /* Get texture info from OpenImageIO. */
+ OSL::TextureSystem *ts = texture_system;
+ return ts->get_texture_info(filename, subimage, dataname, datatype, data);
}
int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals *sg,
diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h
index 2fad5833fc9..024ef656be1 100644
--- a/intern/cycles/kernel/osl/osl_services.h
+++ b/intern/cycles/kernel/osl/osl_services.h
@@ -40,13 +40,46 @@ class Shader;
struct ShaderData;
struct float3;
struct KernelGlobals;
+
+/* OSL Texture Handle
+ *
+ * OSL texture lookups are string based. If those strings are known at compile
+ * time, the OSL compiler can cache a texture handle to use instead of a string.
+ *
+ * By default it uses TextureSystem::TextureHandle. But since we want to support
+ * different kinds of textures and color space conversions, this is our own handle
+ * with additional data.
+ *
+ * These are stored in a concurrent hash map, because OSL can compile multiple
+ * shaders in parallel. */
+
+struct OSLTextureHandle : public OIIO::RefCnt {
+ enum Type { OIIO, SVM, IES, BEVEL, AO };
+
+ OSLTextureHandle(Type type = OIIO, int svm_slot = -1)
+ : type(type), svm_slot(svm_slot), oiio_handle(NULL), processor(NULL)
+ {
+ }
+
+ Type type;
+ int svm_slot;
+ OSL::TextureSystem::TextureHandle *oiio_handle;
+ ColorSpaceProcessor *processor;
+};
+
+typedef OIIO::intrusive_ptr<OSLTextureHandle> OSLTextureHandleRef;
+typedef OIIO::unordered_map_concurrent<ustring, OSLTextureHandleRef, ustringHash>
+ OSLTextureHandleMap;
+
+/* OSL Render Services
+ *
+ * Interface for OSL to access attributes, textures and other scene data. */
+
class OSLRenderServices : public OSL::RendererServices {
public:
- OSLRenderServices();
+ OSLRenderServices(OSL::TextureSystem *texture_system);
~OSLRenderServices();
- void thread_init(KernelGlobals *kernel_globals, OSL::TextureSystem *ts);
-
bool get_matrix(OSL::ShaderGlobals *sg,
OSL::Matrix44 &result,
OSL::TransformationPtr xform,
@@ -255,12 +288,12 @@ class OSLRenderServices : public OSL::RendererServices {
static ustring u_at_bevel;
static ustring u_at_ao;
- private:
- KernelGlobals *kernel_globals;
- OSL::TextureSystem *osl_ts;
-#ifdef WITH_PTEX
- PtexCache *ptex_cache;
-#endif
+ /* Texture system and texture handle map are part of the services instead of
+ * globals to be shared between different render sessions. This saves memory,
+ * and is required because texture handles are cached as part of the shared
+ * shading system. */
+ OSL::TextureSystem *texture_system;
+ OSLTextureHandleMap textures;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
index 3d9c579c9ff..db5ad06d3fc 100644
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ b/intern/cycles/kernel/osl/osl_shader.cpp
@@ -49,7 +49,6 @@ void OSLShader::thread_init(KernelGlobals *kg,
/* per thread kernel data init*/
kg->osl = osl_globals;
- kg->osl->services->thread_init(kernel_globals, osl_globals->ts);
OSL::ShadingSystem *ss = kg->osl->ss;
OSLThreadData *tdata = new OSLThreadData();
diff --git a/intern/cycles/kernel/shaders/node_environment_texture.osl b/intern/cycles/kernel/shaders/node_environment_texture.osl
index eb32dad392f..43f607f7cb0 100644
--- a/intern/cycles/kernel/shaders/node_environment_texture.osl
+++ b/intern/cycles/kernel/shaders/node_environment_texture.osl
@@ -47,9 +47,10 @@ shader node_environment_texture(
string filename = "",
string projection = "equirectangular",
string interpolation = "linear",
- string color_space = "sRGB",
+ int compress_as_srgb = 0,
+ int ignore_alpha = 0,
+ int unassociate_alpha = 0,
int is_float = 1,
- int use_alpha = 1,
output color Color = 0.0,
output float Alpha = 1.0)
{
@@ -69,13 +70,16 @@ shader node_environment_texture(
Color = (color)texture(
filename, p[0], 1.0 - p[1], "wrap", "periodic", "interp", interpolation, "alpha", Alpha);
- if (use_alpha) {
+ if (ignore_alpha) {
+ Alpha = 1.0;
+ }
+ else if (unassociate_alpha) {
Color = color_unpremultiply(Color, Alpha);
if (!is_float)
Color = min(Color, 1.0);
}
- if (color_space == "sRGB")
+ if (compress_as_srgb)
Color = color_srgb_to_scene_linear(Color);
}
diff --git a/intern/cycles/kernel/shaders/node_ies_light.osl b/intern/cycles/kernel/shaders/node_ies_light.osl
index ea8c44e09de..ce0173451da 100644
--- a/intern/cycles/kernel/shaders/node_ies_light.osl
+++ b/intern/cycles/kernel/shaders/node_ies_light.osl
@@ -21,7 +21,7 @@
shader node_ies_light(int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- int slot = 0,
+ string filename = "",
float Strength = 1.0,
point Vector = I,
output float Fac = 0.0)
@@ -37,5 +37,5 @@ shader node_ies_light(int use_mapping = 0,
float v_angle = acos(-p[2]);
float h_angle = atan2(p[0], p[1]) + M_PI;
- Fac = Strength * texture(format("@l%d", slot), h_angle, v_angle);
+ Fac = Strength * texture(filename, h_angle, v_angle);
}
diff --git a/intern/cycles/kernel/shaders/node_image_texture.osl b/intern/cycles/kernel/shaders/node_image_texture.osl
index df5eda39985..f78ca7ec0e8 100644
--- a/intern/cycles/kernel/shaders/node_image_texture.osl
+++ b/intern/cycles/kernel/shaders/node_image_texture.osl
@@ -56,11 +56,12 @@ point map_to_sphere(vector dir)
}
color image_texture_lookup(string filename,
- string color_space,
float u,
float v,
output float Alpha,
- int use_alpha,
+ int compress_as_srgb,
+ int ignore_alpha,
+ int unassociate_alpha,
int is_float,
string interpolation,
string extension)
@@ -68,14 +69,17 @@ color image_texture_lookup(string filename,
color rgb = (color)texture(
filename, u, 1.0 - v, "wrap", extension, "interp", interpolation, "alpha", Alpha);
- if (use_alpha) {
+ if (ignore_alpha) {
+ Alpha = 1.0;
+ }
+ else if (unassociate_alpha) {
rgb = color_unpremultiply(rgb, Alpha);
if (!is_float)
rgb = min(rgb, 1.0);
}
- if (color_space == "sRGB") {
+ if (compress_as_srgb) {
rgb = color_srgb_to_scene_linear(rgb);
}
@@ -86,13 +90,14 @@ shader node_image_texture(int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
point Vector = P,
string filename = "",
- string color_space = "sRGB",
string projection = "flat",
string interpolation = "smartcubic",
string extension = "periodic",
float projection_blend = 0.0,
+ int compress_as_srgb = 0,
+ int ignore_alpha = 0,
+ int unassociate_alpha = 0,
int is_float = 1,
- int use_alpha = 1,
output color Color = 0.0,
output float Alpha = 1.0)
{
@@ -102,8 +107,16 @@ shader node_image_texture(int use_mapping = 0,
p = transform(mapping, p);
if (projection == "flat") {
- Color = image_texture_lookup(
- filename, color_space, p[0], p[1], Alpha, use_alpha, is_float, interpolation, extension);
+ Color = image_texture_lookup(filename,
+ p[0],
+ p[1],
+ Alpha,
+ compress_as_srgb,
+ ignore_alpha,
+ unassociate_alpha,
+ is_float,
+ interpolation,
+ extension);
}
else if (projection == "box") {
/* object space normal */
@@ -173,11 +186,12 @@ shader node_image_texture(int use_mapping = 0,
if (weight[0] > 0.0) {
Color += weight[0] * image_texture_lookup(filename,
- color_space,
p[1],
p[2],
tmp_alpha,
- use_alpha,
+ compress_as_srgb,
+ ignore_alpha,
+ unassociate_alpha,
is_float,
interpolation,
extension);
@@ -185,11 +199,12 @@ shader node_image_texture(int use_mapping = 0,
}
if (weight[1] > 0.0) {
Color += weight[1] * image_texture_lookup(filename,
- color_space,
p[0],
p[2],
tmp_alpha,
- use_alpha,
+ compress_as_srgb,
+ ignore_alpha,
+ unassociate_alpha,
is_float,
interpolation,
extension);
@@ -197,11 +212,12 @@ shader node_image_texture(int use_mapping = 0,
}
if (weight[2] > 0.0) {
Color += weight[2] * image_texture_lookup(filename,
- color_space,
p[1],
p[0],
tmp_alpha,
- use_alpha,
+ compress_as_srgb,
+ ignore_alpha,
+ unassociate_alpha,
is_float,
interpolation,
extension);
@@ -211,11 +227,12 @@ shader node_image_texture(int use_mapping = 0,
else if (projection == "sphere") {
point projected = map_to_sphere(texco_remap_square(p));
Color = image_texture_lookup(filename,
- color_space,
projected[0],
projected[1],
Alpha,
- use_alpha,
+ compress_as_srgb,
+ ignore_alpha,
+ unassociate_alpha,
is_float,
interpolation,
extension);
@@ -223,11 +240,12 @@ shader node_image_texture(int use_mapping = 0,
else if (projection == "tube") {
point projected = map_to_tube(texco_remap_square(p));
Color = image_texture_lookup(filename,
- color_space,
projected[0],
projected[1],
Alpha,
- use_alpha,
+ compress_as_srgb,
+ ignore_alpha,
+ unassociate_alpha,
is_float,
interpolation,
extension);
diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h
index ee4b8b6e50c..2ef64662d0e 100644
--- a/intern/cycles/kernel/svm/svm_image.h
+++ b/intern/cycles/kernel/svm/svm_image.h
@@ -16,13 +16,12 @@
CCL_NAMESPACE_BEGIN
-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 flags)
{
float4 r = kernel_tex_image_interp(kg, id, x, y);
const float alpha = r.w;
- if (use_alpha && alpha != 1.0f && alpha != 0.0f) {
+ if ((flags & NODE_IMAGE_ALPHA_UNASSOCIATE) && alpha != 1.0f && alpha != 0.0f) {
r /= alpha;
const int texture_type = kernel_tex_type(id);
if (texture_type == IMAGE_DATA_TYPE_BYTE4 || texture_type == IMAGE_DATA_TYPE_BYTE) {
@@ -31,8 +30,7 @@ svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb, uint u
r.w = alpha;
}
- if (srgb) {
- /* TODO(lukas): Implement proper conversion for image textures. */
+ if (flags & NODE_IMAGE_COMPRESS_AS_SRGB) {
r = color_srgb_to_linear_v4(r);
}
@@ -48,13 +46,12 @@ 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, flags;
- decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &srgb);
+ decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &flags);
float3 co = stack_load_float3(stack, co_offset);
float2 tex_co;
- uint use_alpha = stack_valid(alpha_offset);
if (node.w == NODE_IMAGE_PROJ_SPHERE) {
co = texco_remap_square(co);
tex_co = map_to_sphere(co);
@@ -66,7 +63,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, flags);
if (stack_valid(out_offset))
stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
@@ -145,27 +142,26 @@ 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, flags;
+ decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &flags);
float3 co = stack_load_float3(stack, co_offset);
uint id = node.y;
float4 f = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- uint use_alpha = stack_valid(alpha_offset);
/* Map so that no textures are flipped, rotation is somewhat arbitrary. */
if (weight.x > 0.0f) {
float2 uv = make_float2((signed_N.x < 0.0f) ? 1.0f - co.y : co.y, co.z);
- f += weight.x * svm_image_texture(kg, id, uv.x, uv.y, srgb, use_alpha);
+ f += weight.x * svm_image_texture(kg, id, uv.x, uv.y, flags);
}
if (weight.y > 0.0f) {
float2 uv = make_float2((signed_N.y > 0.0f) ? 1.0f - co.x : co.x, co.z);
- f += weight.y * svm_image_texture(kg, id, uv.x, uv.y, srgb, use_alpha);
+ f += weight.y * svm_image_texture(kg, id, uv.x, uv.y, flags);
}
if (weight.z > 0.0f) {
float2 uv = make_float2((signed_N.z > 0.0f) ? 1.0f - co.y : co.y, co.x);
- f += weight.z * svm_image_texture(kg, id, uv.x, uv.y, srgb, use_alpha);
+ f += weight.z * svm_image_texture(kg, id, uv.x, uv.y, flags);
}
if (stack_valid(out_offset))
@@ -180,10 +176,10 @@ ccl_device void svm_node_tex_environment(KernelGlobals *kg,
uint4 node)
{
uint id = node.y;
- uint co_offset, out_offset, alpha_offset, srgb;
+ uint co_offset, out_offset, alpha_offset, flags;
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, &flags);
float3 co = stack_load_float3(stack, co_offset);
float2 uv;
@@ -195,8 +191,7 @@ ccl_device void svm_node_tex_environment(KernelGlobals *kg,
else
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, flags);
if (stack_valid(out_offset))
stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index d31e4f93696..ea92fd7ce59 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -373,11 +373,6 @@ typedef enum NodeNormalMapSpace {
NODE_NORMAL_MAP_BLENDER_WORLD,
} NodeNormalMapSpace;
-typedef enum NodeImageColorSpace {
- NODE_COLOR_SPACE_NONE = 0,
- NODE_COLOR_SPACE_COLOR = 1,
-} NodeImageColorSpace;
-
typedef enum NodeImageProjection {
NODE_IMAGE_PROJ_FLAT = 0,
NODE_IMAGE_PROJ_BOX = 1,
@@ -385,6 +380,11 @@ typedef enum NodeImageProjection {
NODE_IMAGE_PROJ_TUBE = 3,
} NodeImageProjection;
+typedef enum NodeImageFlags {
+ NODE_IMAGE_COMPRESS_AS_SRGB = 1,
+ NODE_IMAGE_ALPHA_UNASSOCIATE = 2,
+} NodeImageFlags;
+
typedef enum NodeEnvironmentProjection {
NODE_ENVIRONMENT_EQUIRECTANGULAR = 0,
NODE_ENVIRONMENT_MIRROR_BALL = 1,
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index 378957d21f4..c79e5a23ea1 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -14,6 +14,7 @@ set(SRC
bake.cpp
buffers.cpp
camera.cpp
+ colorspace.cpp
constant_fold.cpp
coverage.cpp
denoising.cpp
@@ -48,6 +49,7 @@ set(SRC_HEADERS
background.h
buffers.h
camera.h
+ colorspace.h
constant_fold.h
coverage.h
denoising.h
diff --git a/intern/cycles/render/colorspace.cpp b/intern/cycles/render/colorspace.cpp
new file mode 100644
index 00000000000..f4c217bc9fb
--- /dev/null
+++ b/intern/cycles/render/colorspace.cpp
@@ -0,0 +1,410 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "render/colorspace.h"
+
+#include "util/util_color.h"
+#include "util/util_image.h"
+#include "util/util_half.h"
+#include "util/util_logging.h"
+#include "util/util_math.h"
+#include "util/util_thread.h"
+#include "util/util_vector.h"
+
+#ifdef WITH_OCIO
+# include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/* Builtin colorspaces. */
+ustring u_colorspace_auto;
+ustring u_colorspace_raw("__builtin_raw");
+ustring u_colorspace_srgb("__builtin_srgb");
+
+/* Cached data. */
+#ifdef WITH_OCIO
+static thread_mutex cache_colorspaces_mutex;
+static thread_mutex cache_processors_mutex;
+static unordered_map<ustring, ustring, ustringHash> cached_colorspaces;
+static unordered_map<ustring, OCIO::ConstProcessorRcPtr, ustringHash> cached_processors;
+#endif
+
+ColorSpaceProcessor *ColorSpaceManager::get_processor(ustring colorspace)
+{
+#ifdef WITH_OCIO
+ /* Only use this for OpenColorIO color spaces, not the builtin ones. */
+ assert(colorspace != u_colorspace_srgb && colorspace != u_colorspace_auto);
+
+ if (colorspace == u_colorspace_raw) {
+ return NULL;
+ }
+
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ if (!config) {
+ return NULL;
+ }
+
+ /* Cache processor until free_memory(), memory overhead is expected to be
+ * small and the processor is likely to be reused. */
+ thread_scoped_lock cache_processors_lock(cache_processors_mutex);
+ if (cached_processors.find(colorspace) == cached_processors.end()) {
+ try {
+ cached_processors[colorspace] = config->getProcessor(colorspace.c_str(), "scene_linear");
+ }
+ catch (OCIO::Exception &exception) {
+ cached_processors[colorspace] = OCIO::ConstProcessorRcPtr();
+ VLOG(1) << "Colorspace " << colorspace.c_str()
+ << " can't be converted to scene_linear: " << exception.what();
+ }
+ }
+
+ const OCIO::Processor *processor = cached_processors[colorspace].get();
+ return (ColorSpaceProcessor *)processor;
+#else
+ /* No OpenColorIO. */
+ (void)colorspace;
+ return NULL;
+#endif
+}
+
+bool ColorSpaceManager::colorspace_is_data(ustring colorspace)
+{
+ if (colorspace == u_colorspace_auto || colorspace == u_colorspace_raw ||
+ colorspace == u_colorspace_srgb) {
+ return false;
+ }
+
+#ifdef WITH_OCIO
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ if (!config) {
+ return false;
+ }
+
+ try {
+ OCIO::ConstColorSpaceRcPtr space = config->getColorSpace(colorspace.c_str());
+ return space && space->isData();
+ }
+ catch (OCIO::Exception &exception) {
+ return false;
+ }
+#else
+ return false;
+#endif
+}
+
+ustring ColorSpaceManager::detect_known_colorspace(ustring colorspace,
+ const char *file_format,
+ bool is_float)
+{
+ if (colorspace == u_colorspace_auto) {
+ /* Auto detect sRGB or raw if none specified. */
+ if (is_float) {
+ bool srgb = (colorspace == "sRGB" || colorspace == "GammaCorrected" ||
+ (colorspace.empty() &&
+ (strcmp(file_format, "png") == 0 || strcmp(file_format, "tiff") == 0 ||
+ strcmp(file_format, "dpx") == 0 || strcmp(file_format, "jpeg2000") == 0)));
+ return srgb ? u_colorspace_srgb : u_colorspace_raw;
+ }
+ else {
+ return u_colorspace_srgb;
+ }
+ }
+ else if (colorspace == u_colorspace_srgb || colorspace == u_colorspace_raw) {
+ /* Builtin colorspaces. */
+ return colorspace;
+ }
+ else {
+ /* Use OpenColorIO. */
+#ifdef WITH_OCIO
+ {
+ thread_scoped_lock cache_lock(cache_colorspaces_mutex);
+ /* Cached lookup. */
+ if (cached_colorspaces.find(colorspace) != cached_colorspaces.end()) {
+ return cached_colorspaces[colorspace];
+ }
+ }
+
+ /* Detect if it matches a simple builtin colorspace. */
+ bool is_scene_linear, is_srgb;
+ is_builtin_colorspace(colorspace, is_scene_linear, is_srgb);
+
+ thread_scoped_lock cache_lock(cache_colorspaces_mutex);
+ if (is_scene_linear) {
+ VLOG(1) << "Colorspace " << colorspace.string() << " is no-op";
+ cached_colorspaces[colorspace] = u_colorspace_raw;
+ return u_colorspace_raw;
+ }
+ else if (is_srgb) {
+ VLOG(1) << "Colorspace " << colorspace.string() << " is sRGB";
+ cached_colorspaces[colorspace] = u_colorspace_srgb;
+ return u_colorspace_srgb;
+ }
+
+ /* Verify if we can convert from the requested color space. */
+ if (!get_processor(colorspace)) {
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ if (!config || !config->getColorSpace(colorspace.c_str())) {
+ VLOG(1) << "Colorspace " << colorspace.c_str() << " not found, using raw instead";
+ }
+ else {
+ VLOG(1) << "Colorspace " << colorspace.c_str()
+ << " can't be converted to scene_linear, using raw instead";
+ }
+ cached_colorspaces[colorspace] = u_colorspace_raw;
+ return u_colorspace_raw;
+ }
+
+ /* Convert to/from colorspace with OpenColorIO. */
+ VLOG(1) << "Colorspace " << colorspace.string() << " handled through OpenColorIO";
+ cached_colorspaces[colorspace] = colorspace;
+ return colorspace;
+#else
+ VLOG(1) << "Colorspace " << colorspace.c_str() << " not available, built without OpenColorIO";
+ return u_colorspace_raw;
+#endif
+ }
+}
+
+void ColorSpaceManager::is_builtin_colorspace(ustring colorspace,
+ bool &is_scene_linear,
+ bool &is_srgb)
+{
+#ifdef WITH_OCIO
+ const OCIO::Processor *processor = (const OCIO::Processor *)get_processor(colorspace);
+ if (!processor) {
+ is_scene_linear = false;
+ is_srgb = false;
+ return;
+ }
+
+ is_scene_linear = true;
+ is_srgb = true;
+ for (int i = 0; i < 256; i++) {
+ float v = i / 255.0f;
+
+ float cR[3] = {v, 0, 0};
+ float cG[3] = {0, v, 0};
+ float cB[3] = {0, 0, v};
+ float cW[3] = {v, v, v};
+ processor->applyRGB(cR);
+ processor->applyRGB(cG);
+ processor->applyRGB(cB);
+ processor->applyRGB(cW);
+
+ /* Make sure that there is no channel crosstalk. */
+ if (fabsf(cR[1]) > 1e-5f || fabsf(cR[2]) > 1e-5f || fabsf(cG[0]) > 1e-5f ||
+ fabsf(cG[2]) > 1e-5f || fabsf(cB[0]) > 1e-5f || fabsf(cB[1]) > 1e-5f) {
+ is_scene_linear = false;
+ is_srgb = false;
+ break;
+ }
+ /* Make sure that the three primaries combine linearly. */
+ if (!compare_floats(cR[0], cW[0], 1e-6f, 64) || !compare_floats(cG[1], cW[1], 1e-6f, 64) ||
+ !compare_floats(cB[2], cW[2], 1e-6f, 64)) {
+ is_scene_linear = false;
+ is_srgb = false;
+ break;
+ }
+ /* Make sure that the three channels behave identically. */
+ if (!compare_floats(cW[0], cW[1], 1e-6f, 64) || !compare_floats(cW[1], cW[2], 1e-6f, 64)) {
+ is_scene_linear = false;
+ is_srgb = false;
+ break;
+ }
+
+ float out_v = average(make_float3(cW[0], cW[1], cW[2]));
+ if (!compare_floats(v, out_v, 1e-6f, 64)) {
+ is_scene_linear = false;
+ }
+ if (!compare_floats(color_srgb_to_linear(v), out_v, 1e-6f, 64)) {
+ is_srgb = false;
+ }
+ }
+#else
+ (void)colorspace;
+ is_scene_linear = false;
+ is_srgb = false;
+#endif
+}
+
+#ifdef WITH_OCIO
+
+template<typename T> inline float4 cast_to_float4(T *data)
+{
+ return make_float4(util_image_cast_to_float(data[0]),
+ util_image_cast_to_float(data[1]),
+ util_image_cast_to_float(data[2]),
+ util_image_cast_to_float(data[3]));
+}
+
+template<typename T> inline void cast_from_float4(T *data, float4 value)
+{
+ data[0] = util_image_cast_from_float<T>(value.x);
+ data[1] = util_image_cast_from_float<T>(value.y);
+ data[2] = util_image_cast_from_float<T>(value.z);
+ data[3] = util_image_cast_from_float<T>(value.w);
+}
+
+/* Slower versions for other all data types, which needs to convert to float and back. */
+template<typename T, bool compress_as_srgb = false>
+inline void processor_apply_pixels(const OCIO::Processor *processor,
+ T *pixels,
+ size_t width,
+ size_t height)
+{
+ /* TODO: implement faster version for when we know the conversion
+ * is a simple matrix transform between linear spaces. In that case
+ * unpremultiply is not needed. */
+
+ /* Process large images in chunks to keep temporary memory requirement down. */
+ size_t y_chunk_size = max(1, 16 * 1024 * 1024 / (sizeof(float4) * width));
+ vector<float4> float_pixels(y_chunk_size * width);
+
+ for (size_t y0 = 0; y0 < height; y0 += y_chunk_size) {
+ size_t y1 = std::min(y0 + y_chunk_size, height);
+ size_t i = 0;
+
+ for (size_t y = y0; y < y1; y++) {
+ for (size_t x = 0; x < width; x++, i++) {
+ float4 value = cast_to_float4(pixels + 4 * (y * width + x));
+
+ if (!(value.w == 0.0f || value.w == 1.0f)) {
+ float inv_alpha = 1.0f / value.w;
+ value.x *= inv_alpha;
+ value.y *= inv_alpha;
+ value.z *= inv_alpha;
+ }
+
+ float_pixels[i] = value;
+ }
+ }
+
+ OCIO::PackedImageDesc desc((float *)float_pixels.data(), width, y_chunk_size, 4);
+ processor->apply(desc);
+
+ i = 0;
+ for (size_t y = y0; y < y1; y++) {
+ for (size_t x = 0; x < width; x++, i++) {
+ float4 value = float_pixels[i];
+
+ value.x *= value.w;
+ value.y *= value.w;
+ value.z *= value.w;
+
+ if (compress_as_srgb) {
+ value = color_linear_to_srgb_v4(value);
+ }
+
+ cast_from_float4(pixels + 4 * (y * width + x), value);
+ }
+ }
+ }
+}
+#endif
+
+template<typename T>
+void ColorSpaceManager::to_scene_linear(ustring colorspace,
+ T *pixels,
+ size_t width,
+ size_t height,
+ size_t depth,
+ bool compress_as_srgb)
+{
+#ifdef WITH_OCIO
+ const OCIO::Processor *processor = (const OCIO::Processor *)get_processor(colorspace);
+
+ if (processor) {
+ if (compress_as_srgb) {
+ /* Compress output as sRGB. */
+ for (size_t z = 0; z < depth; z++) {
+ processor_apply_pixels<T, true>(processor, &pixels[z * width * height], width, height);
+ }
+ }
+ else {
+ /* Write output as scene linear directly. */
+ for (size_t z = 0; z < depth; z++) {
+ processor_apply_pixels<T>(processor, &pixels[z * width * height], width, height);
+ }
+ }
+ }
+#else
+ (void)colorspace;
+ (void)pixels;
+ (void)width;
+ (void)height;
+ (void)depth;
+ (void)compress_as_srgb;
+#endif
+}
+
+void ColorSpaceManager::to_scene_linear(ColorSpaceProcessor *processor_,
+ float *pixel,
+ int channels)
+{
+#ifdef WITH_OCIO
+ const OCIO::Processor *processor = (const OCIO::Processor *)processor_;
+
+ if (processor) {
+ if (channels == 3) {
+ processor->applyRGB(pixel);
+ }
+ else if (channels == 4) {
+ if (pixel[3] == 1.0f || pixel[3] == 0.0f) {
+ /* Fast path for RGBA. */
+ processor->applyRGB(pixel);
+ }
+ else {
+ /* Unassociate and associate alpha since color management should not
+ * be affected by transparency. */
+ float alpha = pixel[3];
+ float inv_alpha = 1.0f / alpha;
+
+ pixel[0] *= inv_alpha;
+ pixel[1] *= inv_alpha;
+ pixel[2] *= inv_alpha;
+
+ processor->applyRGB(pixel);
+
+ pixel[0] *= alpha;
+ pixel[1] *= alpha;
+ pixel[2] *= alpha;
+ }
+ }
+ }
+#else
+ (void)processor_;
+ (void)pixel;
+ (void)channels;
+#endif
+}
+
+void ColorSpaceManager::free_memory()
+{
+#ifdef WITH_OCIO
+ map_free_memory(cached_colorspaces);
+ map_free_memory(cached_colorspaces);
+#endif
+}
+
+/* Template instanstations so we don't have to inline functions. */
+template void ColorSpaceManager::to_scene_linear(ustring, uchar *, size_t, size_t, size_t, bool);
+template void ColorSpaceManager::to_scene_linear(ustring, ushort *, size_t, size_t, size_t, bool);
+template void ColorSpaceManager::to_scene_linear(ustring, half *, size_t, size_t, size_t, bool);
+template void ColorSpaceManager::to_scene_linear(ustring, float *, size_t, size_t, size_t, bool);
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/colorspace.h b/intern/cycles/render/colorspace.h
new file mode 100644
index 00000000000..9fea2d6efc6
--- /dev/null
+++ b/intern/cycles/render/colorspace.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __COLORSPACE_H__
+#define __COLORSPACE_H__
+
+#include "util/util_map.h"
+#include "util/util_param.h"
+
+CCL_NAMESPACE_BEGIN
+
+extern ustring u_colorspace_auto;
+extern ustring u_colorspace_raw;
+extern ustring u_colorspace_srgb;
+
+class ColorSpaceProcessor;
+
+class ColorSpaceManager {
+ public:
+ /* Convert used specified colorspace to a colorspace that we are able to
+ * convert to and from. If the colorspace is u_colorspace_auto, we auto
+ * detect a colospace. */
+ static ustring detect_known_colorspace(ustring colorspace,
+ const char *file_format,
+ bool is_float);
+
+ /* Test if colorspace is for non-color data. */
+ static bool colorspace_is_data(ustring colorspace);
+
+ /* Convert pixels in the specified colorspace to scene linear color for
+ * rendering. Must be a colorspace returned from detect_known_colorspace. */
+ template<typename T>
+ static void to_scene_linear(ustring colorspace,
+ T *pixels,
+ size_t width,
+ size_t height,
+ size_t depth,
+ bool compress_as_srgb);
+
+ /* Efficiently convert pixels to scene linear colorspace at render time,
+ * for OSL where the image texture cache contains original pixels. The
+ * handle is valid for the lifetime of the application. */
+ static ColorSpaceProcessor *get_processor(ustring colorspace);
+ static void to_scene_linear(ColorSpaceProcessor *processor, float *pixel, int channels);
+
+ /* Clear memory when the application exits. Invalidates all processors. */
+ static void free_memory();
+
+ private:
+ static void is_builtin_colorspace(ustring colorspace, bool &is_no_op, bool &is_srgb);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __COLORSPACE_H__ */
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
index e5fd39f08b7..9203c4468d2 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -127,6 +127,12 @@ ShaderOutput *ShaderNode::output(ustring name)
return NULL;
}
+void ShaderNode::remove_input(ShaderInput *input)
+{
+ assert(input->link == NULL);
+ inputs.erase(remove(inputs.begin(), inputs.end(), input), inputs.end());
+}
+
void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
foreach (ShaderInput *input, inputs) {
@@ -297,6 +303,28 @@ void ShaderGraph::disconnect(ShaderInput *to)
from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end());
}
+void ShaderGraph::relink(ShaderInput *from, ShaderInput *to)
+{
+ ShaderOutput *out = from->link;
+ if (out) {
+ disconnect(from);
+ connect(out, to);
+ }
+ to->parent->copy_value(to->socket_type, *(from->parent), from->socket_type);
+}
+
+void ShaderGraph::relink(ShaderOutput *from, ShaderOutput *to)
+{
+ /* Copy because disconnect modifies this list. */
+ vector<ShaderInput *> outputs = from->links;
+
+ foreach (ShaderInput *sock, outputs) {
+ disconnect(sock);
+ if (to)
+ connect(to, sock);
+ }
+}
+
void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to)
{
simplified = false;
@@ -320,6 +348,7 @@ void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to)
void ShaderGraph::simplify(Scene *scene)
{
if (!simplified) {
+ expand();
default_inputs(scene->shader_manager->use_osl());
clean(scene);
refine_bump_nodes();
@@ -780,6 +809,14 @@ void ShaderGraph::clean(Scene *scene)
nodes = newnodes;
}
+void ShaderGraph::expand()
+{
+ /* Call expand on all nodes, to generate additional nodes. */
+ foreach (ShaderNode *node, nodes) {
+ node->expand(this);
+ }
+}
+
void ShaderGraph::default_inputs(bool do_osl)
{
/* nodes can specify default texture coordinates, for now we give
diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h
index b1aa5cf3168..cade04de374 100644
--- a/intern/cycles/render/graph.h
+++ b/intern/cycles/render/graph.h
@@ -147,6 +147,7 @@ class ShaderNode : public Node {
virtual ~ShaderNode();
void create_inputs_outputs(const NodeType *type);
+ void remove_input(ShaderInput *input);
ShaderInput *input(const char *name);
ShaderOutput *output(const char *name);
@@ -158,6 +159,11 @@ class ShaderNode : public Node {
virtual void compile(SVMCompiler &compiler) = 0;
virtual void compile(OSLCompiler &compiler) = 0;
+ /* Expand node into additional nodes. */
+ virtual void expand(ShaderGraph * /* graph */)
+ {
+ }
+
/* ** Node optimization ** */
/* Check whether the node can be replaced with single constant. */
virtual void constant_fold(const ConstantFolder & /*folder*/)
@@ -322,6 +328,8 @@ class ShaderGraph {
void connect(ShaderOutput *from, ShaderInput *to);
void disconnect(ShaderOutput *from);
void disconnect(ShaderInput *to);
+ void relink(ShaderInput *from, ShaderInput *to);
+ void relink(ShaderOutput *from, ShaderOutput *to);
void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to);
void remove_proxy_nodes();
@@ -346,6 +354,7 @@ class ShaderGraph {
void break_cycles(ShaderNode *node, vector<bool> &visited, vector<bool> &on_stack);
void bump_from_displacement(bool use_object_space);
void refine_bump_nodes();
+ void expand();
void default_inputs(bool do_osl);
void transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume);
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index ae219e912e0..160e7d9ff1e 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -14,12 +14,14 @@
* limitations under the License.
*/
-#include "device/device.h"
#include "render/image.h"
+#include "device/device.h"
+#include "render/colorspace.h"
#include "render/scene.h"
#include "render/stats.h"
#include "util/util_foreach.h"
+#include "util/util_image_impl.h"
#include "util/util_logging.h"
#include "util/util_path.h"
#include "util/util_progress.h"
@@ -164,11 +166,45 @@ bool ImageManager::get_image_metadata(int flat_slot, ImageMetaData &metadata)
return false;
}
+void ImageManager::metadata_detect_colorspace(ImageMetaData &metadata, const char *file_format)
+{
+ /* Convert used specified color spaces to one we know how to handle. */
+ metadata.colorspace = ColorSpaceManager::detect_known_colorspace(
+ metadata.colorspace, file_format, metadata.is_float || metadata.is_half);
+
+ if (metadata.colorspace == u_colorspace_raw) {
+ /* Nothing to do. */
+ }
+ else if (metadata.colorspace == u_colorspace_srgb) {
+ /* Keep sRGB colorspace stored as sRGB, to save memory and/or loading time
+ * for the common case of 8bit sRGB images like PNG. */
+ metadata.compress_as_srgb = true;
+ }
+ else {
+ /* Always compress non-raw 8bit images as scene linear + sRGB, as a
+ * heuristic to keep memory usage the same without too much data loss
+ * due to quantization in common cases. */
+ metadata.compress_as_srgb = (metadata.type == IMAGE_DATA_TYPE_BYTE ||
+ metadata.type == IMAGE_DATA_TYPE_BYTE4);
+
+ /* If colorspace conversion needed, use half instead of short so we can
+ * represent HDR values that might result from conversion. */
+ if (metadata.type == IMAGE_DATA_TYPE_USHORT) {
+ metadata.type = IMAGE_DATA_TYPE_HALF;
+ }
+ else if (metadata.type == IMAGE_DATA_TYPE_USHORT4) {
+ metadata.type = IMAGE_DATA_TYPE_HALF4;
+ }
+ }
+}
+
bool ImageManager::get_image_metadata(const string &filename,
void *builtin_data,
+ ustring colorspace,
ImageMetaData &metadata)
{
- memset(&metadata, 0, sizeof(metadata));
+ metadata = ImageMetaData();
+ metadata.colorspace = colorspace;
if (builtin_data) {
if (builtin_image_info_cb) {
@@ -179,13 +215,14 @@ bool ImageManager::get_image_metadata(const string &filename,
}
if (metadata.is_float) {
- metadata.is_linear = true;
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
}
else {
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
}
+ metadata_detect_colorspace(metadata, "");
+
return true;
}
@@ -213,20 +250,19 @@ bool ImageManager::get_image_metadata(const string &filename,
metadata.width = spec.width;
metadata.height = spec.height;
metadata.depth = spec.depth;
+ metadata.compress_as_srgb = false;
/* Check the main format, and channel formats. */
size_t channel_size = spec.format.basesize();
if (spec.format.is_floating_point()) {
metadata.is_float = true;
- metadata.is_linear = true;
}
for (size_t channel = 0; channel < spec.channelformats.size(); channel++) {
channel_size = max(channel_size, spec.channelformats[channel].basesize());
if (spec.channelformats[channel].is_floating_point()) {
metadata.is_float = true;
- metadata.is_linear = true;
}
}
@@ -235,21 +271,6 @@ bool ImageManager::get_image_metadata(const string &filename,
metadata.is_half = true;
}
- /* basic color space detection, not great but better than nothing
- * before we do OpenColorIO integration */
- if (metadata.is_float) {
- string colorspace = spec.get_string_attribute("oiio:ColorSpace");
-
- metadata.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 {
- metadata.is_linear = false;
- }
-
/* set type and channels */
metadata.channels = spec.nchannels;
@@ -266,6 +287,8 @@ bool ImageManager::get_image_metadata(const string &filename,
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
}
+ metadata_detect_colorspace(metadata, in->format_name());
+
in->close();
return true;
@@ -276,11 +299,12 @@ static bool image_equals(ImageManager::Image *image,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension,
- bool use_alpha)
+ ImageAlphaType alpha_type,
+ ustring colorspace)
{
return image->filename == filename && image->builtin_data == builtin_data &&
image->interpolation == interpolation && image->extension == extension &&
- image->use_alpha == use_alpha;
+ image->alpha_type == alpha_type && image->colorspace == colorspace;
}
int ImageManager::add_image(const string &filename,
@@ -289,13 +313,14 @@ int ImageManager::add_image(const string &filename,
float frame,
InterpolationType interpolation,
ExtensionType extension,
- bool use_alpha,
+ ImageAlphaType alpha_type,
+ ustring colorspace,
ImageMetaData &metadata)
{
Image *img;
size_t slot;
- get_image_metadata(filename, builtin_data, metadata);
+ get_image_metadata(filename, builtin_data, colorspace, metadata);
ImageDataType type = metadata.type;
thread_scoped_lock device_lock(device_mutex);
@@ -313,13 +338,19 @@ int ImageManager::add_image(const string &filename,
/* Fnd existing image. */
for (slot = 0; slot < images[type].size(); slot++) {
img = images[type][slot];
- if (img && image_equals(img, filename, builtin_data, interpolation, extension, use_alpha)) {
+ if (img &&
+ image_equals(
+ img, filename, builtin_data, interpolation, extension, alpha_type, colorspace)) {
if (img->frame != frame) {
img->frame = frame;
img->need_load = true;
}
- if (img->use_alpha != use_alpha) {
- img->use_alpha = use_alpha;
+ if (img->alpha_type != alpha_type) {
+ img->alpha_type = alpha_type;
+ img->need_load = true;
+ }
+ if (img->colorspace != colorspace) {
+ img->colorspace = colorspace;
img->need_load = true;
}
if (!(img->metadata == metadata)) {
@@ -369,7 +400,8 @@ int ImageManager::add_image(const string &filename,
img->interpolation = interpolation;
img->extension = extension;
img->users = 1;
- img->use_alpha = use_alpha;
+ img->alpha_type = alpha_type;
+ img->colorspace = colorspace;
img->mem = NULL;
images[type][slot] = img;
@@ -381,6 +413,17 @@ int ImageManager::add_image(const string &filename,
return type_index_to_flattened_slot(slot, type);
}
+void ImageManager::add_image_user(int flat_slot)
+{
+ ImageDataType type;
+ int slot = flattened_slot_to_type_index(flat_slot, &type);
+
+ Image *image = images[type][slot];
+ assert(image && image->users >= 1);
+
+ image->users++;
+}
+
void ImageManager::remove_image(int flat_slot)
{
ImageDataType type;
@@ -403,15 +446,20 @@ void ImageManager::remove_image(const string &filename,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension,
- bool use_alpha)
+ ImageAlphaType alpha_type,
+ ustring colorspace)
{
size_t slot;
for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
for (slot = 0; slot < images[type].size(); slot++) {
- if (images[type][slot] &&
- image_equals(
- images[type][slot], filename, builtin_data, interpolation, extension, use_alpha)) {
+ if (images[type][slot] && image_equals(images[type][slot],
+ filename,
+ builtin_data,
+ interpolation,
+ extension,
+ alpha_type,
+ colorspace)) {
remove_image(type_index_to_flattened_slot(slot, (ImageDataType)type));
return;
}
@@ -427,13 +475,18 @@ void ImageManager::tag_reload_image(const string &filename,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension,
- bool use_alpha)
+ ImageAlphaType alpha_type,
+ ustring colorspace)
{
for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
for (size_t slot = 0; slot < images[type].size(); slot++) {
- if (images[type][slot] &&
- image_equals(
- images[type][slot], filename, builtin_data, interpolation, extension, use_alpha)) {
+ if (images[type][slot] && image_equals(images[type][slot],
+ filename,
+ builtin_data,
+ interpolation,
+ extension,
+ alpha_type,
+ colorspace)) {
images[type][slot]->need_load = true;
break;
}
@@ -461,8 +514,15 @@ bool ImageManager::file_load_image_generic(Image *img, unique_ptr<ImageInput> *i
ImageSpec spec = ImageSpec();
ImageSpec config = ImageSpec();
- if (img->use_alpha == false)
+ /* For typical RGBA images we let OIIO convert to associated alpha,
+ * but some types we want to leave the RGB channels untouched. */
+ const bool associate_alpha = !(ColorSpaceManager::colorspace_is_data(img->colorspace) ||
+ img->alpha_type == IMAGE_ALPHA_IGNORE ||
+ img->alpha_type == IMAGE_ALPHA_CHANNEL_PACKED);
+
+ if (!associate_alpha) {
config.attribute("oiio:UnassociatedAlpha", 1);
+ }
if (!(*in)->open(img->filename, spec, config)) {
return false;
@@ -502,14 +562,16 @@ bool ImageManager::file_load_image(Image *img,
int depth = img->metadata.depth;
int components = img->metadata.channels;
- /* Read RGBA pixels. */
+ /* Read pixels. */
vector<StorageType> pixels_storage;
StorageType *pixels;
const size_t max_size = max(max(width, height), depth);
if (max_size == 0) {
- /* Don't bother with invalid images. */
+ /* Don't bother with empty images. */
return false;
}
+
+ /* Allocate memory as needed, may be smaller to resize down. */
if (texture_limit > 0 && max_size > texture_limit) {
pixels_storage.resize(((size_t)width) * height * depth * 4);
pixels = &pixels_storage[0];
@@ -518,19 +580,23 @@ bool ImageManager::file_load_image(Image *img,
thread_scoped_lock device_lock(device_mutex);
pixels = (StorageType *)tex_img.alloc(width, height, depth);
}
+
if (pixels == NULL) {
/* Could be that we've run out of memory. */
return false;
}
+
bool cmyk = false;
const size_t num_pixels = ((size_t)width) * height * depth;
if (in) {
+ /* Read pixels through OpenImageIO. */
StorageType *readpixels = pixels;
vector<StorageType> tmppixels;
if (components > 4) {
tmppixels.resize(((size_t)width) * height * components);
readpixels = &tmppixels[0];
}
+
if (depth <= 1) {
size_t scanlinesize = ((size_t)width) * components * sizeof(StorageType);
in->read_image(FileFormat,
@@ -542,6 +608,7 @@ bool ImageManager::file_load_image(Image *img,
else {
in->read_image(FileFormat, (uchar *)readpixels);
}
+
if (components > 4) {
size_t dimensions = ((size_t)width) * height;
for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) {
@@ -552,10 +619,12 @@ bool ImageManager::file_load_image(Image *img,
}
tmppixels.clear();
}
+
cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4;
in->close();
}
else {
+ /* Read pixels through callback. */
if (FileFormat == TypeDesc::FLOAT) {
builtin_image_float_pixels_cb(img->filename,
img->builtin_data,
@@ -574,16 +643,17 @@ bool ImageManager::file_load_image(Image *img,
/* TODO(dingto): Support half for ImBuf. */
}
}
- /* Check if we actually have a float4 slot, in case components == 1,
- * but device doesn't support single channel textures.
- */
+
+ /* The kernel can handle 1 and 4 channel images. Anything that is not a single
+ * channel image is converted to RGBA format. */
bool is_rgba = (type == IMAGE_DATA_TYPE_FLOAT4 || type == IMAGE_DATA_TYPE_HALF4 ||
type == IMAGE_DATA_TYPE_BYTE4 || type == IMAGE_DATA_TYPE_USHORT4);
+
if (is_rgba) {
const StorageType one = util_image_cast_from_float<StorageType>(1.0f);
if (cmyk) {
- /* CMYK */
+ /* CMYK to RGBA. */
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
float c = util_image_cast_to_float(pixels[i * 4 + 0]);
float m = util_image_cast_to_float(pixels[i * 4 + 1]);
@@ -596,7 +666,7 @@ bool ImageManager::file_load_image(Image *img,
}
}
else if (components == 2) {
- /* grayscale + alpha */
+ /* Grayscale + alpha to RGBA. */
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i * 4 + 3] = pixels[i * 2 + 1];
pixels[i * 4 + 2] = pixels[i * 2 + 0];
@@ -605,7 +675,7 @@ bool ImageManager::file_load_image(Image *img,
}
}
else if (components == 3) {
- /* RGB */
+ /* RGB to RGBA. */
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i * 4 + 3] = one;
pixels[i * 4 + 2] = pixels[i * 3 + 2];
@@ -614,7 +684,7 @@ bool ImageManager::file_load_image(Image *img,
}
}
else if (components == 1) {
- /* grayscale */
+ /* Grayscale to RGBA. */
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i * 4 + 3] = one;
pixels[i * 4 + 2] = pixels[i];
@@ -622,18 +692,27 @@ bool ImageManager::file_load_image(Image *img,
pixels[i * 4 + 0] = pixels[i];
}
}
- if (img->use_alpha == false) {
+
+ /* Disable alpha if requested by the user. */
+ if (img->alpha_type == IMAGE_ALPHA_IGNORE) {
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i * 4 + 3] = one;
}
}
+
+ if (img->metadata.colorspace != u_colorspace_raw &&
+ img->metadata.colorspace != u_colorspace_srgb) {
+ /* Convert to scene linear. */
+ ColorSpaceManager::to_scene_linear(
+ img->metadata.colorspace, pixels, width, height, depth, img->metadata.compress_as_srgb);
+ }
}
+
/* Make sure we don't have buggy values. */
if (FileFormat == TypeDesc::FLOAT) {
/* For RGBA buffers we put all channels to 0 if either of them is not
* finite. This way we avoid possible artifacts caused by fully changed
- * hue.
- */
+ * hue. */
if (is_rgba) {
for (size_t i = 0; i < num_pixels; i += 4) {
StorageType *pixel = &pixels[i * 4];
@@ -655,6 +734,7 @@ bool ImageManager::file_load_image(Image *img,
}
}
}
+
/* Scale image down if needed. */
if (pixels_storage.size() > 0) {
float scale_factor = 1.0f;
@@ -684,6 +764,7 @@ bool ImageManager::file_load_image(Image *img,
memcpy(texture_pixels, &scaled_pixels[0], scaled_pixels.size() * sizeof(StorageType));
}
+
return true;
}
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index 34f046692f6..ed2780f8471 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -20,6 +20,8 @@
#include "device/device.h"
#include "device/device_memory.h"
+#include "render/colorspace.h"
+
#include "util/util_image.h"
#include "util/util_string.h"
#include "util/util_thread.h"
@@ -32,6 +34,7 @@ class Device;
class Progress;
class RenderStats;
class Scene;
+class ColorSpaceProcessor;
class ImageMetaData {
public:
@@ -43,13 +46,29 @@ class ImageMetaData {
/* Automatically set. */
ImageDataType type;
- bool is_linear;
+ ustring colorspace;
+ bool compress_as_srgb;
+
+ ImageMetaData()
+ : is_float(false),
+ is_half(false),
+ channels(0),
+ width(0),
+ height(0),
+ depth(0),
+ builtin_free_cache(false),
+ type((ImageDataType)0),
+ colorspace(u_colorspace_raw),
+ compress_as_srgb(false)
+ {
+ }
bool operator==(const ImageMetaData &other) const
{
return is_float == other.is_float && is_half == other.is_half && channels == other.channels &&
width == other.width && height == other.height && depth == other.depth &&
- type == other.type && is_linear == other.is_linear;
+ type == other.type && colorspace == other.colorspace &&
+ compress_as_srgb == other.compress_as_srgb;
}
};
@@ -64,20 +83,27 @@ class ImageManager {
float frame,
InterpolationType interpolation,
ExtensionType extension,
- bool use_alpha,
+ ImageAlphaType alpha_type,
+ ustring colorspace,
ImageMetaData &metadata);
+ void add_image_user(int flat_slot);
void remove_image(int flat_slot);
void remove_image(const string &filename,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension,
- bool use_alpha);
+ ImageAlphaType alpha_type,
+ ustring colorspace);
void tag_reload_image(const string &filename,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension,
- bool use_alpha);
- bool get_image_metadata(const string &filename, void *builtin_data, ImageMetaData &metadata);
+ ImageAlphaType alpha_type,
+ ustring colorspace);
+ bool get_image_metadata(const string &filename,
+ void *builtin_data,
+ ustring colorspace,
+ ImageMetaData &metadata);
bool get_image_metadata(int flat_slot, ImageMetaData &metadata);
void device_update(Device *device, Scene *scene, Progress &progress);
@@ -120,7 +146,8 @@ class ImageManager {
void *builtin_data;
ImageMetaData metadata;
- bool use_alpha;
+ ustring colorspace;
+ ImageAlphaType alpha_type;
bool need_load;
bool animated;
float frame;
@@ -152,6 +179,8 @@ class ImageManager {
int texture_limit,
device_vector<DeviceType> &tex_img);
+ void metadata_detect_colorspace(ImageMetaData &metadata, const char *file_format);
+
void device_load_image(
Device *device, Scene *scene, ImageDataType type, int slot, Progress *progress);
void device_free_image(Device *device, ImageDataType type, int slot);
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index d4c233e3bb3..5c3f1c35bdc 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -114,6 +114,8 @@ NODE_DEFINE(Light)
type_enum.insert("spot", LIGHT_SPOT);
SOCKET_ENUM(type, "Type", type_enum, LIGHT_POINT);
+ SOCKET_COLOR(strength, "Strength", make_float3(1.0f, 1.0f, 1.0f));
+
SOCKET_POINT(co, "Co", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_VECTOR(dir, "Dir", make_float3(0.0f, 0.0f, 0.0f));
@@ -162,6 +164,9 @@ void Light::tag_update(Scene *scene)
bool Light::has_contribution(Scene *scene)
{
+ if (strength == make_float3(0.0f, 0.0f, 0.0f)) {
+ return false;
+ }
if (is_portal) {
return false;
}
@@ -393,11 +398,18 @@ void LightManager::device_update_distribution(Device *,
distribution[offset].lamp.size = light->size;
totarea += lightarea;
- if (light->size > 0.0f && light->use_mis)
- use_lamp_mis = true;
- if (light->type == LIGHT_BACKGROUND) {
+ if (light->type == LIGHT_DISTANT) {
+ use_lamp_mis |= (light->angle > 0.0f && light->use_mis);
+ }
+ else if (light->type == LIGHT_POINT || light->type == LIGHT_SPOT) {
+ use_lamp_mis |= (light->size > 0.0f && light->use_mis);
+ }
+ else if (light->type == LIGHT_AREA) {
+ use_lamp_mis |= light->use_mis;
+ }
+ else if (light->type == LIGHT_BACKGROUND) {
num_background_lights++;
- background_mis = light->use_mis;
+ background_mis |= light->use_mis;
}
light_index++;
@@ -672,7 +684,6 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
float3 co = light->co;
Shader *shader = (light->shader) ? light->shader : scene->default_light;
int shader_id = scene->shader_manager->get_shader_id(shader);
- int samples = light->samples;
int max_bounces = light->max_bounces;
float random = (float)light->random_id * (1.0f / (float)0xFFFFFFFF);
@@ -697,7 +708,10 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
}
klights[light_index].type = light->type;
- klights[light_index].samples = samples;
+ klights[light_index].samples = light->samples;
+ klights[light_index].strength[0] = light->strength.x;
+ klights[light_index].strength[1] = light->strength.y;
+ klights[light_index].strength[2] = light->strength.z;
if (light->type == LIGHT_POINT) {
shader_id &= ~SHADER_AREA_LIGHT;
@@ -718,8 +732,8 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
else if (light->type == LIGHT_DISTANT) {
shader_id &= ~SHADER_AREA_LIGHT;
- float radius = light->size;
- float angle = atanf(radius);
+ float angle = light->angle / 2.0f;
+ float radius = tanf(angle);
float cosangle = cosf(angle);
float area = M_PI_F * radius * radius;
float invarea = (area > 0.0f) ? 1.0f / area : 1.0f;
diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h
index 66732000f3b..79450ea5f8d 100644
--- a/intern/cycles/render/light.h
+++ b/intern/cycles/render/light.h
@@ -42,10 +42,12 @@ class Light : public Node {
Light();
LightType type;
+ float3 strength;
float3 co;
float3 dir;
float size;
+ float angle;
float3 axisu;
float sizeu;
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 16416a9a009..c5b0f6a1e79 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "render/colorspace.h"
#include "render/film.h"
#include "render/image.h"
#include "render/integrator.h"
@@ -207,13 +208,15 @@ NODE_DEFINE(ImageTextureNode)
TEXTURE_MAPPING_DEFINE(ImageTextureNode);
SOCKET_STRING(filename, "Filename", ustring());
+ SOCKET_STRING(colorspace, "Colorspace", u_colorspace_auto);
- static NodeEnum color_space_enum;
- color_space_enum.insert("none", NODE_COLOR_SPACE_NONE);
- color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR);
- SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR);
-
- SOCKET_BOOLEAN(use_alpha, "Use Alpha", true);
+ static NodeEnum alpha_type_enum;
+ alpha_type_enum.insert("auto", IMAGE_ALPHA_AUTO);
+ alpha_type_enum.insert("unassociated", IMAGE_ALPHA_UNASSOCIATED);
+ alpha_type_enum.insert("associated", IMAGE_ALPHA_ASSOCIATED);
+ alpha_type_enum.insert("channel_packed", IMAGE_ALPHA_CHANNEL_PACKED);
+ alpha_type_enum.insert("ignore", IMAGE_ALPHA_IGNORE);
+ SOCKET_ENUM(alpha_type, "Alpha Type", alpha_type_enum, IMAGE_ALPHA_AUTO);
static NodeEnum interpolation_enum;
interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
@@ -250,7 +253,8 @@ ImageTextureNode::ImageTextureNode() : ImageSlotTextureNode(node_type)
image_manager = NULL;
slot = -1;
is_float = -1;
- is_linear = false;
+ compress_as_srgb = false;
+ colorspace = u_colorspace_raw;
builtin_data = NULL;
animated = false;
}
@@ -259,18 +263,17 @@ ImageTextureNode::~ImageTextureNode()
{
if (image_manager) {
image_manager->remove_image(
- filename.string(), builtin_data, interpolation, extension, use_alpha);
+ filename.string(), builtin_data, interpolation, extension, alpha_type, colorspace);
}
}
ShaderNode *ImageTextureNode::clone() const
{
- ImageTextureNode *node = new ImageTextureNode(*this);
- node->image_manager = NULL;
- node->slot = -1;
- node->is_float = -1;
- node->is_linear = false;
- return node;
+ /* Increase image user count for new node. */
+ if (slot != -1) {
+ image_manager->add_image_user(slot);
+ }
+ return new ImageTextureNode(*this);
}
void ImageTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -303,15 +306,30 @@ void ImageTextureNode::compile(SVMCompiler &compiler)
0,
interpolation,
extension,
- use_alpha,
+ alpha_type,
+ colorspace,
metadata);
is_float = metadata.is_float;
- is_linear = metadata.is_linear;
+ compress_as_srgb = metadata.compress_as_srgb;
+ known_colorspace = metadata.colorspace;
}
if (slot != -1) {
- int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR) ? 0 : 1;
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+ uint flags = 0;
+
+ if (compress_as_srgb) {
+ flags |= NODE_IMAGE_COMPRESS_AS_SRGB;
+ }
+ if (!alpha_out->links.empty()) {
+ const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
+ alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
+ alpha_type == IMAGE_ALPHA_IGNORE);
+
+ if (unassociate_alpha) {
+ flags |= NODE_IMAGE_ALPHA_UNASSOCIATE;
+ }
+ }
if (projection != NODE_IMAGE_PROJ_BOX) {
compiler.add_node(NODE_TEX_IMAGE,
@@ -319,7 +337,7 @@ void ImageTextureNode::compile(SVMCompiler &compiler)
compiler.encode_uchar4(vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
- srgb),
+ flags),
projection);
}
else {
@@ -328,7 +346,7 @@ void ImageTextureNode::compile(SVMCompiler &compiler)
compiler.encode_uchar4(vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
- srgb),
+ flags),
__float_as_int(projection_blend));
}
@@ -358,7 +376,7 @@ void ImageTextureNode::compile(OSLCompiler &compiler)
if (is_float == -1) {
ImageMetaData metadata;
if (builtin_data == NULL) {
- image_manager->get_image_metadata(filename.string(), NULL, metadata);
+ image_manager->get_image_metadata(filename.string(), NULL, colorspace, metadata);
}
else {
slot = image_manager->add_image(filename.string(),
@@ -367,33 +385,32 @@ void ImageTextureNode::compile(OSLCompiler &compiler)
0,
interpolation,
extension,
- use_alpha,
+ alpha_type,
+ colorspace,
metadata);
}
is_float = metadata.is_float;
- is_linear = metadata.is_linear;
+ compress_as_srgb = metadata.compress_as_srgb;
+ known_colorspace = metadata.colorspace;
}
if (slot == -1) {
- compiler.parameter(this, "filename");
+ compiler.parameter_texture("filename", filename, known_colorspace);
}
else {
- /* TODO(sergey): It's not so simple to pass custom attribute
- * to the texture() function in order to make builtin images
- * support more clear. So we use special file name which is
- * "@i<slot_number>" and check whether file name matches this
- * mask in the OSLRenderServices::texture().
- */
- compiler.parameter("filename", string_printf("@i%d", slot).c_str());
+ compiler.parameter_texture("filename", slot);
}
- if (is_linear || color_space != NODE_COLOR_SPACE_COLOR)
- compiler.parameter("color_space", "linear");
- else
- compiler.parameter("color_space", "sRGB");
+
+ const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
+ alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
+ alpha_type == IMAGE_ALPHA_IGNORE);
+
compiler.parameter(this, "projection");
compiler.parameter(this, "projection_blend");
+ compiler.parameter("compress_as_srgb", compress_as_srgb);
+ compiler.parameter("ignore_alpha", alpha_type == IMAGE_ALPHA_IGNORE);
+ compiler.parameter("unassociate_alpha", !alpha_out->links.empty() && unassociate_alpha);
compiler.parameter("is_float", is_float);
- compiler.parameter("use_alpha", !alpha_out->links.empty());
compiler.parameter(this, "interpolation");
compiler.parameter(this, "extension");
@@ -409,13 +426,15 @@ NODE_DEFINE(EnvironmentTextureNode)
TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode);
SOCKET_STRING(filename, "Filename", ustring());
+ SOCKET_STRING(colorspace, "Colorspace", u_colorspace_auto);
- static NodeEnum color_space_enum;
- color_space_enum.insert("none", NODE_COLOR_SPACE_NONE);
- color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR);
- SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR);
-
- SOCKET_BOOLEAN(use_alpha, "Use Alpha", true);
+ static NodeEnum alpha_type_enum;
+ alpha_type_enum.insert("auto", IMAGE_ALPHA_AUTO);
+ alpha_type_enum.insert("unassociated", IMAGE_ALPHA_UNASSOCIATED);
+ alpha_type_enum.insert("associated", IMAGE_ALPHA_ASSOCIATED);
+ alpha_type_enum.insert("channel_packed", IMAGE_ALPHA_CHANNEL_PACKED);
+ alpha_type_enum.insert("ignore", IMAGE_ALPHA_IGNORE);
+ SOCKET_ENUM(alpha_type, "Alpha Type", alpha_type_enum, IMAGE_ALPHA_AUTO);
static NodeEnum interpolation_enum;
interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
@@ -442,7 +461,8 @@ EnvironmentTextureNode::EnvironmentTextureNode() : ImageSlotTextureNode(node_typ
image_manager = NULL;
slot = -1;
is_float = -1;
- is_linear = false;
+ compress_as_srgb = false;
+ colorspace = u_colorspace_raw;
builtin_data = NULL;
animated = false;
}
@@ -451,18 +471,17 @@ EnvironmentTextureNode::~EnvironmentTextureNode()
{
if (image_manager) {
image_manager->remove_image(
- filename.string(), builtin_data, interpolation, EXTENSION_REPEAT, use_alpha);
+ filename.string(), builtin_data, interpolation, EXTENSION_REPEAT, alpha_type, colorspace);
}
}
ShaderNode *EnvironmentTextureNode::clone() const
{
- EnvironmentTextureNode *node = new EnvironmentTextureNode(*this);
- node->image_manager = NULL;
- node->slot = -1;
- node->is_float = -1;
- node->is_linear = false;
- return node;
+ /* Increase image user count for new node. */
+ if (slot != -1) {
+ image_manager->add_image_user(slot);
+ }
+ return new EnvironmentTextureNode(*this);
}
void EnvironmentTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -493,22 +512,28 @@ void EnvironmentTextureNode::compile(SVMCompiler &compiler)
0,
interpolation,
EXTENSION_REPEAT,
- use_alpha,
+ alpha_type,
+ colorspace,
metadata);
is_float = metadata.is_float;
- is_linear = metadata.is_linear;
+ compress_as_srgb = metadata.compress_as_srgb;
+ known_colorspace = metadata.colorspace;
}
if (slot != -1) {
- int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR) ? 0 : 1;
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+ uint flags = 0;
+
+ if (compress_as_srgb) {
+ flags |= NODE_IMAGE_COMPRESS_AS_SRGB;
+ }
compiler.add_node(NODE_TEX_ENVIRONMENT,
slot,
compiler.encode_uchar4(vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
- srgb),
+ flags),
projection);
tex_mapping.compile_end(compiler, vector_in, vector_offset);
@@ -529,8 +554,6 @@ void EnvironmentTextureNode::compile(SVMCompiler &compiler)
void EnvironmentTextureNode::compile(OSLCompiler &compiler)
{
- ShaderOutput *alpha_out = output("Alpha");
-
tex_mapping.compile(compiler);
/* See comments in ImageTextureNode::compile about support
@@ -540,7 +563,7 @@ void EnvironmentTextureNode::compile(OSLCompiler &compiler)
if (is_float == -1) {
ImageMetaData metadata;
if (builtin_data == NULL) {
- image_manager->get_image_metadata(filename.string(), NULL, metadata);
+ image_manager->get_image_metadata(filename.string(), NULL, colorspace, metadata);
}
else {
slot = image_manager->add_image(filename.string(),
@@ -549,28 +572,27 @@ void EnvironmentTextureNode::compile(OSLCompiler &compiler)
0,
interpolation,
EXTENSION_REPEAT,
- use_alpha,
+ alpha_type,
+ colorspace,
metadata);
}
is_float = metadata.is_float;
- is_linear = metadata.is_linear;
+ compress_as_srgb = metadata.compress_as_srgb;
+ known_colorspace = metadata.colorspace;
}
if (slot == -1) {
- compiler.parameter(this, "filename");
+ compiler.parameter_texture("filename", filename, known_colorspace);
}
else {
- compiler.parameter("filename", string_printf("@i%d", slot).c_str());
+ compiler.parameter_texture("filename", slot);
}
- compiler.parameter(this, "projection");
- if (is_linear || color_space != NODE_COLOR_SPACE_COLOR)
- compiler.parameter("color_space", "linear");
- else
- compiler.parameter("color_space", "sRGB");
+ compiler.parameter(this, "projection");
compiler.parameter(this, "interpolation");
+ compiler.parameter("compress_as_srgb", compress_as_srgb);
+ compiler.parameter("ignore_alpha", alpha_type == IMAGE_ALPHA_IGNORE);
compiler.parameter("is_float", is_float);
- compiler.parameter("use_alpha", !alpha_out->links.empty());
compiler.add(this, "node_environment_texture");
}
@@ -1080,7 +1102,7 @@ void IESLightNode::compile(OSLCompiler &compiler)
tex_mapping.compile(compiler);
- compiler.parameter("slot", slot);
+ compiler.parameter_texture_ies("filename", slot);
compiler.add(this, "node_ies_light");
}
@@ -1482,17 +1504,24 @@ PointDensityTextureNode::PointDensityTextureNode() : ShaderNode(node_type)
PointDensityTextureNode::~PointDensityTextureNode()
{
if (image_manager) {
- image_manager->remove_image(
- filename.string(), builtin_data, interpolation, EXTENSION_CLIP, true);
+ image_manager->remove_image(filename.string(),
+ builtin_data,
+ interpolation,
+ EXTENSION_CLIP,
+ IMAGE_ALPHA_AUTO,
+ ustring());
}
}
ShaderNode *PointDensityTextureNode::clone() const
{
- PointDensityTextureNode *node = new PointDensityTextureNode(*this);
- node->image_manager = NULL;
- node->slot = -1;
- return node;
+ /* Increase image user count for new node. We need to ensure to not call
+ * add_image again, to work around access of freed data on the Blender
+ * side. A better solution should be found to avoid this. */
+ if (slot != -1) {
+ image_manager->add_image_user(slot);
+ }
+ return new PointDensityTextureNode(*this);
}
void PointDensityTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -1507,8 +1536,15 @@ void PointDensityTextureNode::add_image()
{
if (slot == -1) {
ImageMetaData metadata;
- slot = image_manager->add_image(
- filename.string(), builtin_data, false, 0, interpolation, EXTENSION_CLIP, true, metadata);
+ slot = image_manager->add_image(filename.string(),
+ builtin_data,
+ false,
+ 0,
+ interpolation,
+ EXTENSION_CLIP,
+ IMAGE_ALPHA_AUTO,
+ u_colorspace_raw,
+ metadata);
}
}
@@ -1567,9 +1603,7 @@ void PointDensityTextureNode::compile(OSLCompiler &compiler)
if (use_density || use_color) {
add_image();
- if (slot != -1) {
- compiler.parameter("filename", string_printf("@i%d", slot).c_str());
- }
+ compiler.parameter_texture("filename", slot);
if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.parameter("mapping", tfm);
compiler.parameter("use_mapping", 1);
@@ -2430,6 +2464,8 @@ NODE_DEFINE(PrincipledBsdfNode)
SOCKET_IN_FLOAT(transmission, "Transmission", 0.0f);
SOCKET_IN_FLOAT(transmission_roughness, "Transmission Roughness", 0.0f);
SOCKET_IN_FLOAT(anisotropic_rotation, "Anisotropic Rotation", 0.0f);
+ SOCKET_IN_COLOR(emission, "Emission", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_FLOAT(alpha, "Alpha", 1.0f);
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
SOCKET_IN_NORMAL(clearcoat_normal,
"Clearcoat Normal",
@@ -2450,6 +2486,48 @@ PrincipledBsdfNode::PrincipledBsdfNode() : BsdfBaseNode(node_type)
distribution_orig = NBUILTIN_CLOSURES;
}
+void PrincipledBsdfNode::expand(ShaderGraph *graph)
+{
+ ShaderOutput *principled_out = output("BSDF");
+
+ ShaderInput *emission_in = input("Emission");
+ if (emission_in->link || emission != make_float3(0.0f, 0.0f, 0.0f)) {
+ /* Create add closure and emission. */
+ AddClosureNode *add = new AddClosureNode();
+ EmissionNode *emission_node = new EmissionNode();
+ ShaderOutput *new_out = add->output("Closure");
+
+ graph->add(add);
+ graph->add(emission_node);
+
+ emission_node->strength = 1.0f;
+ graph->relink(emission_in, emission_node->input("Color"));
+ graph->relink(principled_out, new_out);
+ graph->connect(emission_node->output("Emission"), add->input("Closure1"));
+ graph->connect(principled_out, add->input("Closure2"));
+
+ principled_out = new_out;
+ }
+
+ ShaderInput *alpha_in = input("Alpha");
+ if (alpha_in->link || alpha != 1.0f) {
+ /* Create mix and transparent BSDF for alpha transparency. */
+ MixClosureNode *mix = new MixClosureNode();
+ TransparentBsdfNode *transparent = new TransparentBsdfNode();
+
+ graph->add(mix);
+ graph->add(transparent);
+
+ graph->relink(alpha_in, mix->input("Fac"));
+ graph->relink(principled_out, mix->output("Closure"));
+ graph->connect(transparent->output("BSDF"), mix->input("Closure1"));
+ graph->connect(principled_out, mix->input("Closure2"));
+ }
+
+ remove_input(emission_in);
+ remove_input(alpha_in);
+}
+
bool PrincipledBsdfNode::has_surface_bssrdf()
{
ShaderInput *subsurface_in = input("Subsurface");
@@ -2630,7 +2708,7 @@ NODE_DEFINE(TransparentBsdfNode)
{
NodeType *type = NodeType::add("transparent_bsdf", create, NodeType::SHADER);
- SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_COLOR(color, "Color", make_float3(1.0f, 1.0f, 1.0f));
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 7796711115e..6b21be88663 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -92,13 +92,18 @@ class ImageTextureNode : public ImageSlotTextureNode {
return true;
}
- ImageManager *image_manager;
- int is_float;
- bool is_linear;
- bool use_alpha;
+ virtual bool equals(const ShaderNode &other)
+ {
+ const ImageTextureNode &image_node = (const ImageTextureNode &)other;
+ return ImageSlotTextureNode::equals(other) && builtin_data == image_node.builtin_data &&
+ animated == image_node.animated;
+ }
+
+ /* Parameters. */
ustring filename;
void *builtin_data;
- NodeImageColorSpace color_space;
+ ustring colorspace;
+ ImageAlphaType alpha_type;
NodeImageProjection projection;
InterpolationType interpolation;
ExtensionType extension;
@@ -106,12 +111,11 @@ class ImageTextureNode : public ImageSlotTextureNode {
bool animated;
float3 vector;
- virtual bool equals(const ShaderNode &other)
- {
- const ImageTextureNode &image_node = (const ImageTextureNode &)other;
- return ImageSlotTextureNode::equals(other) && builtin_data == image_node.builtin_data &&
- animated == image_node.animated;
- }
+ /* Runtime. */
+ ImageManager *image_manager;
+ int is_float;
+ bool compress_as_srgb;
+ ustring known_colorspace;
};
class EnvironmentTextureNode : public ImageSlotTextureNode {
@@ -129,24 +133,28 @@ class EnvironmentTextureNode : public ImageSlotTextureNode {
return NODE_GROUP_LEVEL_2;
}
- ImageManager *image_manager;
- int is_float;
- bool is_linear;
- bool use_alpha;
+ virtual bool equals(const ShaderNode &other)
+ {
+ const EnvironmentTextureNode &env_node = (const EnvironmentTextureNode &)other;
+ return ImageSlotTextureNode::equals(other) && builtin_data == env_node.builtin_data &&
+ animated == env_node.animated;
+ }
+
+ /* Parameters. */
ustring filename;
void *builtin_data;
- NodeImageColorSpace color_space;
+ ustring colorspace;
+ ImageAlphaType alpha_type;
NodeEnvironmentProjection projection;
InterpolationType interpolation;
bool animated;
float3 vector;
- virtual bool equals(const ShaderNode &other)
- {
- const EnvironmentTextureNode &env_node = (const EnvironmentTextureNode &)other;
- return ImageSlotTextureNode::equals(other) && builtin_data == env_node.builtin_data &&
- animated == env_node.animated;
- }
+ /* Runtime. */
+ ImageManager *image_manager;
+ int is_float;
+ bool compress_as_srgb;
+ ustring known_colorspace;
};
class SkyTextureNode : public TextureNode {
@@ -319,15 +327,17 @@ class PointDensityTextureNode : public ShaderNode {
void add_image();
+ /* Parameters. */
ustring filename;
NodeTexVoxelSpace space;
InterpolationType interpolation;
Transform tfm;
float3 vector;
+ void *builtin_data;
+ /* Runtime. */
ImageManager *image_manager;
int slot;
- void *builtin_data;
virtual bool equals(const ShaderNode &other)
{
@@ -477,6 +487,7 @@ class PrincipledBsdfNode : public BsdfBaseNode {
public:
SHADER_NODE_CLASS(PrincipledBsdfNode)
+ void expand(ShaderGraph *graph);
bool has_surface_bssrdf();
bool has_bssrdf_bump();
void compile(SVMCompiler &compiler,
@@ -505,6 +516,8 @@ class PrincipledBsdfNode : public BsdfBaseNode {
float surface_mix_weight;
ClosureType distribution, distribution_orig;
ClosureType subsurface_method;
+ float3 emission;
+ float alpha;
bool has_integrator_dependency();
void attributes(Shader *shader, AttributeRequestSet *attributes);
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index b66a46938be..6f927bd5c42 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -16,6 +16,7 @@
#include "device/device.h"
+#include "render/colorspace.h"
#include "render/graph.h"
#include "render/light.h"
#include "render/osl.h"
@@ -29,6 +30,7 @@
# include "kernel/osl/osl_services.h"
# include "kernel/osl/osl_shader.h"
+# include "util/util_aligned_malloc.h"
# include "util/util_foreach.h"
# include "util/util_logging.h"
# include "util/util_md5.h"
@@ -53,6 +55,7 @@ OSLRenderServices *OSLShaderManager::services_shared = NULL;
int OSLShaderManager::ss_shared_users = 0;
thread_mutex OSLShaderManager::ss_shared_mutex;
thread_mutex OSLShaderManager::ss_mutex;
+int OSLCompiler::texture_shared_unique_id = 0;
/* Shader Manager */
@@ -115,7 +118,7 @@ void OSLShaderManager::device_update(Device *device,
* compile shaders alternating */
thread_scoped_lock lock(ss_mutex);
- OSLCompiler compiler((void *)this, (void *)ss, scene->image_manager, scene->light_manager);
+ OSLCompiler compiler(this, services, ss, scene->image_manager, scene->light_manager);
compiler.background = (shader == scene->default_background);
compiler.compile(scene, og, shader);
@@ -140,6 +143,10 @@ void OSLShaderManager::device_update(Device *device,
/* set texture system */
scene->image_manager->set_osl_texture_system((void *)ts);
+ /* add special builtin texture types */
+ services->textures.insert(ustring("@ao"), new OSLTextureHandle(OSLTextureHandle::AO));
+ services->textures.insert(ustring("@bevel"), new OSLTextureHandle(OSLTextureHandle::BEVEL));
+
device_update_common(device, dscene, scene, progress);
{
@@ -218,7 +225,8 @@ void OSLShaderManager::shading_system_init()
thread_scoped_lock lock(ss_shared_mutex);
if (ss_shared_users == 0) {
- services_shared = new OSLRenderServices();
+ /* Must use aligned new due to concurrent hash map. */
+ services_shared = util_aligned_new<OSLRenderServices>(ts_shared);
string shader_path = path_get("shader");
# ifdef _WIN32
@@ -287,7 +295,7 @@ void OSLShaderManager::shading_system_free()
delete ss_shared;
ss_shared = NULL;
- delete services_shared;
+ util_aligned_delete(services_shared);
services_shared = NULL;
}
@@ -555,15 +563,17 @@ OSLNode *OSLShaderManager::osl_node(const std::string &filepath,
/* Graph Compiler */
-OSLCompiler::OSLCompiler(void *manager_,
- void *shadingsys_,
- ImageManager *image_manager_,
- LightManager *light_manager_)
+OSLCompiler::OSLCompiler(OSLShaderManager *manager,
+ OSLRenderServices *services,
+ OSL::ShadingSystem *ss,
+ ImageManager *image_manager,
+ LightManager *light_manager)
+ : image_manager(image_manager),
+ light_manager(light_manager),
+ manager(manager),
+ services(services),
+ ss(ss)
{
- manager = manager_;
- shadingsys = shadingsys_;
- image_manager = image_manager_;
- light_manager = light_manager_;
current_type = SHADER_TYPE_SURFACE;
current_shader = NULL;
background = false;
@@ -649,11 +659,9 @@ bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys;
-
/* load filepath */
if (isfilepath) {
- name = ((OSLShaderManager *)manager)->shader_load_filepath(name);
+ name = manager->shader_load_filepath(name);
if (name == NULL)
return;
@@ -731,7 +739,7 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
}
/* test if we shader contains specific closures */
- OSLShaderInfo *info = ((OSLShaderManager *)manager)->shader_loaded_info(name);
+ OSLShaderInfo *info = manager->shader_loaded_info(name);
if (current_type == SHADER_TYPE_SURFACE) {
if (info) {
@@ -778,7 +786,6 @@ static TypeDesc array_typedesc(TypeDesc typedesc, int arraylength)
void OSLCompiler::parameter(ShaderNode *node, const char *name)
{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys;
ustring uname = ustring(name);
const SocketType &socket = *(node->type->find_input(uname));
@@ -930,56 +937,47 @@ void OSLCompiler::parameter(ShaderNode *node, const char *name)
void OSLCompiler::parameter(const char *name, float f)
{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys;
ss->Parameter(name, TypeDesc::TypeFloat, &f);
}
void OSLCompiler::parameter_color(const char *name, float3 f)
{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys;
ss->Parameter(name, TypeDesc::TypeColor, &f);
}
void OSLCompiler::parameter_point(const char *name, float3 f)
{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys;
ss->Parameter(name, TypeDesc::TypePoint, &f);
}
void OSLCompiler::parameter_normal(const char *name, float3 f)
{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys;
ss->Parameter(name, TypeDesc::TypeNormal, &f);
}
void OSLCompiler::parameter_vector(const char *name, float3 f)
{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys;
ss->Parameter(name, TypeDesc::TypeVector, &f);
}
void OSLCompiler::parameter(const char *name, int f)
{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys;
ss->Parameter(name, TypeDesc::TypeInt, &f);
}
void OSLCompiler::parameter(const char *name, const char *s)
{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys;
ss->Parameter(name, TypeDesc::TypeString, &s);
}
void OSLCompiler::parameter(const char *name, ustring s)
{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys;
const char *str = s.c_str();
ss->Parameter(name, TypeDesc::TypeString, &str);
}
void OSLCompiler::parameter(const char *name, const Transform &tfm)
{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys;
ProjectionTransform projection(tfm);
projection = projection_transpose(projection);
ss->Parameter(name, TypeDesc::TypeMatrix, (float *)&projection);
@@ -987,7 +985,6 @@ void OSLCompiler::parameter(const char *name, const Transform &tfm)
void OSLCompiler::parameter_array(const char *name, const float f[], int arraylen)
{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys;
TypeDesc type = TypeDesc::TypeFloat;
type.arraylen = arraylen;
ss->Parameter(name, type, f);
@@ -1004,7 +1001,6 @@ void OSLCompiler::parameter_color_array(const char *name, const array<float3> &f
table[i][2] = f[i].z;
}
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys;
TypeDesc type = TypeDesc::TypeColor;
type.arraylen = table.size();
ss->Parameter(name, type, table.data());
@@ -1082,8 +1078,6 @@ void OSLCompiler::generate_nodes(const ShaderNodeSet &nodes)
OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys;
-
current_type = type;
OSL::ShaderGroupRef group = ss->ShaderGroupBegin(shader->name.c_str());
@@ -1194,6 +1188,35 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
og->bump_state.push_back(shader->osl_surface_bump_ref);
}
+void OSLCompiler::parameter_texture(const char *name, ustring filename, ustring colorspace)
+{
+ /* Textured loaded through the OpenImageIO texture cache. For this
+ * case we need to do runtime color space conversion. */
+ OSLTextureHandle *handle = new OSLTextureHandle(OSLTextureHandle::OIIO);
+ handle->processor = ColorSpaceManager::get_processor(colorspace);
+ services->textures.insert(filename, handle);
+ parameter(name, filename);
+}
+
+void OSLCompiler::parameter_texture(const char *name, int svm_slot)
+{
+ /* Texture loaded through SVM image texture system. We generate a unique
+ * name, which ends up being used in OSLRenderServices::get_texture_handle
+ * to get handle again. Note that this name must be unique between multiple
+ * render sessions as the render services are shared. */
+ ustring filename(string_printf("@svm%d", texture_shared_unique_id++).c_str());
+ services->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::SVM, svm_slot));
+ parameter(name, filename);
+}
+
+void OSLCompiler::parameter_texture_ies(const char *name, int svm_slot)
+{
+ /* IES light textures stored in SVM. */
+ ustring filename(string_printf("@svm%d", texture_shared_unique_id++).c_str());
+ services->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::IES, svm_slot));
+ parameter(name, filename);
+}
+
#else
void OSLCompiler::add(ShaderNode * /*node*/, const char * /*name*/, bool /*isfilepath*/)
@@ -1248,6 +1271,20 @@ void OSLCompiler::parameter_color_array(const char * /*name*/, const array<float
{
}
+void OSLCompiler::parameter_texture(const char * /* name */,
+ ustring /* filename */,
+ ustring /* colorspace */)
+{
+}
+
+void OSLCompiler::parameter_texture(const char * /* name */, int /* svm_slot */)
+{
+}
+
+void OSLCompiler::parameter_texture_ies(const char * /* name */, int /* svm_slot */)
+{
+}
+
#endif /* WITH_OSL */
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h
index aec518a6c2b..17bf98a3433 100644
--- a/intern/cycles/render/osl.h
+++ b/intern/cycles/render/osl.h
@@ -127,10 +127,13 @@ class OSLShaderManager : public ShaderManager {
class OSLCompiler {
public:
- OSLCompiler(void *manager,
- void *shadingsys,
+#ifdef WITH_OSL
+ OSLCompiler(OSLShaderManager *manager,
+ OSLRenderServices *services,
+ OSL::ShadingSystem *shadingsys,
ImageManager *image_manager,
LightManager *light_manager);
+#endif
void compile(Scene *scene, OSLGlobals *og, Shader *shader);
void add(ShaderNode *node, const char *name, bool isfilepath = false);
@@ -152,6 +155,10 @@ class OSLCompiler {
void parameter_attribute(const char *name, ustring s);
+ void parameter_texture(const char *name, ustring filename, ustring colorspace);
+ void parameter_texture(const char *name, int svm_slot);
+ void parameter_texture_ies(const char *name, int svm_slot);
+
ShaderType output_type()
{
return current_type;
@@ -171,12 +178,16 @@ class OSLCompiler {
void find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input);
void generate_nodes(const ShaderNodeSet &nodes);
+
+ OSLShaderManager *manager;
+ OSLRenderServices *services;
+ OSL::ShadingSystem *ss;
#endif
- void *shadingsys;
- void *manager;
ShaderType current_type;
Shader *current_shader;
+
+ static int texture_shared_unique_id;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index ac3303cbfeb..ec85e516832 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -14,9 +14,11 @@
* limitations under the License.
*/
+#include "device/device.h"
+
#include "render/background.h"
#include "render/camera.h"
-#include "device/device.h"
+#include "render/colorspace.h"
#include "render/graph.h"
#include "render/integrator.h"
#include "render/light.h"
@@ -717,6 +719,8 @@ void ShaderManager::free_memory()
#ifdef WITH_OSL
OSLShaderManager::free_memory();
#endif
+
+ ColorSpaceManager::free_memory();
}
float ShaderManager::linear_rgb_to_gray(float3 c)
diff --git a/intern/cycles/util/util_aligned_malloc.h b/intern/cycles/util/util_aligned_malloc.h
index 0f006e95f6a..df7d93c056d 100644
--- a/intern/cycles/util/util_aligned_malloc.h
+++ b/intern/cycles/util/util_aligned_malloc.h
@@ -30,6 +30,21 @@ void *util_aligned_malloc(size_t size, int alignment);
/* Free memory allocated by util_aligned_malloc. */
void util_aligned_free(void *ptr);
+/* Aligned new operator. */
+template<typename T, typename... Args> T *util_aligned_new(Args... args)
+{
+ void *mem = util_aligned_malloc(sizeof(T), alignof(T));
+ return new (mem) T(args...);
+}
+
+template<typename T> void util_aligned_delete(T *t)
+{
+ if (t) {
+ t->~T();
+ util_aligned_free(t);
+ }
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_ALIGNED_MALLOC_H__ */
diff --git a/intern/cycles/util/util_color.h b/intern/cycles/util/util_color.h
index 85f241c6221..83410db13c6 100644
--- a/intern/cycles/util/util_color.h
+++ b/intern/cycles/util/util_color.h
@@ -236,6 +236,12 @@ ccl_device float3 color_linear_to_srgb_v3(float3 c)
color_linear_to_srgb(c.x), color_linear_to_srgb(c.y), color_linear_to_srgb(c.z));
}
+ccl_device float4 color_linear_to_srgb_v4(float4 c)
+{
+ return make_float4(
+ color_linear_to_srgb(c.x), color_linear_to_srgb(c.y), color_linear_to_srgb(c.z), c.w);
+}
+
ccl_device float4 color_srgb_to_linear_v4(float4 c)
{
#ifdef __KERNEL_SSE2__
diff --git a/intern/cycles/util/util_image.h b/intern/cycles/util/util_image.h
index 8962c09d098..27ec7ffb423 100644
--- a/intern/cycles/util/util_image.h
+++ b/intern/cycles/util/util_image.h
@@ -21,6 +21,7 @@
# include <OpenImageIO/imageio.h>
+# include "util/util_half.h"
# include "util/util_vector.h"
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/util/util_map.h b/intern/cycles/util/util_map.h
index 3c9288417cf..8385b08dd5a 100644
--- a/intern/cycles/util/util_map.h
+++ b/intern/cycles/util/util_map.h
@@ -26,6 +26,13 @@ using std::map;
using std::pair;
using std::unordered_map;
+template<typename T> static void map_free_memory(T &data)
+{
+ /* Use swap() trick to actually free all internal memory. */
+ T empty_data;
+ data.swap(empty_data);
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_MAP_H__ */
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
index 92cab29346a..dde0d31f467 100644
--- a/intern/cycles/util/util_math.h
+++ b/intern/cycles/util/util_math.h
@@ -651,6 +651,26 @@ ccl_device_inline float2 map_to_sphere(const float3 co)
return make_float2(u, v);
}
+/* Compares two floats.
+ * Returns true if their absolute difference is smaller than abs_diff (for numbers near zero)
+ * or their relative difference is less than ulp_diff ULPs.
+ * Based on
+ * https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
+ */
+
+ccl_device_inline float compare_floats(float a, float b, float abs_diff, int ulp_diff)
+{
+ if (fabsf(a - b) < abs_diff) {
+ return true;
+ }
+
+ if ((a < 0.0f) != (b < 0.0f)) {
+ return false;
+ }
+
+ return (abs(__float_as_int(a) - __float_as_int(b)) < ulp_diff);
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_MATH_H__ */
diff --git a/intern/cycles/util/util_texture.h b/intern/cycles/util/util_texture.h
index 5ce16e0095a..d43852480d1 100644
--- a/intern/cycles/util/util_texture.h
+++ b/intern/cycles/util/util_texture.h
@@ -59,6 +59,18 @@ typedef enum ImageDataType {
IMAGE_DATA_NUM_TYPES
} ImageDataType;
+/* Alpha types
+ * How to treat alpha in images. */
+typedef enum ImageAlphaType {
+ IMAGE_ALPHA_UNASSOCIATED = 0,
+ IMAGE_ALPHA_ASSOCIATED = 1,
+ IMAGE_ALPHA_CHANNEL_PACKED = 2,
+ IMAGE_ALPHA_IGNORE = 3,
+ IMAGE_ALPHA_AUTO = 4,
+
+ IMAGE_ALPHA_NUM_TYPES,
+} ImageAlphaType;
+
#define IMAGE_DATA_TYPE_SHIFT 3
#define IMAGE_DATA_TYPE_MASK 0x7
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index 6c490e51b0d..fa783c17e8c 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -33,7 +33,7 @@ extern "C" {
/**
* Creates a "handle" for a C++ GHOST object.
* A handle is just an opaque pointer to an empty struct.
- * In the API the pointer is casted to the actual C++ class.
+ * In the API the pointer is cast to the actual C++ class.
* The 'name' argument to the macro is the name of the handle to create.
*/
@@ -906,17 +906,6 @@ extern void GHOST_putClipboard(GHOST_TInt8 *buffer, int selection);
extern int GHOST_toggleConsole(int action);
/**
- * Confirms quitting he program when there is just one window left open
- * in the application
- */
-extern int GHOST_confirmQuit(GHOST_WindowHandle windowhandle);
-
-/**
- * Informs if the system provides native dialogs (eg. confirm quit)
- */
-extern int GHOST_SupportsNativeDialogs(void);
-
-/**
* Use native pixel size (MacBook pro 'retina'), if supported.
*/
extern int GHOST_UseNativePixels(void);
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 3c93d21f30f..f0ceb7fb8ba 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -235,7 +235,7 @@ class GHOST_ISystem {
* \param state: The state of the window when opened.
* \param type: The type of drawing context installed in this window.
* \param glSettings: Misc OpenGL settings.
- * \param exclusive: Use to show the window ontop and ignore others (used fullscreen).
+ * \param exclusive: Use to show the window on top and ignore others (used fullscreen).
* \param parentWindow: Parent (embedder) window
* \return The new window (or 0 if creation failed).
*/
@@ -435,17 +435,6 @@ class GHOST_ISystem {
*/
virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const = 0;
- /**
- * Confirms quitting he program when there is just one window left open
- * in the application
- */
- virtual int confirmQuit(GHOST_IWindow *window) const = 0;
-
- /**
- * Informs if the system provides native dialogs (eg. confirm quit)
- */
- virtual bool supportsNativeDialogs(void) = 0;
-
protected:
/**
* Initialize the system.
diff --git a/intern/ghost/GHOST_Rect.h b/intern/ghost/GHOST_Rect.h
index d4c05a7b8aa..831d3ef1445 100644
--- a/intern/ghost/GHOST_Rect.h
+++ b/intern/ghost/GHOST_Rect.h
@@ -236,7 +236,6 @@ inline void GHOST_Rect::unionPoint(GHOST_TInt32 x, GHOST_TInt32 y)
if (y > m_b)
m_b = y;
}
-#include <stdio.h>
inline void GHOST_Rect::wrapPoint(GHOST_TInt32 &x, GHOST_TInt32 &y, GHOST_TInt32 ofs)
{
GHOST_TInt32 w = getWidth();
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index faba5bb996a..f38154cbf94 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -125,9 +125,6 @@ typedef enum {
// GHOST_kWindowStateUnModified,
} GHOST_TWindowState;
-/** Constants for the answer to the blender exit request */
-typedef enum { GHOST_kExitCancel = 0, GHOST_kExitNow } GHOST_TExitRequestResponse;
-
typedef enum { GHOST_kWindowOrderTop = 0, GHOST_kWindowOrderBottom } GHOST_TWindowOrder;
typedef enum {
@@ -165,7 +162,7 @@ typedef enum {
GHOST_kEventKeyUp,
// GHOST_kEventKeyAuto,
- GHOST_kEventQuit,
+ GHOST_kEventQuitRequest,
GHOST_kEventWindowClose,
GHOST_kEventWindowActivate,
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 3848c723e5b..c8ee2e44efe 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -788,18 +788,6 @@ int GHOST_toggleConsole(int action)
return system->toggleConsole(action);
}
-int GHOST_SupportsNativeDialogs(void)
-{
- GHOST_ISystem *system = GHOST_ISystem::getSystem();
- return system->supportsNativeDialogs();
-}
-
-int GHOST_confirmQuit(GHOST_WindowHandle windowhandle)
-{
- GHOST_ISystem *system = GHOST_ISystem::getSystem();
- return system->confirmQuit((GHOST_IWindow *)windowhandle);
-}
-
int GHOST_UseNativePixels(void)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();
diff --git a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
index 4626955ac7f..f1acf74ca41 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
@@ -24,6 +24,8 @@
* \ingroup GHOST
*/
+#include <stdio.h>
+
#ifdef WITH_X11_XF86VMODE
# include <X11/Xlib.h>
# include <X11/extensions/xf86vmode.h>
diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.h b/intern/ghost/intern/GHOST_DropTargetWin32.h
index e1985f85640..588d89f1549 100644
--- a/intern/ghost/intern/GHOST_DropTargetWin32.h
+++ b/intern/ghost/intern/GHOST_DropTargetWin32.h
@@ -125,7 +125,7 @@ class GHOST_DropTargetWin32 : public IDropTarget {
void *getDropDataAsString(IDataObject *pDataObject);
/**
- * Convert Unicode to ANSI, replacing unconvertable chars with '?'.
+ * Convert Unicode to ANSI, replacing uncomfortable chars with '?'.
* The ANSI codepage is the system default codepage,
* and can change from system to system.
* \param in LPCWSTR.
diff --git a/intern/ghost/intern/GHOST_DropTargetX11.h b/intern/ghost/intern/GHOST_DropTargetX11.h
index 1edb52de5e5..d3f98ff11cf 100644
--- a/intern/ghost/intern/GHOST_DropTargetX11.h
+++ b/intern/ghost/intern/GHOST_DropTargetX11.h
@@ -69,7 +69,7 @@ class GHOST_DropTargetX11 {
void Initialize(void);
/**
- * Uninitialize XDND and all related X atoms
+ * Uninitialized XDND and all related X atoms
*/
void Uninitialize(void);
diff --git a/intern/ghost/intern/GHOST_EventPrinter.cpp b/intern/ghost/intern/GHOST_EventPrinter.cpp
index 3c5f613e11f..ba9ed6e3037 100644
--- a/intern/ghost/intern/GHOST_EventPrinter.cpp
+++ b/intern/ghost/intern/GHOST_EventPrinter.cpp
@@ -139,8 +139,8 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
std::cout << "GHOST_kEventOpenMainFile with no path specified!!";
} break;
- case GHOST_kEventQuit:
- std::cout << "GHOST_kEventQuit";
+ case GHOST_kEventQuitRequest:
+ std::cout << "GHOST_kEventQuitRequest";
break;
case GHOST_kEventWindowClose:
std::cout << "GHOST_kEventWindowClose";
diff --git a/intern/ghost/intern/GHOST_ImeWin32.cpp b/intern/ghost/intern/GHOST_ImeWin32.cpp
index 06fab47933a..9ad12cb0e63 100644
--- a/intern/ghost/intern/GHOST_ImeWin32.cpp
+++ b/intern/ghost/intern/GHOST_ImeWin32.cpp
@@ -178,7 +178,7 @@ void GHOST_ImeWin32::CleanupComposition(HWND window_handle)
/**
* Notify the IMM attached to the given window to complete the ongoing
* composition, (this case happens when the given window is de-activated
- * while composing a text and re-activated), and reset the omposition status.
+ * while composing a text and re-activated), and reset the composition status.
*/
if (is_composing_) {
HIMC imm_context = ::ImmGetContext(window_handle);
@@ -273,7 +273,7 @@ void GHOST_ImeWin32::GetCaret(HIMC imm_context, LPARAM lparam, ImeComposition *c
/**
* For Japanese IMEs, the robustest way to retrieve the caret
* is scanning the attribute of the latest composition string and
- * retrieving the begining and the end of the target clause, i.e.
+ * retrieving the beginning and the end of the target clause, i.e.
* a clause being converted.
*/
if (lparam & GCS_COMPATTR) {
diff --git a/intern/ghost/intern/GHOST_ImeWin32.h b/intern/ghost/intern/GHOST_ImeWin32.h
index 9c1f2473223..112217023a7 100644
--- a/intern/ghost/intern/GHOST_ImeWin32.h
+++ b/intern/ghost/intern/GHOST_ImeWin32.h
@@ -122,7 +122,7 @@ struct ImeComposition {
/**
* This class controls the IMM (Input Method Manager) through IMM32 APIs and
- * enables it to retrieve the string being controled by the IMM. (I wrote
+ * enables it to retrieve the string being controlled by the IMM. (I wrote
* a note to describe the reason why I do not use 'IME' but 'IMM' below.)
* NOTE(hbono):
* Fortunately or unfortunately, TSF (Text Service Framework) and
@@ -274,7 +274,7 @@ class GHOST_ImeWin32 {
* events to be dispatched to the IME.
* In Chrome, this function is used when:
* * a renderer process moves its input focus to another edit control, or;
- * * a renrerer process moves the position of the focused edit control.
+ * * a renderer process moves the position of the focused edit control.
* Parameters
* * window_handle [in] (HWND)
* Represents the window handle of the caller.
@@ -297,7 +297,7 @@ class GHOST_ImeWin32 {
* Disable the IME attached to the given window, i.e. prohibits any user-input
* events from being dispatched to the IME.
* In Chrome, this function is used when:
- * * a renreder process sets its input focus to a password input.
+ * * a rendeder process sets its input focus to a password input.
* Parameters
* * window_handle [in] (HWND)
* Represents the window handle of the caller.
@@ -350,7 +350,7 @@ class GHOST_ImeWin32 {
/**
* The current input Language ID retrieved from Windows, which consists of:
- * * Primary Language ID (bit 0 to bit 9), which shows a natunal language
+ * * Primary Language ID (bit 0 to bit 9), which shows a natural language
* (English, Korean, Chinese, Japanese, etc.) and;
* * Sub-Language ID (bit 10 to bit 15), which shows a geometrical region
* the language is spoken (For English, United States, United Kingdom,
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index a696afeae02..21935abed9c 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -378,16 +378,6 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
return (*window == NULL) ? GHOST_kFailure : GHOST_kSuccess;
}
-int GHOST_System::confirmQuit(GHOST_IWindow * /*window*/) const
-{
- return 1;
-}
-
-bool GHOST_System::supportsNativeDialogs(void)
-{
- return 1;
-}
-
bool GHOST_System::useNativePixel(void)
{
m_nativePixel = true;
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index a62641c5cf5..fbf8af01e59 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -317,17 +317,6 @@ class GHOST_System : public GHOST_ISystem {
*/
virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const = 0;
- /**
- * Confirms quitting he program when there is just one window left open
- * in the application
- */
- virtual int confirmQuit(GHOST_IWindow *window) const;
-
- /**
- * Informs if the system provides native dialogs (eg. confirm quit)
- */
- virtual bool supportsNativeDialogs(void);
-
protected:
/**
* Initialize the system.
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h
index 749139fee76..109dd6c180d 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.h
+++ b/intern/ghost/intern/GHOST_SystemCocoa.h
@@ -140,7 +140,7 @@ class GHOST_SystemCocoa : public GHOST_System {
* Handle User request to quit, from Menu bar Quit, and Cmd+Q
* Display alert panel if changes performed since last save
*/
- GHOST_TUns8 handleQuitRequest();
+ void handleQuitRequest();
/**
* Handle Cocoa openFile event
@@ -269,11 +269,6 @@ class GHOST_SystemCocoa : public GHOST_System {
*/
GHOST_TSuccess handleKeyEvent(void *eventPtr);
- /**
- * Informs if the system provides native dialogs (eg. confirm quit)
- */
- virtual bool supportsNativeDialogs(void);
-
protected:
/**
* Initializes the system.
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index 1fd0914eb73..49e01a983a0 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -427,10 +427,8 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
/* TODO: implement graceful termination through Cocoa mechanism
* to avoid session log off to be canceled. */
/* Note that Cmd+Q is already handled by keyhandler. */
- if (systemCocoa->handleQuitRequest() == GHOST_kExitNow)
- return NSTerminateCancel; //NSTerminateNow;
- else
- return NSTerminateCancel;
+ systemCocoa->handleQuitRequest();
+ return NSTerminateCancel;
}
// To avoid canceling a log off process, we must use Cocoa termination process
@@ -1342,46 +1340,17 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
return GHOST_kSuccess;
}
-GHOST_TUns8 GHOST_SystemCocoa::handleQuitRequest()
+void GHOST_SystemCocoa::handleQuitRequest()
{
GHOST_Window *window = (GHOST_Window *)m_windowManager->getActiveWindow();
// Discard quit event if we are in cursor grab sequence
if (window && window->getCursorGrabModeIsWarp())
- return GHOST_kExitCancel;
-
- // Check open windows if some changes are not saved
- if (m_windowManager->getAnyModifiedState()) {
- int shouldQuit = NSRunAlertPanel(
- @"Exit Blender",
- @"Some changes have not been saved.\nDo you really want to quit?",
- @"Cancel",
- @"Quit Anyway",
- nil);
- if (shouldQuit == NSAlertAlternateReturn) {
- pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventQuit, NULL));
- return GHOST_kExitNow;
- }
- else {
- // Give back focus to the blender window if user selected cancel quit
- NSArray *windowsList = [NSApp orderedWindows];
- if ([windowsList count]) {
- [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
- // Handle the modifiers keyes changed state issue
- // as recovering from the quit dialog is like application
- // gaining focus back.
- // Main issue fixed is Cmd modifier not being cleared
- handleApplicationBecomeActiveEvent();
- }
- }
- }
- else {
- pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventQuit, NULL));
- m_outsideLoopEventProcessed = true;
- return GHOST_kExitNow;
- }
+ return;
- return GHOST_kExitCancel;
+ // Push the event to Blender so it can open a dialog if needed
+ pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventQuitRequest, window));
+ m_outsideLoopEventProcessed = true;
}
bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
@@ -1400,7 +1369,7 @@ bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
/* Discard event if we are in cursor grab sequence,
* it'll lead to "stuck cursor" situation if the alert panel is raised */
if (window && window->getCursorGrabModeIsWarp())
- return GHOST_kExitCancel;
+ return NO;
// Check open windows if some changes are not saved
if (m_windowManager->getAnyModifiedState()) {
@@ -1622,7 +1591,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
window->getClientBounds(bounds);
/* Switch back to Cocoa coordinates orientation
- * (y=0 at botton,the same as blender internal btw!), and to client coordinates. */
+ * (y=0 at bottom, the same as blender internal btw!), and to client coordinates. */
window->getClientBounds(windowBounds);
window->screenToClient(bounds.m_l, bounds.m_b, correctedBounds.m_l, correctedBounds.m_t);
window->screenToClient(bounds.m_r, bounds.m_t, correctedBounds.m_r, correctedBounds.m_b);
@@ -1696,7 +1665,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
else if (phase == NSEventPhaseEnded)
m_multiTouchScroll = false;
- /* Standard scrollwheel case, if no swiping happened,
+ /* Standard scroll-wheel case, if no swiping happened,
* and no momentum (kinetic scroll) works. */
if (!m_multiTouchScroll && momentumPhase == NSEventPhaseNone) {
GHOST_TInt32 delta;
@@ -1989,8 +1958,3 @@ void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const
[pool drain];
}
-
-bool GHOST_SystemCocoa::supportsNativeDialogs(void)
-{
- return false;
-}
diff --git a/intern/ghost/intern/GHOST_SystemNULL.h b/intern/ghost/intern/GHOST_SystemNULL.h
index 7f68c801a70..93aea87e9a6 100644
--- a/intern/ghost/intern/GHOST_SystemNULL.h
+++ b/intern/ghost/intern/GHOST_SystemNULL.h
@@ -82,10 +82,6 @@ class GHOST_SystemNULL : public GHOST_System {
void getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const
{ /* nop */
}
- bool supportsNativeDialogs(void)
- {
- return false;
- }
GHOST_IContext *createOffscreenContext()
{
return NULL;
@@ -130,8 +126,7 @@ class GHOST_SystemNULL : public GHOST_System {
state,
parentWindow,
type,
- ((glSettings.flags & GHOST_glStereoVisual) != 0),
- 1);
+ ((glSettings.flags & GHOST_glStereoVisual) != 0));
}
};
diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.h b/intern/ghost/intern/GHOST_SystemPathsUnix.h
index bcbe24b0d31..dcd3ab34704 100644
--- a/intern/ghost/intern/GHOST_SystemPathsUnix.h
+++ b/intern/ghost/intern/GHOST_SystemPathsUnix.h
@@ -31,7 +31,7 @@ class GHOST_SystemPathsUnix : public GHOST_SystemPaths {
public:
/**
* Constructor
- * this class should only be instanciated by GHOST_ISystem.
+ * this class should only be instantiated by GHOST_ISystem.
*/
GHOST_SystemPathsUnix();
diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp
index 7b0407c6c4c..8fc7046565d 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.cpp
+++ b/intern/ghost/intern/GHOST_SystemSDL.cpp
@@ -338,9 +338,12 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
break;
}
- case SDL_QUIT:
- g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventQuit, NULL);
+
+ case SDL_QUIT: {
+ GHOST_IWindow *window = m_windowManager->getActiveWindow();
+ g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventQuitRequest, window);
break;
+ }
case SDL_MOUSEMOTION: {
SDL_MouseMotionEvent &sdl_sub_evt = sdl_event->motion;
@@ -718,11 +721,6 @@ void GHOST_SystemSDL::addDirtyWindow(GHOST_WindowSDL *bad_wind)
m_dirty_windows.push_back(bad_wind);
}
-bool GHOST_SystemSDL::supportsNativeDialogs(void)
-{
- return false;
-}
-
GHOST_TSuccess GHOST_SystemSDL::getButtons(GHOST_Buttons &buttons) const
{
Uint8 state = SDL_GetMouseState(NULL, NULL);
diff --git a/intern/ghost/intern/GHOST_SystemSDL.h b/intern/ghost/intern/GHOST_SystemSDL.h
index e51cc3d5b5d..7dbdc3ccec8 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.h
+++ b/intern/ghost/intern/GHOST_SystemSDL.h
@@ -77,11 +77,6 @@ class GHOST_SystemSDL : public GHOST_System {
GHOST_TSuccess disposeContext(GHOST_IContext *context);
- /**
- * Informs if the system provides native dialogs (eg. confirm quit)
- */
- virtual bool supportsNativeDialogs(void);
-
private:
GHOST_TSuccess init();
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 5d882fd6dcb..9f7b6f75e41 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -1524,7 +1524,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
* message without calling DefWindowProc.
*/
/* we get first WM_SIZE before we fully init.
- * So, do not dispatch before we continiously resizng */
+ * So, do not dispatch before we continuously resizing. */
if (window->m_inLiveResize) {
system->pushEvent(processWindowEvent(GHOST_kEventWindowSize, window));
system->dispatchEvents();
@@ -1560,7 +1560,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
case WM_DPICHANGED:
/* The WM_DPICHANGED message is sent when the effective dots per inch (dpi) for a
* window has changed. The DPI is the scale factor for a window. There are multiple
- * events that can cause the DPI tochange such as when the window is moved to a monitor
+ * events that can cause the DPI to change such as when the window is moved to a monitor
* with a different DPI.
*/
{
@@ -1872,11 +1872,3 @@ int GHOST_SystemWin32::toggleConsole(int action)
return m_consoleStatus;
}
-
-int GHOST_SystemWin32::confirmQuit(GHOST_IWindow *window) const
-{
- return (MessageBox(window ? ((GHOST_WindowWin32 *)window)->getHWND() : 0,
- "Some changes have not been saved.\nDo you really want to quit?",
- "Exit Blender",
- MB_OKCANCEL | MB_ICONWARNING | MB_TOPMOST) == IDOK);
-}
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index 98b18d2c00b..7ac6a3e3e20 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -221,12 +221,6 @@ class GHOST_SystemWin32 : public GHOST_System {
int mouseY,
void *data);
- /**
- * Confirms quitting he program when there is just one window left open
- * in the application
- */
- int confirmQuit(GHOST_IWindow *window) const;
-
protected:
/**
* Initializes the system.
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index c688d7713b2..b95e5fe3846 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -376,11 +376,6 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const STR_String &title,
return window;
}
-bool GHOST_SystemX11::supportsNativeDialogs(void)
-{
- return false;
-}
-
/**
* Create a new offscreen context.
* Never explicitly delete the context, use disposeContext() instead.
diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index f7f33185f9b..1fe94b40f17 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -78,7 +78,7 @@ class GHOST_SystemX11 : public GHOST_System {
public:
/**
* Constructor
- * this class should only be instanciated by GHOST_ISystem.
+ * this class should only be instantiated by GHOST_ISystem.
*/
GHOST_SystemX11();
@@ -91,11 +91,6 @@ class GHOST_SystemX11 : public GHOST_System {
GHOST_TSuccess init();
/**
- * Informs if the system provides native dialogs (eg. confirm quit)
- */
- virtual bool supportsNativeDialogs(void);
-
- /**
* \section Interface Inherited from GHOST_ISystem
*/
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index 8c69b9eb65e..a8cbb874c50 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -1056,8 +1056,6 @@ GHOST_TSuccess GHOST_WindowX11::setState(GHOST_TWindowState state)
return (GHOST_kFailure);
}
-#include <iostream>
-
GHOST_TSuccess GHOST_WindowX11::setOrder(GHOST_TWindowOrder order)
{
if (order == GHOST_kWindowOrderTop) {
diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc
index 91f009b3b57..ec63dccf147 100644
--- a/intern/opencolorio/fallback_impl.cc
+++ b/intern/opencolorio/fallback_impl.cc
@@ -283,7 +283,7 @@ const char *FallbackImpl::configGetDisplay(OCIO_ConstConfigRcPtr * /*config*/, i
const char *FallbackImpl::configGetDefaultView(OCIO_ConstConfigRcPtr * /*config*/,
const char * /*display*/)
{
- return "Default";
+ return "Standard";
}
int FallbackImpl::configGetNumViews(OCIO_ConstConfigRcPtr * /*config*/, const char * /*display*/)
@@ -296,7 +296,7 @@ const char *FallbackImpl::configGetView(OCIO_ConstConfigRcPtr * /*config*/,
int index)
{
if (index == 0) {
- return "Default";
+ return "Standard";
}
return NULL;
}
@@ -363,6 +363,25 @@ int FallbackImpl::colorSpaceIsData(OCIO_ConstColorSpaceRcPtr * /*cs*/)
return 0;
}
+void FallbackImpl::colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr * /*config*/,
+ OCIO_ConstColorSpaceRcPtr *cs,
+ bool &is_scene_linear,
+ bool &is_srgb)
+{
+ if (cs == COLORSPACE_LINEAR) {
+ is_scene_linear = true;
+ is_srgb = false;
+ }
+ else if (cs == COLORSPACE_SRGB) {
+ is_scene_linear = false;
+ is_srgb = true;
+ }
+ else {
+ is_scene_linear = false;
+ is_srgb = false;
+ }
+}
+
void FallbackImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr * /*cs*/)
{
}
diff --git a/intern/opencolorio/ocio_capi.cc b/intern/opencolorio/ocio_capi.cc
index 530d1fb8a27..d259ba73e45 100644
--- a/intern/opencolorio/ocio_capi.cc
+++ b/intern/opencolorio/ocio_capi.cc
@@ -174,6 +174,14 @@ int OCIO_colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs)
return impl->colorSpaceIsData(cs);
}
+void OCIO_colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config,
+ OCIO_ConstColorSpaceRcPtr *cs,
+ bool *is_scene_linear,
+ bool *is_srgb)
+{
+ impl->colorSpaceIsBuiltin(config, cs, *is_scene_linear, *is_srgb);
+}
+
void OCIO_colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs)
{
impl->colorSpaceRelease(cs);
diff --git a/intern/opencolorio/ocio_capi.h b/intern/opencolorio/ocio_capi.h
index 9af302647a3..9ba2d8fb8f9 100644
--- a/intern/opencolorio/ocio_capi.h
+++ b/intern/opencolorio/ocio_capi.h
@@ -31,6 +31,7 @@ struct OCIO_GLSLDrawState;
int unused; \
} * name
+#define OCIO_ROLE_DATA "data"
#define OCIO_ROLE_SCENE_LINEAR "scene_linear"
#define OCIO_ROLE_COLOR_PICKING "color_picking"
#define OCIO_ROLE_TEXTURE_PAINT "texture_paint"
@@ -130,6 +131,10 @@ int OCIO_configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char *
int OCIO_colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs);
int OCIO_colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs);
+void OCIO_colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config,
+ OCIO_ConstColorSpaceRcPtr *cs,
+ bool *is_scene_linear,
+ bool *is_srgb);
void OCIO_colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs);
diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc
index 1b2207bfb53..25c1df70045 100644
--- a/intern/opencolorio/ocio_impl.cc
+++ b/intern/opencolorio/ocio_impl.cc
@@ -18,6 +18,7 @@
*/
#include <iostream>
+#include <math.h>
#include <sstream>
#include <string.h>
@@ -34,6 +35,8 @@ using namespace OCIO_NAMESPACE;
#include "MEM_guardedalloc.h"
+#include "BLI_math_color.h"
+
#include "ocio_impl.h"
#if !defined(WITH_ASSERT_ABORT)
@@ -520,6 +523,86 @@ int OCIOImpl::colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs)
return (*(ConstColorSpaceRcPtr *)cs)->isData();
}
+static float compare_floats(float a, float b, float abs_diff, int ulp_diff)
+{
+ /* Returns true if the absolute difference is smaller than abs_diff (for numbers near zero)
+ * or their relative difference is less than ulp_diff ULPs. Based on:
+ * https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ */
+ if (fabsf(a - b) < abs_diff) {
+ return true;
+ }
+
+ if ((a < 0.0f) != (b < 0.0f)) {
+ return false;
+ }
+
+ return (abs((*(int *)&a) - (*(int *)&b)) < ulp_diff);
+}
+
+void OCIOImpl::colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config_,
+ OCIO_ConstColorSpaceRcPtr *cs_,
+ bool &is_scene_linear,
+ bool &is_srgb)
+{
+ ConstConfigRcPtr *config = (ConstConfigRcPtr *)config_;
+ ConstColorSpaceRcPtr *cs = (ConstColorSpaceRcPtr *)cs_;
+ ConstProcessorRcPtr processor;
+
+ try {
+ processor = (*config)->getProcessor((*cs)->getName(), "scene_linear");
+ }
+ catch (Exception &exception) {
+ /* Silently ignore if no conversion possible, then it's not scene linear or sRGB. */
+ is_scene_linear = false;
+ is_srgb = false;
+ return;
+ }
+
+ is_scene_linear = true;
+ is_srgb = true;
+ for (int i = 0; i < 256; i++) {
+ float v = i / 255.0f;
+
+ float cR[3] = {v, 0, 0};
+ float cG[3] = {0, v, 0};
+ float cB[3] = {0, 0, v};
+ float cW[3] = {v, v, v};
+ processor->applyRGB(cR);
+ processor->applyRGB(cG);
+ processor->applyRGB(cB);
+ processor->applyRGB(cW);
+
+ /* Make sure that there is no channel crosstalk. */
+ if (fabsf(cR[1]) > 1e-5f || fabsf(cR[2]) > 1e-5f || fabsf(cG[0]) > 1e-5f ||
+ fabsf(cG[2]) > 1e-5f || fabsf(cB[0]) > 1e-5f || fabsf(cB[1]) > 1e-5f) {
+ is_scene_linear = false;
+ is_srgb = false;
+ break;
+ }
+ /* Make sure that the three primaries combine linearly. */
+ if (!compare_floats(cR[0], cW[0], 1e-6f, 64) || !compare_floats(cG[1], cW[1], 1e-6f, 64) ||
+ !compare_floats(cB[2], cW[2], 1e-6f, 64)) {
+ is_scene_linear = false;
+ is_srgb = false;
+ break;
+ }
+ /* Make sure that the three channels behave identically. */
+ if (!compare_floats(cW[0], cW[1], 1e-6f, 64) || !compare_floats(cW[1], cW[2], 1e-6f, 64)) {
+ is_scene_linear = false;
+ is_srgb = false;
+ break;
+ }
+
+ float out_v = (cW[0] + cW[1] + cW[2]) * (1.0f / 3.0f);
+ if (!compare_floats(v, out_v, 1e-6f, 64)) {
+ is_scene_linear = false;
+ }
+ if (!compare_floats(srgb_to_linearrgb(v), out_v, 1e-6f, 64)) {
+ is_srgb = false;
+ }
+ }
+}
+
void OCIOImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs)
{
OBJECT_GUARDED_DELETE((ConstColorSpaceRcPtr *)cs, ConstColorSpaceRcPtr);
diff --git a/intern/opencolorio/ocio_impl.h b/intern/opencolorio/ocio_impl.h
index 0952e7e16d0..082aa4a091e 100644
--- a/intern/opencolorio/ocio_impl.h
+++ b/intern/opencolorio/ocio_impl.h
@@ -44,6 +44,10 @@ class IOCIOImpl {
virtual int colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs) = 0;
virtual int colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs) = 0;
+ virtual void colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config,
+ OCIO_ConstColorSpaceRcPtr *cs,
+ bool &is_scene_linear,
+ bool &is_srgb) = 0;
virtual void colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs) = 0;
@@ -160,6 +164,10 @@ class FallbackImpl : public IOCIOImpl {
int colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs);
int colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs);
+ void colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config,
+ OCIO_ConstColorSpaceRcPtr *cs,
+ bool &is_scene_linear,
+ bool &is_srgb);
void colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs);
@@ -266,6 +274,10 @@ class OCIOImpl : public IOCIOImpl {
int colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs);
int colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs);
+ void colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config,
+ OCIO_ConstColorSpaceRcPtr *cs,
+ bool &is_scene_linear,
+ bool &is_srgb);
void colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs);