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:
authorTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2013-01-27 03:49:13 +0400
committerTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2013-01-27 03:49:13 +0400
commit556912792ad3c37c294256a558c96b39f264e7b5 (patch)
tree9b6ee8cf1ad92ee89c04f27a89be11599c5b40c0 /intern
parent9251d628db0abe599d927d79170025d8545c8ace (diff)
parentc84383301c5a2582e95259a7e4468a23a3566401 (diff)
Merged changes in the trunk up to revision 54110.
Conflicts resolved: source/blender/blenfont/SConscript source/blender/blenkernel/intern/subsurf_ccg.c source/blender/makesdna/intern/makesdna.c source/blender/makesrna/intern/rna_scene.c
Diffstat (limited to 'intern')
-rw-r--r--intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp13
-rw-r--r--intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp15
-rw-r--r--intern/cycles/CMakeLists.txt4
-rw-r--r--intern/cycles/SConscript3
-rw-r--r--intern/cycles/app/cycles_xml.cpp16
-rw-r--r--intern/cycles/blender/addon/__init__.py7
-rw-r--r--intern/cycles/blender/addon/engine.py2
-rw-r--r--intern/cycles/blender/addon/osl.py17
-rw-r--r--intern/cycles/blender/addon/properties.py29
-rw-r--r--intern/cycles/blender/addon/ui.py245
-rw-r--r--intern/cycles/blender/blender_curves.cpp203
-rw-r--r--intern/cycles/blender/blender_session.cpp124
-rw-r--r--intern/cycles/blender/blender_session.h5
-rw-r--r--intern/cycles/blender/blender_shader.cpp46
-rw-r--r--intern/cycles/blender/blender_sync.cpp10
-rw-r--r--intern/cycles/blender/blender_util.h18
-rw-r--r--intern/cycles/bvh/bvh.cpp16
-rw-r--r--intern/cycles/bvh/bvh_build.cpp20
-rw-r--r--intern/cycles/device/device_cuda.cpp18
-rw-r--r--intern/cycles/device/device_opencl.cpp2
-rw-r--r--intern/cycles/kernel/kernel_accumulate.h55
-rw-r--r--intern/cycles/kernel/kernel_bvh.h457
-rw-r--r--intern/cycles/kernel/kernel_camera.h2
-rw-r--r--intern/cycles/kernel/kernel_light.h9
-rw-r--r--intern/cycles/kernel/kernel_path.h5
-rw-r--r--intern/cycles/kernel/kernel_primitive.h2
-rw-r--r--intern/cycles/kernel/kernel_shader.h2
-rw-r--r--intern/cycles/kernel/kernel_types.h18
-rw-r--r--intern/cycles/kernel/shaders/node_normal_map.osl20
-rw-r--r--intern/cycles/kernel/svm/svm_tex_coord.h17
-rw-r--r--intern/cycles/render/camera.cpp4
-rw-r--r--intern/cycles/render/camera.h2
-rw-r--r--intern/cycles/render/curves.cpp112
-rw-r--r--intern/cycles/render/curves.h13
-rw-r--r--intern/cycles/render/graph.cpp3
-rw-r--r--intern/cycles/render/image.cpp151
-rw-r--r--intern/cycles/render/image.h10
-rw-r--r--intern/cycles/render/light.cpp4
-rw-r--r--intern/cycles/render/mesh.cpp38
-rw-r--r--intern/cycles/render/mesh.h1
-rw-r--r--intern/cycles/render/nodes.cpp18
-rw-r--r--intern/cycles/render/nodes.h2
-rw-r--r--intern/cycles/render/object.cpp30
-rw-r--r--intern/cycles/util/util_cuda.cpp22
-rw-r--r--intern/cycles/util/util_cuda.h1
-rw-r--r--intern/cycles/util/util_task.cpp7
-rw-r--r--intern/cycles/util/util_task.h1
-rw-r--r--intern/dualcon/intern/MemoryAllocator.h2
-rw-r--r--intern/ffmpeg/ffmpeg_compat.h59
-rw-r--r--intern/ghost/GHOST_C-api.h2
-rw-r--r--intern/ghost/GHOST_ISystem.h2
-rw-r--r--intern/ghost/GHOST_IWindow.h4
-rw-r--r--intern/ghost/GHOST_Types.h1
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp8
-rw-r--r--intern/ghost/intern/GHOST_Debug.h17
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerWin32.cpp32
-rw-r--r--intern/ghost/intern/GHOST_System.cpp7
-rw-r--r--intern/ghost/intern/GHOST_System.h3
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm22
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp4
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp314
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h38
-rw-r--r--intern/ghost/intern/GHOST_Window.cpp3
-rw-r--r--intern/ghost/intern/GHOST_Window.h10
-rw-r--r--intern/ghost/intern/GHOST_WindowCarbon.cpp3
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.h5
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm28
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp227
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.h30
-rw-r--r--intern/guardedalloc/intern/mallocn.c31
-rw-r--r--intern/locale/boost_locale_wrapper.cpp30
-rw-r--r--intern/locale/boost_locale_wrapper.h3
72 files changed, 1861 insertions, 843 deletions
diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
index 0a3d0f8e85a..831e1998182 100644
--- a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
+++ b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
@@ -107,7 +107,7 @@ void AUD_FFMPEGReader::init()
m_position = 0;
m_pkgbuf_left = 0;
- if(av_find_stream_info(m_formatCtx)<0)
+ if(avformat_find_stream_info(m_formatCtx, NULL) < 0)
AUD_THROW(AUD_ERROR_FFMPEG, streaminfo_error);
// find audio stream and codec
@@ -133,7 +133,7 @@ void AUD_FFMPEGReader::init()
if(!aCodec)
AUD_THROW(AUD_ERROR_FFMPEG, nodecoder_error);
- if(avcodec_open(m_codecCtx, aCodec)<0)
+ if(avcodec_open2(m_codecCtx, aCodec, NULL) < 0)
AUD_THROW(AUD_ERROR_FFMPEG, codecopen_error);
// XXX this prints file information to stdout:
@@ -236,14 +236,7 @@ AUD_FFMPEGReader::AUD_FFMPEGReader(boost::shared_ptr<AUD_Buffer> buffer) :
AUD_FFMPEGReader::~AUD_FFMPEGReader()
{
avcodec_close(m_codecCtx);
-
- if(m_aviocontext)
- {
- avformat_close_input(&m_formatCtx);
- av_free(m_aviocontext);
- }
- else
- av_close_input_file(m_formatCtx);
+ avformat_close_input(&m_formatCtx);
}
int AUD_FFMPEGReader::read_packet(void* opaque, uint8_t* buf, int buf_size)
diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
index 2b34348da81..55040e4db8e 100644
--- a/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
+++ b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
@@ -55,10 +55,15 @@ AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs,
{
static const char* formats[] = { NULL, "ac3", "flac", "matroska", "mp2", "mp3", "ogg", "wav" };
- if(avformat_alloc_output_context2(&m_formatCtx, NULL, formats[format], filename.c_str()))
- AUD_THROW(AUD_ERROR_FFMPEG, context_error);
+ m_formatCtx = avformat_alloc_context();
+ if (!m_formatCtx) AUD_THROW(AUD_ERROR_FFMPEG, context_error);
- m_outputFmt = m_formatCtx->oformat;
+ strcpy(m_formatCtx->filename, filename.c_str());
+ m_outputFmt = m_formatCtx->oformat = av_guess_format(formats[format], filename.c_str(), NULL);
+ if (!m_outputFmt) {
+ avformat_free_context(m_formatCtx);
+ AUD_THROW(AUD_ERROR_FFMPEG, context_error);
+ }
switch(codec)
{
@@ -116,7 +121,7 @@ AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs,
if(m_outputFmt->audio_codec == CODEC_ID_NONE)
AUD_THROW(AUD_ERROR_SPECS, codec_error);
- m_stream = av_new_stream(m_formatCtx, 0);
+ m_stream = avformat_new_stream(m_formatCtx, NULL);
if(!m_stream)
AUD_THROW(AUD_ERROR_FFMPEG, stream_error);
@@ -164,7 +169,7 @@ AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs,
if(!codec)
AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
- if(avcodec_open(m_codecCtx, codec))
+ if(avcodec_open2(m_codecCtx, codec, NULL))
AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
m_output_buffer.resize(FF_MIN_BUFFER_SIZE);
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index 3242acf3edd..048a2a50a7f 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -47,10 +47,6 @@ if(WITH_CYCLES_OSL)
include_directories(${OSL_INCLUDES})
endif()
-if(WITH_CYCLES_CUDA_BINARIES)
- add_definitions(-DWITH_CUDA_BINARIES)
-endif()
-
add_definitions(-DWITH_OPENCL)
add_definitions(-DWITH_CUDA)
add_definitions(-DWITH_MULTI)
diff --git a/intern/cycles/SConscript b/intern/cycles/SConscript
index dcb684c4be7..44a17ac0cd6 100644
--- a/intern/cycles/SConscript
+++ b/intern/cycles/SConscript
@@ -53,9 +53,6 @@ if env['WITH_BF_CYCLES_OSL']:
defs.append('WITH_OSL')
incs.append(cycles['BF_OSL_INC'])
-if env['WITH_BF_CYCLES_CUDA_BINARIES']:
- defs.append('WITH_CUDA_BINARIES')
-
incs.extend('. bvh render device kernel kernel/osl kernel/svm util subd'.split())
incs.extend('#intern/guardedalloc #source/blender/makesrna #source/blender/makesdna'.split())
incs.extend('#source/blender/blenloader ../../source/blender/makesrna/intern'.split())
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index 5de9d71b8cc..40fbb7af556 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -233,16 +233,16 @@ static void xml_read_film(const XMLReadState& state, pugi::xml_node node)
float aspect = (float)cam->width/(float)cam->height;
if(cam->width >= cam->height) {
- cam->left = -aspect;
- cam->right = aspect;
- cam->bottom = -1.0f;
- cam->top = 1.0f;
+ cam->viewplane.left = -aspect;
+ cam->viewplane.right = aspect;
+ cam->viewplane.bottom = -1.0f;
+ cam->viewplane.top = 1.0f;
}
else {
- cam->left = -1.0f;
- cam->right = 1.0f;
- cam->bottom = -1.0f/aspect;
- cam->top = 1.0f/aspect;
+ cam->viewplane.left = -1.0f;
+ cam->viewplane.right = 1.0f;
+ cam->viewplane.bottom = -1.0f/aspect;
+ cam->viewplane.top = 1.0f/aspect;
}
cam->need_update = true;
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index dddf7bafb14..36fb5c0418d 100644
--- a/intern/cycles/blender/addon/__init__.py
+++ b/intern/cycles/blender/addon/__init__.py
@@ -34,13 +34,13 @@ import bpy
from . import engine
+
class CyclesRender(bpy.types.RenderEngine):
bl_idname = 'CYCLES'
bl_label = "Cycles Render"
bl_use_shading_nodes = True
def __init__(self):
- engine.init()
self.session = None
def __del__(self):
@@ -69,7 +69,7 @@ class CyclesRender(bpy.types.RenderEngine):
def view_update(self, context):
if not self.session:
engine.create(self, context.blend_data, context.scene,
- context.region, context.space_data, context.region_data)
+ context.region, context.space_data, context.region_data)
engine.update(self, context.blend_data, context.scene)
def view_draw(self, context):
@@ -88,6 +88,8 @@ def register():
from . import properties
from . import presets
+ engine.init()
+
properties.register()
ui.register()
presets.register()
@@ -103,4 +105,3 @@ def unregister():
properties.unregister()
presets.unregister()
bpy.utils.unregister_module(__name__)
-
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index 9641128d994..ef700ba26f1 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -18,6 +18,7 @@
# <pep8 compliant>
+
def init():
import bpy
import _cycles
@@ -89,4 +90,3 @@ def available_devices():
def with_osl():
import _cycles
return _cycles.with_osl
-
diff --git a/intern/cycles/blender/addon/osl.py b/intern/cycles/blender/addon/osl.py
index 79ce3df20c3..0a67edac1e3 100644
--- a/intern/cycles/blender/addon/osl.py
+++ b/intern/cycles/blender/addon/osl.py
@@ -18,10 +18,13 @@
# <pep8 compliant>
-import bpy, _cycles, os, tempfile
+import bpy
+import _cycles
+
-# compile .osl file with given filepath to temporary .oso file
def osl_compile(input_path, report):
+ """compile .osl file with given filepath to temporary .oso file"""
+ import tempfile
output_file = tempfile.NamedTemporaryFile(mode='w', suffix=".oso", delete=False)
output_path = output_file.name
output_file.close()
@@ -33,9 +36,12 @@ def osl_compile(input_path, report):
return ok, output_path
-# compile and update shader script node
+
def update_script_node(node, report):
- import os, shutil
+ """compile and update shader script node"""
+ import os
+ import shutil
+ import tempfile
if node.mode == 'EXTERNAL':
# compile external script file
@@ -103,7 +109,7 @@ def update_script_node(node, report):
report({'ERROR'}, "Can't read OSO bytecode to store in node at %r" % oso_path)
ok = False
-
+
else:
report({'WARNING'}, "No text or file specified in node, nothing to compile")
return
@@ -125,4 +131,3 @@ def update_script_node(node, report):
pass
return ok
-
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 8b90b0bd4ff..3661274ae43 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -74,13 +74,14 @@ enum_curve_presets = (
enum_curve_primitives = (
('TRIANGLES', "Triangles", "Create triangle geometry around strands"),
('LINE_SEGMENTS', "Line Segments", "Use line segment primitives"),
- ('CURVE_SEGMENTS', "?Curve Segments?", "Use curve segment primitives (not implemented)"),
+ ('CURVE_SEGMENTS', "Curve Segments", "Use segmented cardinal curve primitives"),
+ ('CURVE_RIBBONS', "Curve Ribbons", "Use smooth cardinal curve ribbon primitives"),
)
enum_triangle_curves = (
- ('CAMERA', "Planes", "Create individual triangles forming planes that face camera"),
- ('RIBBONS', "Ribbons", "Create individual triangles forming ribbon"),
- ('TESSELLATED', "Tessellated", "Create mesh surrounding each strand"),
+ ('CAMERA_TRIANGLES', "Planes", "Create individual triangles forming planes that face camera"),
+ ('RIBBON_TRIANGLES', "Ribbons", "Create individual triangles forming ribbon"),
+ ('TESSELLATED_TRIANGLES', "Tessellated", "Create mesh surrounding each strand"),
)
enum_line_curves = (
@@ -95,7 +96,7 @@ enum_curves_interpolation = (
('CARDINAL', "Cardinal interpolation", "Use cardinal interpolation between segments"),
('BSPLINE', "B-spline interpolation", "Use b-spline interpolation between segments"),
)
-
+
enum_tile_order = (
('CENTER', "Center", "Render from center to the edges"),
('RIGHT_TO_LEFT', "Right to Left", "Render from right to left"),
@@ -104,6 +105,7 @@ enum_tile_order = (
('BOTTOM_TO_TOP', "Bottom to Top", "Render from bottom to top"),
)
+
class CyclesRenderSettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
@@ -619,6 +621,7 @@ class CyclesMeshSettings(bpy.types.PropertyGroup):
del bpy.types.Curve.cycles
del bpy.types.MetaBall.cycles
+
class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
@@ -643,7 +646,7 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
name="Mesh Geometry",
description="Method for creating triangle geometry",
items=enum_triangle_curves,
- default='CAMERA',
+ default='CAMERA_TRIANGLES',
)
cls.line_method = EnumProperty(
name="Intersection Method",
@@ -682,10 +685,6 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
description="Correct the tangent normal for the strand's slope",
default=False,
)
- cls.use_cache = BoolProperty(
- name="Export Cached data",
- default=True,
- )
cls.use_parents = BoolProperty(
name="Use parent strands",
description="Use parents with children",
@@ -705,7 +704,7 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
name="Use Cycles Hair Rendering",
description="Activate Cycles hair rendering for particle system",
default=True,
- )
+ )
cls.segments = IntProperty(
name="Segments",
description="Number of segments between path keys (note that this combines with the 'draw step' value)",
@@ -730,11 +729,18 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
min=0, max=100.0,
default=1.01,
)
+ cls.subdivisions = IntProperty(
+ name="Subdivisions",
+ description="Number of subdivisions used in Cardinal curve intersection (power of 2)",
+ min=0, max=24,
+ default=3,
+ )
@classmethod
def unregister(cls):
del bpy.types.Scene.cycles_curves
+
class CyclesCurveSettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
@@ -771,6 +777,7 @@ class CyclesCurveSettings(bpy.types.PropertyGroup):
def unregister(cls):
del bpy.types.ParticleSettings.cycles
+
def register():
bpy.utils.register_class(CyclesRenderSettings)
bpy.utils.register_class(CyclesCameraSettings)
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 6a3a0c63236..ccc2a0ecbda 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -976,84 +976,96 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel):
slot = part.texture_slots[part.active_texture_index]
layout.template_ID(slot, "texture", new="texture.new")
+
class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel):
bl_label = "Cycles Hair Rendering"
bl_context = "particle"
-
+
@classmethod
def poll(cls, context):
+ scene = context.scene
+ cscene = scene.cycles
psys = context.particle_system
device_type = context.user_preferences.system.compute_device_type
- experimental = context.scene.cycles.feature_set == 'EXPERIMENTAL' and (context.scene.cycles.device == 'CPU' or device_type == 'NONE')
+ experimental = ((cscene.feature_set == 'EXPERIMENTAL') and (cscene.device == 'CPU' or device_type == 'NONE'))
return CyclesButtonsPanel.poll(context) and experimental and psys
-
+
def draw_header(self, context):
- cscene = context.scene.cycles_curves
- self.layout.prop(cscene, "use_curves", text="")
-
+ ccscene = context.scene.cycles_curves
+ self.layout.prop(ccscene, "use_curves", text="")
+
def draw(self, context):
layout = self.layout
-
+
scene = context.scene
- cscene = scene.cycles_curves
-
- layout.active = cscene.use_curves
-
- layout.prop(cscene, "preset", text="Mode")
-
- if cscene.preset == 'CUSTOM':
- layout.prop(cscene, "primitive", text="Primitive")
-
- if cscene.primitive == 'TRIANGLES':
- layout.prop(cscene, "triangle_method", text="Method")
- if cscene.triangle_method == 'TESSELLATED':
- layout.prop(cscene, "resolution", text="Resolution")
- layout.prop(cscene, "use_smooth", text="Smooth")
- elif cscene.primitive == 'LINE_SEGMENTS':
- layout.prop(cscene, "use_backfacing", text="Check back-faces")
-
+ ccscene = scene.cycles_curves
+
+ layout.active = ccscene.use_curves
+
+ layout.prop(ccscene, "preset", text="Mode")
+
+ if ccscene.preset == 'CUSTOM':
+ layout.prop(ccscene, "primitive", text="Primitive")
+
+ if ccscene.primitive == 'TRIANGLES':
+ layout.prop(ccscene, "triangle_method", text="Method")
+ if ccscene.triangle_method == 'TESSELLATED_TRIANGLES':
+ layout.prop(ccscene, "resolution", text="Resolution")
+ layout.prop(ccscene, "use_smooth", text="Smooth")
+ elif ccscene.primitive == 'LINE_SEGMENTS':
+ layout.prop(ccscene, "use_backfacing", text="Check back-faces")
+
row = layout.row()
- row.prop(cscene, "use_encasing", text="Exclude encasing")
+ row.prop(ccscene, "use_encasing", text="Exclude encasing")
sub = row.row()
- sub.active = cscene.use_encasing
- sub.prop(cscene, "encasing_ratio", text="Ratio for encasing")
-
- layout.prop(cscene, "line_method", text="Method")
- layout.prop(cscene, "use_tangent_normal", text="Use tangent normal as default")
- layout.prop(cscene, "use_tangent_normal_geometry", text="Use tangent normal geometry")
- layout.prop(cscene, "use_tangent_normal_correction", text="Correct tangent normal for slope")
- layout.prop(cscene, "interpolation", text="Interpolation")
-
+ sub.active = ccscene.use_encasing
+ sub.prop(ccscene, "encasing_ratio", text="Ratio for encasing")
+
+ layout.prop(ccscene, "line_method", text="Method")
+ layout.prop(ccscene, "use_tangent_normal", text="Use tangent normal as default")
+ layout.prop(ccscene, "use_tangent_normal_geometry", text="Use tangent normal geometry")
+ layout.prop(ccscene, "use_tangent_normal_correction", text="Correct tangent normal for slope")
+ layout.prop(ccscene, "interpolation", text="Interpolation")
+
+ row = layout.row()
+ row.prop(ccscene, "segments", text="Segments")
+ row.prop(ccscene, "normalmix", text="Ray Mix")
+ elif ccscene.primitive in {'CURVE_SEGMENTS', 'CURVE_RIBBONS'}:
+ layout.prop(ccscene, "subdivisions", text="Curve subdivisions")
+ layout.prop(ccscene, "use_backfacing", text="Check back-faces")
+
+ layout.prop(ccscene, "interpolation", text="Interpolation")
row = layout.row()
- row.prop(cscene, "segments", text="Segments")
- row.prop(cscene, "normalmix", text="Ray Mix")
-
+ row.prop(ccscene, "segments", text="Segments")
+
row = layout.row()
- row.prop(cscene, "use_cache", text="Export cache with children")
- if cscene.use_cache:
- row.prop(cscene, "use_parents", text="Include parents")
-
+ row.prop(ccscene, "use_parents", text="Include parents")
+
+
class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel):
bl_label = "Cycles Hair Settings"
bl_context = "particle"
-
+
@classmethod
def poll(cls, context):
- use_curves = context.scene.cycles_curves.use_curves and context.particle_system
+ scene = context.scene
+ cscene = scene.cycles
+ ccscene = scene.cycles_curves
+ use_curves = ccscene.use_curves and context.particle_system
device_type = context.user_preferences.system.compute_device_type
- experimental = context.scene.cycles.feature_set == 'EXPERIMENTAL' and (context.scene.cycles.device == 'CPU' or device_type == 'NONE')
+ experimental = cscene.feature_set == 'EXPERIMENTAL' and (cscene.device == 'CPU' or device_type == 'NONE')
return CyclesButtonsPanel.poll(context) and experimental and use_curves
def draw(self, context):
layout = self.layout
-
+
psys = context.particle_settings
cpsys = psys.cycles
-
+
row = layout.row()
row.prop(cpsys, "shape", text="Shape")
row.prop(cpsys, "use_closetip", text="Close tip")
-
+
layout.label(text="Width multiplier:")
row = layout.row()
row.prop(cpsys, "root_width", text="Root")
@@ -1120,74 +1132,79 @@ def draw_pause(self, context):
def get_panels():
+ types = bpy.types
return (
- bpy.types.RENDER_PT_render,
- bpy.types.RENDER_PT_output,
- bpy.types.RENDER_PT_encoding,
- bpy.types.RENDER_PT_dimensions,
- bpy.types.RENDER_PT_stamp,
- bpy.types.SCENE_PT_scene,
- bpy.types.SCENE_PT_audio,
- bpy.types.SCENE_PT_unit,
- bpy.types.SCENE_PT_keying_sets,
- bpy.types.SCENE_PT_keying_set_paths,
- bpy.types.SCENE_PT_physics,
- bpy.types.WORLD_PT_context_world,
- bpy.types.DATA_PT_context_mesh,
- bpy.types.DATA_PT_context_camera,
- bpy.types.DATA_PT_context_lamp,
- bpy.types.DATA_PT_context_speaker,
- bpy.types.DATA_PT_texture_space,
- bpy.types.DATA_PT_curve_texture_space,
- bpy.types.DATA_PT_mball_texture_space,
- bpy.types.DATA_PT_vertex_groups,
- bpy.types.DATA_PT_shape_keys,
- bpy.types.DATA_PT_uv_texture,
- bpy.types.DATA_PT_vertex_colors,
- bpy.types.DATA_PT_camera,
- bpy.types.DATA_PT_camera_display,
- bpy.types.DATA_PT_lens,
- bpy.types.DATA_PT_speaker,
- bpy.types.DATA_PT_distance,
- bpy.types.DATA_PT_cone,
- bpy.types.DATA_PT_customdata,
- bpy.types.DATA_PT_custom_props_mesh,
- bpy.types.DATA_PT_custom_props_camera,
- bpy.types.DATA_PT_custom_props_lamp,
- bpy.types.DATA_PT_custom_props_speaker,
- bpy.types.TEXTURE_PT_clouds,
- bpy.types.TEXTURE_PT_wood,
- bpy.types.TEXTURE_PT_marble,
- bpy.types.TEXTURE_PT_magic,
- bpy.types.TEXTURE_PT_blend,
- bpy.types.TEXTURE_PT_stucci,
- bpy.types.TEXTURE_PT_image,
- bpy.types.TEXTURE_PT_image_sampling,
- bpy.types.TEXTURE_PT_image_mapping,
- bpy.types.TEXTURE_PT_musgrave,
- bpy.types.TEXTURE_PT_voronoi,
- bpy.types.TEXTURE_PT_distortednoise,
- bpy.types.TEXTURE_PT_voxeldata,
- bpy.types.TEXTURE_PT_pointdensity,
- bpy.types.TEXTURE_PT_pointdensity_turbulence,
- bpy.types.TEXTURE_PT_mapping,
- bpy.types.TEXTURE_PT_influence,
- bpy.types.TEXTURE_PT_colors,
- bpy.types.PARTICLE_PT_context_particles,
- bpy.types.PARTICLE_PT_emission,
- bpy.types.PARTICLE_PT_hair_dynamics,
- bpy.types.PARTICLE_PT_cache,
- bpy.types.PARTICLE_PT_velocity,
- bpy.types.PARTICLE_PT_rotation,
- bpy.types.PARTICLE_PT_physics,
- bpy.types.PARTICLE_PT_boidbrain,
- bpy.types.PARTICLE_PT_render,
- bpy.types.PARTICLE_PT_draw,
- bpy.types.PARTICLE_PT_children,
- bpy.types.PARTICLE_PT_field_weights,
- bpy.types.PARTICLE_PT_force_fields,
- bpy.types.PARTICLE_PT_vertexgroups,
- bpy.types.PARTICLE_PT_custom_props,
+ types.RENDER_PT_render,
+ types.RENDER_PT_output,
+ types.RENDER_PT_encoding,
+ types.RENDER_PT_dimensions,
+ types.RENDER_PT_stamp,
+ types.SCENE_PT_scene,
+ types.SCENE_PT_color_management,
+ types.SCENE_PT_audio,
+ types.SCENE_PT_unit,
+ types.SCENE_PT_keying_sets,
+ types.SCENE_PT_keying_set_paths,
+ types.SCENE_PT_physics,
+ types.WORLD_PT_context_world,
+ types.DATA_PT_context_mesh,
+ types.DATA_PT_context_camera,
+ types.DATA_PT_context_lamp,
+ types.DATA_PT_context_speaker,
+ types.DATA_PT_texture_space,
+ types.DATA_PT_curve_texture_space,
+ types.DATA_PT_mball_texture_space,
+ types.DATA_PT_vertex_groups,
+ types.DATA_PT_shape_keys,
+ types.DATA_PT_uv_texture,
+ types.DATA_PT_vertex_colors,
+ types.DATA_PT_camera,
+ types.DATA_PT_camera_display,
+ types.DATA_PT_lens,
+ types.DATA_PT_speaker,
+ types.DATA_PT_distance,
+ types.DATA_PT_cone,
+ types.DATA_PT_customdata,
+ types.DATA_PT_custom_props_mesh,
+ types.DATA_PT_custom_props_camera,
+ types.DATA_PT_custom_props_lamp,
+ types.DATA_PT_custom_props_speaker,
+ types.TEXTURE_PT_clouds,
+ types.TEXTURE_PT_wood,
+ types.TEXTURE_PT_marble,
+ types.TEXTURE_PT_magic,
+ types.TEXTURE_PT_blend,
+ types.TEXTURE_PT_stucci,
+ types.TEXTURE_PT_image,
+ types.TEXTURE_PT_image_sampling,
+ types.TEXTURE_PT_image_mapping,
+ types.TEXTURE_PT_musgrave,
+ types.TEXTURE_PT_voronoi,
+ types.TEXTURE_PT_distortednoise,
+ types.TEXTURE_PT_voxeldata,
+ types.TEXTURE_PT_pointdensity,
+ types.TEXTURE_PT_pointdensity_turbulence,
+ types.TEXTURE_PT_mapping,
+ types.TEXTURE_PT_influence,
+ types.TEXTURE_PT_colors,
+ types.PARTICLE_PT_context_particles,
+ types.PARTICLE_PT_emission,
+ types.PARTICLE_PT_hair_dynamics,
+ types.PARTICLE_PT_cache,
+ types.PARTICLE_PT_velocity,
+ types.PARTICLE_PT_rotation,
+ types.PARTICLE_PT_physics,
+ types.SCENE_PT_rigid_body_world,
+ types.SCENE_PT_rigid_body_cache,
+ types.SCENE_PT_rigid_body_field_weights,
+ types.PARTICLE_PT_boidbrain,
+ types.PARTICLE_PT_render,
+ types.PARTICLE_PT_draw,
+ types.PARTICLE_PT_children,
+ types.PARTICLE_PT_field_weights,
+ types.PARTICLE_PT_force_fields,
+ types.PARTICLE_PT_vertexgroups,
+ types.PARTICLE_PT_custom_props,
)
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index 41e1249dae7..cf2c018f1a2 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -37,8 +37,7 @@ void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, floa
void interp_weights(float t, float data[4], int type);
float shaperadius(float shape, float root, float tip, float time);
void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData, int interpolation);
-bool ObtainParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData);
-bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents);
+bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, int uv_num);
bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, int vcol_num);
bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents);
void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, float3 RotCam);
@@ -152,93 +151,6 @@ void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyl
curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t);
}
-bool ObtainParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData)
-{
-
- int curvenum = 0;
- int keyno = 0;
-
- if(!(mesh && b_mesh && b_ob && CData))
- return false;
-
- BL::Object::modifiers_iterator b_mod;
- for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) {
-
- BL::ParticleSystemModifier psmd(b_mod->ptr);
-
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
-
- BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
-
- if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) {
-
- int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1);
- int shader = mesh->used_shaders[mi];
-
- int totcurves = b_psys.particles.length();
-
- if(totcurves == 0)
- continue;
-
- PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
-
- CData->psys_firstcurve.push_back(curvenum);
- CData->psys_curvenum.push_back(totcurves);
- CData->psys_shader.push_back(shader);
-
- float radius = b_psys.settings().particle_size() * 0.5f;
-
- CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
- CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
- CData->psys_shape.push_back(get_float(cpsys, "shape"));
- CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
-
- BL::ParticleSystem::particles_iterator b_pa;
- for(b_psys.particles.begin(b_pa); b_pa != b_psys.particles.end(); ++b_pa) {
- CData->curve_firstkey.push_back(keyno);
-
- int keylength = b_pa->hair_keys.length();
- CData->curve_keynum.push_back(keylength);
-
- float curve_length = 0.0f;
- float3 pcKey;
- int step_no = 0;
- BL::Particle::hair_keys_iterator b_cKey;
- for(b_pa->hair_keys.begin(b_cKey); b_cKey != b_pa->hair_keys.end(); ++b_cKey) {
- float nco[3];
- b_cKey->co_object( *b_ob, psmd, *b_pa, nco);
- float3 cKey = make_float3(nco[0],nco[1],nco[2]);
- if(step_no > 0)
- curve_length += len(cKey - pcKey);
- CData->curvekey_co.push_back(cKey);
- CData->curvekey_time.push_back(curve_length);
- pcKey = cKey;
- keyno++;
- step_no++;
- }
-
- CData->curve_length.push_back(curve_length);
- /*add uvs*/
- BL::Mesh::tessface_uv_textures_iterator l;
- b_mesh->tessface_uv_textures.begin(l);
-
- float3 uv = make_float3(0.0f, 0.0f, 0.0f);
- if(b_mesh->tessface_uv_textures.length())
- b_pa->uv_on_emitter(psmd,&uv.x);
- CData->curve_uv.push_back(uv);
-
- curvenum++;
-
- }
- }
- }
- }
-
- return true;
-
-}
-
bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents)
{
@@ -328,7 +240,7 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
}
-bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents)
+bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, int uv_num)
{
#if 0
int keyno = 0;
@@ -342,6 +254,8 @@ bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Parti
Transform itfm = transform_quick_inverse(tfm);
#endif
+ CData->curve_uv.clear();
+
BL::Object::modifiers_iterator b_mod;
for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) {
@@ -384,7 +298,7 @@ bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Parti
float3 uv = make_float3(0.0f, 0.0f, 0.0f);
if(b_mesh->tessface_uv_textures.length())
- b_psys.uv_on_emitter(psmd, *b_pa, pa_no, &uv.x);
+ b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
CData->curve_uv.push_back(uv);
if(pa_no < totparts && b_pa != b_psys.particles.end())
@@ -413,6 +327,8 @@ bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
Transform itfm = transform_quick_inverse(tfm);
#endif
+ CData->curve_vcol.clear();
+
BL::Object::modifiers_iterator b_mod;
for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) {
@@ -782,10 +698,8 @@ static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CDa
if(!(mesh->curves.empty() && mesh->curve_keys.empty()))
return;
- Attribute *attr_uv = NULL, *attr_intercept = NULL;
+ Attribute *attr_intercept = NULL;
- if(mesh->need_attribute(scene, ATTR_STD_UV))
- attr_uv = mesh->curve_attributes.add(ATTR_STD_UV);
if(mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT))
attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT);
@@ -831,9 +745,6 @@ static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CDa
}
mesh->add_curve(num_keys, num_curve_keys, CData->psys_shader[sys]);
- if(attr_uv)
- attr_uv->add(CData->curve_uv[curve]);
-
num_keys += num_curve_keys;
num_curves++;
}
@@ -929,11 +840,11 @@ void BlenderSync::sync_curve_settings()
curve_system_manager->resolution = get_int(csscene, "resolution");
curve_system_manager->segments = get_int(csscene, "segments");
curve_system_manager->use_smooth = get_boolean(csscene, "use_smooth");
+ curve_system_manager->subdivisions = get_int(csscene, "subdivisions");
curve_system_manager->normalmix = get_float(csscene, "normalmix");
curve_system_manager->encasing_ratio = get_float(csscene, "encasing_ratio");
- curve_system_manager->use_cache = get_boolean(csscene, "use_cache");
curve_system_manager->use_parents = get_boolean(csscene, "use_parents");
curve_system_manager->use_encasing = get_boolean(csscene, "use_encasing");
curve_system_manager->use_backfacing = get_boolean(csscene, "use_backfacing");
@@ -947,7 +858,6 @@ void BlenderSync::sync_curve_settings()
curve_system_manager->interpolation = CURVE_CARDINAL;
curve_system_manager->normalmix = 1.0f;
curve_system_manager->encasing_ratio = 1.01f;
- curve_system_manager->use_cache = true;
curve_system_manager->use_parents = false;
curve_system_manager->segments = 1;
curve_system_manager->use_joined = false;
@@ -1028,7 +938,6 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
int resolution = scene->curve_system_manager->resolution;
int segments = scene->curve_system_manager->segments;
bool use_smooth = scene->curve_system_manager->use_smooth;
- bool use_cache = scene->curve_system_manager->use_cache;
bool use_parents = scene->curve_system_manager->use_parents;
bool export_tgs = scene->curve_system_manager->use_joined;
@@ -1036,12 +945,7 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
ParticleCurveData CData;
- if(use_cache) {
- ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, use_parents);
- ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, use_parents);
- }
- else
- ObtainParticleData(mesh, &b_mesh, &b_ob, &CData);
+ ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, use_parents);
/* attach strands to mesh */
BL::Object b_CamOb = b_scene.camera();
@@ -1055,11 +959,12 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
if(primitive == CURVE_TRIANGLES){
int vert_num = mesh->triangles.size() * 3;
- if(triangle_method == CURVE_CAMERA) {
+ ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, use_parents, 0);
+ if(triangle_method == CURVE_CAMERA_TRIANGLES) {
ExportCurveTrianglePlanes(mesh, &CData, interpolation, use_smooth, segments, RotCam);
ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, 1);
}
- else if(triangle_method == CURVE_RIBBONS) {
+ else if(triangle_method == CURVE_RIBBON_TRIANGLES) {
ExportCurveTriangleRibbons(mesh, &CData, interpolation, use_smooth, segments);
ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, 1);
}
@@ -1088,44 +993,74 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
/* generated coordinates from first key. we should ideally get this from
* blender to handle deforming objects */
- if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
- float3 loc, size;
- mesh_texture_space(b_mesh, loc, size);
+ {
+ if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
+ float3 loc, size;
+ mesh_texture_space(b_mesh, loc, size);
+
+ Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED);
+ float3 *generated = attr_generated->data_float3();
+ size_t i = 0;
+
+ foreach(Mesh::Curve& curve, mesh->curves) {
+ float3 co = mesh->curve_keys[curve.first_key].co;
+ generated[i++] = co*size - loc;
+ }
+ }
+ }
- Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED);
- float3 *generated = attr_generated->data_float3();
- size_t i = 0;
+ /* create vertex color attributes */
+ {
+ BL::Mesh::tessface_vertex_colors_iterator l;
+ int vcol_num = 0;
- foreach(Mesh::Curve& curve, mesh->curves) {
- float3 co = mesh->curve_keys[curve.first_key].co;
- generated[i++] = co*size - loc;
+ for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
+ if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
+ continue;
+
+ Attribute *attr_vcol = mesh->curve_attributes.add(
+ ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
+
+ ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, use_parents, vcol_num);
+
+ float3 *vcol = attr_vcol->data_float3();
+
+ if(vcol) {
+ for(size_t curve = 0; curve < CData.curve_vcol.size() ;curve++)
+ vcol[curve] = color_srgb_to_scene_linear(CData.curve_vcol[curve]);
+ }
}
}
- /* create vertex color attributes */
- BL::Mesh::tessface_vertex_colors_iterator l;
- int vcol_num = 0;
+ /* create uv map attributes */
+ {
+ BL::Mesh::tessface_uv_textures_iterator l;
+ int uv_num = 0;
- for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
- if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
- continue;
+ for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l, uv_num++) {
+ bool active_render = l->active_render();
+ AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
+ ustring name = ustring(l->name().c_str());
- /*error occurs with more than one vertex colour attribute so avoided*/
- if(vcol_num!=0)
- break;
+ /* UV map */
+ if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
+ Attribute *attr;
- Attribute *attr_vcol = mesh->curve_attributes.add(
- ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
+ if(active_render)
+ attr = mesh->curve_attributes.add(std, name);
+ else
+ attr = mesh->curve_attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
- ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, use_parents, 0);
+ ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, use_parents, uv_num);
- float3 *vcol = attr_vcol->data_float3();
+ float3 *uv = attr->data_float3();
- if(vcol) {
- for(size_t curve = 0; curve < CData.curve_vcol.size() ;curve++)
- vcol[curve] = color_srgb_to_scene_linear(CData.curve_vcol[curve]);
+ if(uv) {
+ for(size_t curve = 0; curve < CData.curve_uv.size() ;curve++)
+ uv[curve] = CData.curve_uv[curve];
+ }
+ }
}
-
}
}
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index d0c7c06cbb3..3913323c21c 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -109,6 +109,11 @@ void BlenderSession::create_session()
session->reset(buffer_params, session_params.samples);
b_engine.use_highlight_tiles(session_params.progressive_refine == false);
+
+ /* setup callbacks for builtin image support */
+ scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5);
+ scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2);
+ scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2);
}
void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_)
@@ -607,5 +612,124 @@ void BlenderSession::test_cancel()
session->progress.set_cancel("Cancelled");
}
+/* builtin image file name is actually an image datablock name with
+ * absolute sequence frame number concatenated via '@' character
+ *
+ * this function splits image id name and frame number from a
+ * builtin image name
+ */
+void BlenderSession::builtin_name_split(const string &builtin_name, string &name, int &frame)
+{
+ int last = builtin_name.find_last_of('@');
+ name = builtin_name.substr(0, last);
+ frame = atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str());
+}
+
+void BlenderSession::builtin_image_info(const string &builtin_name, bool &is_float, int &width, int &height, int &channels)
+{
+ string name;
+ int frame;
+ builtin_name_split(builtin_name, name, frame);
+
+ BL::Image b_image = b_data.images[name];
+
+ if(b_image) {
+ is_float = b_image.is_float();
+ width = b_image.size()[0];
+ height = b_image.size()[1];
+ channels = b_image.channels();
+ }
+ else {
+ is_float = false;
+ width = 0;
+ height = 0;
+ channels = 0;
+ }
+}
+
+bool BlenderSession::builtin_image_pixels(const string &builtin_name, unsigned char *pixels)
+{
+ string name;
+ int frame;
+ builtin_name_split(builtin_name, name, frame);
+
+ BL::Image b_image = b_data.images[name];
+
+ if(b_image) {
+ int width = b_image.size()[0];
+ int height = b_image.size()[1];
+ int channels = b_image.channels();
+
+ unsigned char *image_pixels;
+ image_pixels = image_get_pixels_for_frame(b_image, frame);
+
+ if(image_pixels) {
+ memcpy(pixels, image_pixels, width * height * channels * sizeof(unsigned char));
+ MEM_freeN(image_pixels);
+ }
+ else {
+ if(channels == 1) {
+ memset(pixels, 0, width * height * sizeof(unsigned char));
+ }
+ else {
+ unsigned char *cp = pixels;
+ for(int i = 0; i < width * height; i++, cp += channels) {
+ cp[0] = 255;
+ cp[1] = 0;
+ cp[2] = 255;
+ if(channels == 4)
+ cp[3] = 255;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, float *pixels)
+{
+ string name;
+ int frame;
+ builtin_name_split(builtin_name, name, frame);
+
+ BL::Image b_image = b_data.images[name];
+
+ if(b_image) {
+ int width = b_image.size()[0];
+ int height = b_image.size()[1];
+ int channels = b_image.channels();
+
+ float *image_pixels;
+ image_pixels = image_get_float_pixels_for_frame(b_image, frame);
+
+ if(image_pixels) {
+ memcpy(pixels, image_pixels, width * height * channels * sizeof(float));
+ MEM_freeN(image_pixels);
+ }
+ else {
+ if(channels == 1) {
+ memset(pixels, 0, width * height * sizeof(float));
+ }
+ else {
+ float *fp = pixels;
+ for(int i = 0; i < width * height; i++, fp += channels) {
+ fp[0] = 1.0f;
+ fp[1] = 0.0f;
+ fp[2] = 1.0f;
+ if(channels == 4)
+ fp[3] = 1.0f;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
index 7f3973ae873..686ff3d1be9 100644
--- a/intern/cycles/blender/blender_session.h
+++ b/intern/cycles/blender/blender_session.h
@@ -93,6 +93,11 @@ public:
protected:
void do_write_update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile, bool do_update_only);
void do_write_update_render_tile(RenderTile& rtile, bool do_update_only);
+
+ void builtin_name_split(const string &builtin_name, string &name, int &frame);
+ void builtin_image_info(const string &builtin_name, bool &is_float, int &width, int &height, int &channels);
+ bool builtin_image_pixels(const string &builtin_name, unsigned char *pixels);
+ bool builtin_image_float_pixels(const string &builtin_name, float *pixels);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index ddbd7f935e4..b1eaedba47a 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -511,9 +511,31 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
BL::ShaderNodeTexImage b_image_node(b_node);
BL::Image b_image(b_image_node.image());
ImageTextureNode *image = new ImageTextureNode();
- /* todo: handle generated/builtin images */
- if(b_image && b_image.source() != BL::Image::source_MOVIE) {
- image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
+ if(b_image) {
+ /* builtin images will use callback-based reading because
+ * they could only be loaded correct from blender side
+ */
+ bool is_builtin = b_image.packed_file() ||
+ b_image.source() == BL::Image::source_GENERATED ||
+ b_image.source() == BL::Image::source_MOVIE;
+
+ if(is_builtin) {
+ /* for builtin images we're using image datablock name to find an image to
+ * read pixels from later
+ *
+ * also store frame number as well, so there's no differences in handling
+ * builtin names for packed images and movies
+ */
+ int scene_frame = b_scene.frame_current();
+ int image_frame = image_user_frame_number(b_image_node.image_user(), scene_frame);
+ image->filename = b_image.name() + "@" + string_printf("%d", image_frame);
+ image->is_builtin = true;
+ }
+ else {
+ image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
+ image->is_builtin = false;
+ }
+
image->animated = b_image_node.image_user().use_auto_refresh();
}
image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
@@ -527,9 +549,21 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
BL::ShaderNodeTexEnvironment b_env_node(b_node);
BL::Image b_image(b_env_node.image());
EnvironmentTextureNode *env = new EnvironmentTextureNode();
- if(b_image && b_image.source() != BL::Image::source_MOVIE) {
- env->filename = image_user_file_path(b_env_node.image_user(), b_image, b_scene.frame_current());
- env->animated = b_env_node.image_user().use_auto_refresh();
+ if(b_image) {
+ bool is_builtin = b_image.packed_file() ||
+ b_image.source() == BL::Image::source_GENERATED ||
+ b_image.source() == BL::Image::source_MOVIE;
+
+ if(is_builtin) {
+ int scene_frame = b_scene.frame_current();
+ int image_frame = image_user_frame_number(b_env_node.image_user(), scene_frame);
+ env->filename = b_image.name() + "@" + string_printf("%d", image_frame);
+ env->is_builtin = true;
+ }
+ else {
+ env->filename = image_user_file_path(b_env_node.image_user(), b_image, b_scene.frame_current());
+ env->animated = b_env_node.image_user().use_auto_refresh();
+ }
}
env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()];
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index a2a8c23404f..7ad663b7e26 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -359,22 +359,22 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine b_engine, BL::Use
params.background = background;
/* samples */
- if(get_boolean(cscene, "progressive")) {
+ if(get_boolean(cscene, "progressive") == 0 && params.device.type == DEVICE_CPU){
if(background) {
- params.samples = get_int(cscene, "samples");
+ params.samples = get_int(cscene, "aa_samples");
}
else {
- params.samples = get_int(cscene, "preview_samples");
+ params.samples = get_int(cscene, "preview_aa_samples");
if(params.samples == 0)
params.samples = INT_MAX;
}
}
else {
if(background) {
- params.samples = get_int(cscene, "aa_samples");
+ params.samples = get_int(cscene, "samples");
}
else {
- params.samples = get_int(cscene, "preview_aa_samples");
+ params.samples = get_int(cscene, "preview_samples");
if(params.samples == 0)
params.samples = INT_MAX;
}
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index 88c98860794..f134416f2d0 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -33,6 +33,8 @@ extern "C" {
void BLI_timestr(double _time, char *str);
void BKE_image_user_frame_calc(void *iuser, int cfra, int fieldnr);
void BKE_image_user_file_path(void *iuser, void *ima, char *path);
+unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame);
+float *BKE_image_get_float_pixels_for_frame(void *image, int frame);
}
CCL_NAMESPACE_BEGIN
@@ -100,6 +102,22 @@ static inline string image_user_file_path(BL::ImageUser iuser, BL::Image ima, in
return string(filepath);
}
+static inline int image_user_frame_number(BL::ImageUser iuser, int cfra)
+{
+ BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0);
+ return iuser.frame_current();
+}
+
+static inline unsigned char *image_get_pixels_for_frame(BL::Image image, int frame)
+{
+ return BKE_image_get_pixels_for_frame(image.ptr.data, frame);
+}
+
+static inline float *image_get_float_pixels_for_frame(BL::Image image, int frame)
+{
+ return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame);
+}
+
/* Utilities */
static inline Transform get_transform(BL::Array<float, 16> array)
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index 412b44031e6..011406344ea 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -18,6 +18,7 @@
#include "mesh.h"
#include "object.h"
#include "scene.h"
+#include "curves.h"
#include "bvh.h"
#include "bvh_build.h"
@@ -631,8 +632,19 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
int k0 = mesh->curves[pidx - str_offset].first_key + pack.prim_segment[prim]; // XXX!
int k1 = k0 + 1;
- bbox.grow(mesh->curve_keys[k0].co, mesh->curve_keys[k0].radius);
- bbox.grow(mesh->curve_keys[k1].co, mesh->curve_keys[k1].radius);
+ float3 p[4];
+ p[0] = mesh->curve_keys[max(k0 - 1,mesh->curves[pidx - str_offset].first_key)].co;
+ p[1] = mesh->curve_keys[k0].co;
+ p[2] = mesh->curve_keys[k1].co;
+ p[3] = mesh->curve_keys[min(k1 + 1,mesh->curves[pidx - str_offset].first_key + mesh->curves[pidx - str_offset].num_keys - 1)].co;
+ float3 lower;
+ float3 upper;
+ curvebounds(&lower.x, &upper.x, p, 0);
+ curvebounds(&lower.y, &upper.y, p, 1);
+ curvebounds(&lower.z, &upper.z, p, 2);
+ float mr = max(mesh->curve_keys[k0].radius,mesh->curve_keys[k1].radius);
+ bbox.grow(lower, mr);
+ bbox.grow(upper, mr);
}
else {
/* triangles */
diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp
index 38fb1a15a13..022c4c8d294 100644
--- a/intern/cycles/bvh/bvh_build.cpp
+++ b/intern/cycles/bvh/bvh_build.cpp
@@ -24,6 +24,7 @@
#include "mesh.h"
#include "object.h"
#include "scene.h"
+#include "curves.h"
#include "util_debug.h"
#include "util_foreach.h"
@@ -91,11 +92,20 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh,
for(int k = 0; k < curve.num_keys - 1; k++) {
BoundBox bounds = BoundBox::empty;
- float3 co0 = mesh->curve_keys[curve.first_key + k].co;
- float3 co1 = mesh->curve_keys[curve.first_key + k + 1].co;
-
- bounds.grow(co0, mesh->curve_keys[curve.first_key + k].radius);
- bounds.grow(co1, mesh->curve_keys[curve.first_key + k + 1].radius);
+ float3 co[4];
+ co[0] = mesh->curve_keys[max(curve.first_key + k - 1,curve.first_key)].co;
+ co[1] = mesh->curve_keys[curve.first_key + k].co;
+ co[2] = mesh->curve_keys[curve.first_key + k + 1].co;
+ co[3] = mesh->curve_keys[min(curve.first_key + k + 2, curve.first_key + curve.num_keys - 1)].co;
+
+ float3 lower;
+ float3 upper;
+ curvebounds(&lower.x, &upper.x, co, 0);
+ curvebounds(&lower.y, &upper.y, co, 1);
+ curvebounds(&lower.z, &upper.z, co, 2);
+ float mr = max(mesh->curve_keys[curve.first_key + k].radius, mesh->curve_keys[curve.first_key + k + 1].radius);
+ bounds.grow(lower, mr);
+ bounds.grow(upper, mr);
if(bounds.valid()) {
references.push_back(BVHReference(bounds, j, i, k));
diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp
index 040f3044457..0c590645808 100644
--- a/intern/cycles/device/device_cuda.cpp
+++ b/intern/cycles/device/device_cuda.cpp
@@ -238,13 +238,16 @@ public:
if(path_exists(cubin))
return cubin;
-#if defined(WITH_CUDA_BINARIES) && defined(_WIN32)
- if(major <= 1 && minor <= 2)
- cuda_error(string_printf("CUDA device supported only compute capability 1.3 or up, found %d.%d.", major, minor));
- else
- cuda_error(string_printf("CUDA binary kernel for this graphics card compute capability (%d.%d) not found.", major, minor));
- return "";
-#else
+#ifdef _WIN32
+ if(cuHavePrecompiledKernels()) {
+ if(major <= 1 && minor <= 2)
+ cuda_error(string_printf("CUDA device requires compute capability 1.3 or up, found %d.%d. Your GPU is not supported.", major, minor));
+ else
+ cuda_error(string_printf("CUDA binary kernel for this graphics card compute capability (%d.%d) not found.", major, minor));
+ return "";
+ }
+#endif
+
/* if not, find CUDA compiler */
string nvcc = cuCompilerPath();
@@ -282,7 +285,6 @@ public:
printf("Kernel compilation finished in %.2lfs.\n", time_dt() - starttime);
return cubin;
-#endif
}
bool load_kernels(bool experimental)
diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp
index 69287f1a8bd..3ab5d9ee69b 100644
--- a/intern/cycles/device/device_opencl.cpp
+++ b/intern/cycles/device/device_opencl.cpp
@@ -303,7 +303,7 @@ public:
string build_options = " -cl-fast-relaxed-math ";
if(platform_name == "NVIDIA CUDA")
- build_options += "-D__KERNEL_SHADING__ -D__KERNEL_OPENCL_NVIDIA__ -cl-nv-maxrregcount=24 -cl-nv-verbose ";
+ build_options += "-D__KERNEL_OPENCL_NVIDIA__ -cl-nv-maxrregcount=24 -cl-nv-verbose ";
else if(platform_name == "Apple")
build_options += "-D__CL_NO_FLOAT3__ -D__KERNEL_OPENCL_APPLE__ ";
diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h
index d99beb8905a..86177301357 100644
--- a/intern/cycles/kernel/kernel_accumulate.h
+++ b/intern/cycles/kernel/kernel_accumulate.h
@@ -133,6 +133,10 @@ __device_inline void path_radiance_init(PathRadiance *L, int use_light_pass)
L->indirect_glossy = make_float3(0.0f, 0.0f, 0.0f);
L->indirect_transmission = make_float3(0.0f, 0.0f, 0.0f);
+ L->path_diffuse = make_float3(0.0f, 0.0f, 0.0f);
+ L->path_glossy = make_float3(0.0f, 0.0f, 0.0f);
+ L->path_transmission = make_float3(0.0f, 0.0f, 0.0f);
+
L->emission = make_float3(0.0f, 0.0f, 0.0f);
L->background = make_float3(0.0f, 0.0f, 0.0f);
L->ao = make_float3(0.0f, 0.0f, 0.0f);
@@ -156,11 +160,11 @@ __device_inline void path_radiance_bsdf_bounce(PathRadiance *L, float3 *throughp
/* first on directly visible surface */
float3 value = *throughput*inverse_pdf;
- L->indirect_diffuse = bsdf_eval->diffuse*value;
- L->indirect_glossy = bsdf_eval->glossy*value;
- L->indirect_transmission = bsdf_eval->transmission*value;
+ L->path_diffuse = bsdf_eval->diffuse*value;
+ L->path_glossy = bsdf_eval->glossy*value;
+ L->path_transmission = bsdf_eval->transmission*value;
- *throughput = L->indirect_diffuse + L->indirect_glossy + L->indirect_transmission;
+ *throughput = L->path_diffuse + L->path_glossy + L->path_transmission;
L->direct_throughput = *throughput;
}
@@ -266,22 +270,45 @@ __device_inline void path_radiance_accum_background(PathRadiance *L, float3 thro
#endif
}
-__device_inline float3 path_radiance_sum(KernelGlobals *kg, PathRadiance *L)
+__device_inline void path_radiance_sum_indirect(PathRadiance *L)
{
#ifdef __PASSES__
+ /* this division is a bit ugly, but means we only have to keep track of
+ * only a single throughput further along the path, here we recover just
+ * the indirect parth that is not influenced by any particular BSDF type */
if(L->use_light_pass) {
- /* this division is a bit ugly, but means we only have to keep track of
- * only a single throughput further along the path, here we recover just
- * the indirect parth that is not influenced by any particular BSDF type */
L->direct_emission = safe_divide_color(L->direct_emission, L->direct_throughput);
- L->direct_diffuse += L->indirect_diffuse*L->direct_emission;
- L->direct_glossy += L->indirect_glossy*L->direct_emission;
- L->direct_transmission += L->indirect_transmission*L->direct_emission;
+ L->direct_diffuse += L->path_diffuse*L->direct_emission;
+ L->direct_glossy += L->path_glossy*L->direct_emission;
+ L->direct_transmission += L->path_transmission*L->direct_emission;
L->indirect = safe_divide_color(L->indirect, L->direct_throughput);
- L->indirect_diffuse *= L->indirect;
- L->indirect_glossy *= L->indirect;
- L->indirect_transmission *= L->indirect;
+ L->indirect_diffuse += L->path_diffuse*L->indirect;
+ L->indirect_glossy += L->path_glossy*L->indirect;
+ L->indirect_transmission += L->path_transmission*L->indirect;
+ }
+#endif
+}
+
+__device_inline void path_radiance_reset_indirect(PathRadiance *L)
+{
+#ifdef __PASSES__
+ if(L->use_light_pass) {
+ L->path_diffuse = make_float3(0.0f, 0.0f, 0.0f);
+ L->path_glossy = make_float3(0.0f, 0.0f, 0.0f);
+ L->path_transmission = make_float3(0.0f, 0.0f, 0.0f);
+
+ L->direct_emission = make_float3(0.0f, 0.0f, 0.0f);
+ L->indirect = make_float3(0.0f, 0.0f, 0.0f);
+ }
+#endif
+}
+
+__device_inline float3 path_radiance_sum(KernelGlobals *kg, PathRadiance *L)
+{
+#ifdef __PASSES__
+ if(L->use_light_pass) {
+ path_radiance_sum_indirect(L);
float3 L_sum = L->emission
+ L->direct_diffuse + L->direct_glossy + L->direct_transmission
diff --git a/intern/cycles/kernel/kernel_bvh.h b/intern/cycles/kernel/kernel_bvh.h
index 2cb29207b05..1a85b5bbefd 100644
--- a/intern/cycles/kernel/kernel_bvh.h
+++ b/intern/cycles/kernel/kernel_bvh.h
@@ -206,6 +206,317 @@ __device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *ise
}
#ifdef __HAIR__
+__device_inline void curvebounds(float *lower, float *upper, float *extremta, float *extrema, float *extremtb, float *extremb, float p0, float p1, float p2, float p3)
+{
+ float halfdiscroot = (p2 * p2 - 3 * p3 * p1);
+ float ta = -1.0f;
+ float tb = -1.0f;
+ *extremta = -1.0f;
+ *extremtb = -1.0f;
+ *upper = p0;
+ *lower = p0 + p1 + p2 + p3;
+ *extrema = *upper;
+ *extremb = *lower;
+ if(*lower >= *upper) {
+ *upper = *lower;
+ *lower = p0;
+ }
+
+ if(halfdiscroot >= 0) {
+ halfdiscroot = sqrt(halfdiscroot);
+ ta = (-p2 - halfdiscroot) / (3 * p3);
+ tb = (-p2 + halfdiscroot) / (3 * p3);
+ }
+
+ float t2;
+ float t3;
+ if(ta > 0.0f && ta < 1.0f) {
+ t2 = ta * ta;
+ t3 = t2 * ta;
+ *extremta = ta;
+ *extrema = p3 * t3 + p2 * t2 + p1 * ta + p0;
+ if(*extrema > *upper) {
+ *upper = *extrema;
+ }
+ if(*extrema < *lower) {
+ *lower = *extrema;
+ }
+ }
+ if(tb > 0.0f && tb < 1.0f) {
+ t2 = tb * tb;
+ t3 = t2 * tb;
+ *extremtb = tb;
+ *extremb = p3 * t3 + p2 * t2 + p1 * tb + p0;
+ if(*extremb >= *upper) {
+ *upper = *extremb;
+ }
+ if(*extremb <= *lower) {
+ *lower = *extremb;
+ }
+ }
+}
+
+__device_inline void bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersection *isect,
+ float3 P, float3 idir, uint visibility, int object, int curveAddr, int segment)
+{
+ int depth = kernel_data.curve_kernel_data.subdivisions;
+
+ /* curve Intersection check */
+ float3 dir = 1.0f/idir;
+
+ int flags = kernel_data.curve_kernel_data.curveflags;
+
+ int prim = kernel_tex_fetch(__prim_index, curveAddr);
+
+ float3 curve_coef[4];
+ float r_st,r_en;
+
+ /*obtain curve parameters*/
+ {
+ /*ray transform created - this shold be created at beginning of intersection loop*/
+ Transform htfm;
+ float d = sqrtf(dir.x * dir.x + dir.z * dir.z);
+ htfm = make_transform(
+ dir.z / d, 0, -dir.x /d, 0,
+ -dir.x * dir.y /d, d, -dir.y * dir.z /d, 0,
+ dir.x, dir.y, dir.z, 0,
+ 0, 0, 0, 1) * make_transform(
+ 1, 0, 0, -P.x,
+ 0, 1, 0, -P.y,
+ 0, 0, 1, -P.z,
+ 0, 0, 0, 1);
+
+ float4 v00 = kernel_tex_fetch(__curves, prim);
+
+ int k0 = __float_as_int(v00.x) + segment;
+ int k1 = k0 + 1;
+
+ int ka = max(k0 - 1,__float_as_int(v00.x));
+ int kb = min(k1 + 1,__float_as_int(v00.x) + __float_as_int(v00.y) - 1);
+
+ float4 P0 = kernel_tex_fetch(__curve_keys, ka);
+ float4 P1 = kernel_tex_fetch(__curve_keys, k0);
+ float4 P2 = kernel_tex_fetch(__curve_keys, k1);
+ float4 P3 = kernel_tex_fetch(__curve_keys, kb);
+
+ float3 p0 = transform_point(&htfm, float4_to_float3(P0));
+ float3 p1 = transform_point(&htfm, float4_to_float3(P1));
+ float3 p2 = transform_point(&htfm, float4_to_float3(P2));
+ float3 p3 = transform_point(&htfm, float4_to_float3(P3));
+
+ float fc = 0.71f;
+ curve_coef[0] = p1;
+ curve_coef[1] = -fc*p0 + fc*p2;
+ curve_coef[2] = 2.0f * fc * p0 + (fc - 3.0f) * p1 + (3.0f - 2.0f * fc) * p2 - fc * p3;
+ curve_coef[3] = -fc * p0 + (2.0f - fc) * p1 + (fc - 2.0f) * p2 + fc * p3;
+ r_st = P1.w;
+ r_en = P2.w;
+ }
+
+
+ float r_curr = max(r_st, r_en);
+
+ /*find bounds - this is slow for cubic curves*/
+ float upper,lower;
+ float xextrem[4];
+ curvebounds(&lower, &upper, &xextrem[0], &xextrem[1], &xextrem[2], &xextrem[3], curve_coef[0].x, curve_coef[1].x, curve_coef[2].x, curve_coef[3].x);
+ if(lower > r_curr || upper < -r_curr)
+ return;
+
+ float yextrem[4];
+ curvebounds(&lower, &upper, &yextrem[0], &yextrem[1], &yextrem[2], &yextrem[3], curve_coef[0].y, curve_coef[1].y, curve_coef[2].y, curve_coef[3].y);
+ if(lower > r_curr || upper < -r_curr)
+ return;
+
+ float zextrem[4];
+ curvebounds(&lower, &upper, &zextrem[0], &zextrem[1], &zextrem[2], &zextrem[3], curve_coef[0].z, curve_coef[1].z, curve_coef[2].z, curve_coef[3].z);
+ if(lower - r_curr > isect->t || upper + r_curr < 0.0f)
+ return;
+
+ /*setup recurrent loop*/
+ int level = 1 << depth;
+ int tree = 0;
+ float resol = 1.0f / (float)level;
+
+ /*begin loop*/
+ while(!(tree >> (depth))) {
+ float i_st = tree * resol;
+ float i_en = i_st + (level * resol);
+ float3 p_st = ((curve_coef[3] * i_st + curve_coef[2]) * i_st + curve_coef[1]) * i_st + curve_coef[0];
+ float3 p_en = ((curve_coef[3] * i_en + curve_coef[2]) * i_en + curve_coef[1]) * i_en + curve_coef[0];
+
+ float bminx = min(p_st.x, p_en.x);
+ float bmaxx = max(p_st.x, p_en.x);
+ float bminy = min(p_st.y, p_en.y);
+ float bmaxy = max(p_st.y, p_en.y);
+ float bminz = min(p_st.z, p_en.z);
+ float bmaxz = max(p_st.z, p_en.z);
+
+ if(xextrem[0] >= i_st && xextrem[0] <= i_en) {
+ bminx = min(bminx,xextrem[1]);
+ bmaxx = max(bmaxx,xextrem[1]);
+ }
+ if(xextrem[2] >= i_st && xextrem[2] <= i_en) {
+ bminx = min(bminx,xextrem[3]);
+ bmaxx = max(bmaxx,xextrem[3]);
+ }
+ if(yextrem[0] >= i_st && yextrem[0] <= i_en) {
+ bminy = min(bminy,yextrem[1]);
+ bmaxy = max(bmaxy,yextrem[1]);
+ }
+ if(yextrem[2] >= i_st && yextrem[2] <= i_en) {
+ bminy = min(bminy,yextrem[3]);
+ bmaxy = max(bmaxy,yextrem[3]);
+ }
+ if(zextrem[0] >= i_st && zextrem[0] <= i_en) {
+ bminz = min(bminz,zextrem[1]);
+ bmaxz = max(bmaxz,zextrem[1]);
+ }
+ if(zextrem[2] >= i_st && zextrem[2] <= i_en) {
+ bminz = min(bminz,zextrem[3]);
+ bmaxz = max(bmaxz,zextrem[3]);
+ }
+
+ float r1 = r_st + (r_en - r_st) * i_st;
+ float r2 = r_st + (r_en - r_st) * i_en;
+ r_curr = max(r1, r2);
+
+ if (bminz - r_curr > isect->t || bmaxz + r_curr < 0.0f|| bminx > r_curr || bmaxx < -r_curr || bminy > r_curr || bmaxy < -r_curr) {
+ /* the bounding box does not overlap the square centered at O.*/
+ tree += level;
+ level = tree & -tree;
+ }
+ else if (level == 1) {
+
+ /* the maximum recursion depth is reached.
+ * check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0.
+ * dP* is reversed if necessary.*/
+ float t = isect->t;
+ float u = 0.0f;
+ if(flags & CURVE_KN_RIBBONS) {
+ float3 tg = (p_en - p_st);
+ float w = tg.x * tg.x + tg.y * tg.y;
+ if (w == 0) {
+ tree++;
+ level = tree & -tree;
+ continue;
+ }
+ w = -(p_st.x * tg.x + p_st.y * tg.y) / w;
+ w = clamp((float)w, 0.0f, 1.0f);
+
+ /* compute u on the curve segment.*/
+ u = i_st * (1 - w) + i_en * w;
+ r_curr = r_st + (r_en - r_st) * u;
+ /* compare x-y distances.*/
+ float3 p_curr = ((curve_coef[3] * u + curve_coef[2]) * u + curve_coef[1]) * u + curve_coef[0];
+
+ float3 dp_st = (3 * curve_coef[3] * i_st + 2 * curve_coef[2]) * i_st + curve_coef[1];
+ if (dot(tg, dp_st)< 0)
+ dp_st *= -1;
+ if (dot(dp_st, -p_st) + p_curr.z * dp_st.z < 0) {
+ tree++;
+ level = tree & -tree;
+ continue;
+ }
+ float3 dp_en = (3 * curve_coef[3] * i_en + 2 * curve_coef[2]) * i_en + curve_coef[1];
+ if (dot(tg, dp_en) < 0)
+ dp_en *= -1;
+ if (dot(dp_en, p_en) - p_curr.z * dp_en.z < 0) {
+ tree++;
+ level = tree & -tree;
+ continue;
+ }
+
+ if (p_curr.x * p_curr.x + p_curr.y * p_curr.y >= r_curr * r_curr || p_curr.z <= 0.0f) {
+ tree++;
+ level = tree & -tree;
+ continue;
+ }
+ /* compare z distances.*/
+ if (isect->t < p_curr.z) {
+ tree++;
+ level = tree & -tree;
+ continue;
+ }
+ t = p_curr.z;
+ }
+ else {
+ float l = len(p_en - p_st);
+ float3 tg = (p_en - p_st) / l;
+ float gd = (r2 - r1) / l;
+ float difz = -dot(p_st,tg);
+ float cyla = 1.0f - (tg.z * tg.z * (1 + gd*gd));
+ float halfb = (-p_st.z - tg.z*(difz + gd*(difz*gd + r1)));
+ float tcentre = -halfb/cyla;
+ float zcentre = difz + (tg.z * tcentre);
+ float3 tdif = - p_st;
+ tdif.z += tcentre;
+ float tdifz = dot(tdif,tg);
+ float tb = 2*(tdif.z - tg.z*(tdifz + gd*(tdifz*gd + r1)));
+ float tc = dot(tdif,tdif) - tdifz * tdifz * (1 + gd*gd) - r1*r1 - 2*r1*tdifz*gd;
+ float td = tb*tb - 4*cyla*tc;
+ if (td < 0.0f){
+ tree++;
+ level = tree & -tree;
+ continue;
+ }
+
+ float rootd = sqrtf(td);
+ float correction = ((-tb - rootd)/(2*cyla));
+ t = tcentre + correction;
+ float w = (zcentre + (tg.z * correction))/l;
+
+ float3 dp_st = (3 * curve_coef[3] * i_st + 2 * curve_coef[2]) * i_st + curve_coef[1];
+ if (dot(tg, dp_st)< 0)
+ dp_st *= -1;
+ float3 dp_en = (3 * curve_coef[3] * i_en + 2 * curve_coef[2]) * i_en + curve_coef[1];
+ if (dot(tg, dp_en) < 0)
+ dp_en *= -1;
+
+
+ if(flags & CURVE_KN_BACKFACING && (dot(dp_st, -p_st) + t * dp_st.z < 0 || dot(dp_en, p_en) - t * dp_en.z < 0 || isect->t < t || t <= 0.0f)) {
+ correction = ((-tb + rootd)/(2*cyla));
+ t = tcentre + correction;
+ w = (zcentre + (tg.z * correction))/l;
+ }
+
+ if (dot(dp_st, -p_st) + t * dp_st.z < 0 || dot(dp_en, p_en) - t * dp_en.z < 0 || isect->t < t || t <= 0.0f) {
+ tree++;
+ level = tree & -tree;
+ continue;
+ }
+
+ w = clamp((float)w, 0.0f, 1.0f);
+ /* compute u on the curve segment.*/
+ u = i_st * (1 - w) + i_en * w;
+
+ }
+ /* we found a new intersection.*/
+#ifdef __VISIBILITY_FLAG__
+ /* visibility flag test. we do it here under the assumption
+ * that most triangles are culled by node flags */
+ if(kernel_tex_fetch(__prim_visibility, curveAddr) & visibility)
+#endif
+ {
+ /* record intersection */
+ isect->prim = curveAddr;
+ isect->segment = segment;
+ isect->object = object;
+ isect->u = u;
+ isect->v = 0.0f;
+ isect->t = t;
+ }
+
+ tree++;
+ level = tree & -tree;
+ }
+ else {
+ /* split the curve into two curves and process */
+ level = level >> 1;
+ }
+ }
+}
+
__device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
float3 P, float3 idir, uint visibility, int object, int curveAddr, int segment)
{
@@ -222,7 +533,6 @@ __device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
float4 P1 = kernel_tex_fetch(__curve_keys, k0);
float4 P2 = kernel_tex_fetch(__curve_keys, k1);
- float l = len(P2 - P1);
float r1 = P1.w;
float r2 = P2.w;
float mr = max(r1,r2);
@@ -230,6 +540,7 @@ __device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
float3 p2 = float4_to_float3(P2);
float3 dif = P - p1;
float3 dir = 1.0f/idir;
+ float l = len(p2 - p1);
float sp_r = mr + 0.5f * l;
float3 sphere_dif = P - ((p1 + p2) * 0.5f);
@@ -344,7 +655,7 @@ __device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
}
#endif
-__device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
+__device bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
{
/* traversal stack in CUDA thread-local memory */
int traversalStack[BVH_STACK_SIZE];
@@ -425,8 +736,12 @@ __device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint
/* intersect ray against primitive */
#ifdef __HAIR__
uint segment = kernel_tex_fetch(__prim_segment, primAddr);
- if(segment != ~0)
- bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
+ if(segment != ~0) {
+ if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_INTERPOLATE)
+ bvh_cardinal_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
+ else
+ bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
+ }
else
#endif
bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
@@ -470,7 +785,7 @@ __device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint
}
#ifdef __OBJECT_MOTION__
-__device_inline bool bvh_intersect_motion(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
+__device bool bvh_intersect_motion(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
{
/* traversal stack in CUDA thread-local memory */
int traversalStack[BVH_STACK_SIZE];
@@ -551,8 +866,12 @@ __device_inline bool bvh_intersect_motion(KernelGlobals *kg, const Ray *ray, con
/* intersect ray against primitive */
#ifdef __HAIR__
uint segment = kernel_tex_fetch(__prim_segment, primAddr);
- if(segment != ~0)
- bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
+ if(segment != ~0) {
+ if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_INTERPOLATE)
+ bvh_cardinal_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
+ else
+ bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
+ }
else
#endif
bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
@@ -610,7 +929,7 @@ __device_inline float3 ray_offset(float3 P, float3 Ng)
const float epsilon_f = 1e-5f;
/* ideally this should match epsilon_f, but instancing/mblur
* precision makes it problematic */
- const float epsilon_test = 1e-1f;
+ const float epsilon_test = 1.0f;
const int epsilon_i = 32;
float3 res;
@@ -697,6 +1016,32 @@ __device_inline float3 bvh_triangle_refine(KernelGlobals *kg, ShaderData *sd, co
}
#ifdef __HAIR__
+
+__device_inline float3 curvetangent(float t, float3 p0, float3 p1, float3 p2, float3 p3)
+{
+ float fc = 0.71f;
+ float data[4];
+ float t2 = t * t;
+ data[0] = -3.0f * fc * t2 + 4.0f * fc * t - fc;
+ data[1] = 3.0f * (2.0f - fc) * t2 + 2.0f * (fc - 3.0f) * t;
+ data[2] = 3.0f * (fc - 2.0f) * t2 + 2.0f * (3.0f - 2.0f * fc) * t + fc;
+ data[3] = 3.0f * fc * t2 - 2.0f * fc * t;
+ return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3;
+}
+
+__device_inline float3 curvepoint(float t, float3 p0, float3 p1, float3 p2, float3 p3)
+{
+ float data[4];
+ float fc = 0.71f;
+ float t2 = t * t;
+ float t3 = t2 * t;
+ data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t;
+ data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f;
+ data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t;
+ data[3] = fc * t3 - fc * t2;
+ return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3;
+}
+
__device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, float t)
{
int flag = kernel_data.curve_kernel_data.curveflags;
@@ -723,64 +1068,92 @@ __device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, const
float4 P1 = kernel_tex_fetch(__curve_keys, k0);
float4 P2 = kernel_tex_fetch(__curve_keys, k1);
- float l = len(P2 - P1);
+ float l = 1.0f;
+ float3 tg = normalize_len(float4_to_float3(P2 - P1),&l);
float r1 = P1.w;
float r2 = P2.w;
- float3 tg = float4_to_float3(P2 - P1) / l;
- float3 dif = P - float4_to_float3(P1) + t * D;
float gd = ((r2 - r1)/l);
-
+
P = P + D*t;
- dif = P - float4_to_float3(P1);
+ if(flag & CURVE_KN_INTERPOLATE) {
+ int ka = max(k0 - 1,__float_as_int(v00.x));
+ int kb = min(k1 + 1,__float_as_int(v00.x) + __float_as_int(v00.y) - 1);
- #ifdef __UV__
- sd->u = dot(dif,tg)/l;
- sd->v = 0.0f;
- #endif
+ float4 P0 = kernel_tex_fetch(__curve_keys, ka);
+ float4 P3 = kernel_tex_fetch(__curve_keys, kb);
- if (flag & CURVE_KN_TRUETANGENTGNORMAL) {
- sd->Ng = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix));
- sd->Ng = normalize(sd->Ng);
- if (flag & CURVE_KN_NORMALCORRECTION)
- {
- //sd->Ng = normalize(sd->Ng);
+ float3 p[4];
+ p[0] = float4_to_float3(P0);
+ p[1] = float4_to_float3(P1);
+ p[2] = float4_to_float3(P2);
+ p[3] = float4_to_float3(P3);
+
+ tg = normalize(curvetangent(isect->u,p[0],p[1],p[2],p[3]));
+ float3 p_curr = curvepoint(isect->u,p[0],p[1],p[2],p[3]);
+
+#ifdef __UV__
+ sd->u = isect->u;
+ sd->v = 0.0f;
+#endif
+
+ if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_RIBBONS)
+ sd->Ng = normalize(-(D - tg * (dot(tg,D))));
+ else {
+ sd->Ng = normalize(P - p_curr);
sd->Ng = sd->Ng - gd * tg;
sd->Ng = normalize(sd->Ng);
}
+ sd->N = sd->Ng;
}
else {
- sd->Ng = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd);
- if (gd != 0.0f) {
- sd->Ng = sd->Ng - gd * tg ;
+ float3 dif = P - float4_to_float3(P1);
+
+#ifdef __UV__
+ sd->u = dot(dif,tg)/l;
+ sd->v = 0.0f;
+#endif
+
+ if (flag & CURVE_KN_TRUETANGENTGNORMAL) {
+ sd->Ng = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix));
sd->Ng = normalize(sd->Ng);
+ if (flag & CURVE_KN_NORMALCORRECTION) {
+ sd->Ng = sd->Ng - gd * tg;
+ sd->Ng = normalize(sd->Ng);
+ }
+ }
+ else {
+ sd->Ng = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd);
+ if (gd != 0.0f) {
+ sd->Ng = sd->Ng - gd * tg ;
+ sd->Ng = normalize(sd->Ng);
+ }
}
- }
- sd->N = sd->Ng;
+ sd->N = sd->Ng;
- if (flag & CURVE_KN_TANGENTGNORMAL && !(flag & CURVE_KN_TRUETANGENTGNORMAL)) {
- sd->N = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix));
- sd->N = normalize(sd->N);
- if (flag & CURVE_KN_NORMALCORRECTION) {
- //sd->N = normalize(sd->N);
- sd->N = sd->N - gd * tg;
+ if (flag & CURVE_KN_TANGENTGNORMAL && !(flag & CURVE_KN_TRUETANGENTGNORMAL)) {
+ sd->N = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix));
sd->N = normalize(sd->N);
+ if (flag & CURVE_KN_NORMALCORRECTION) {
+ sd->N = sd->N - gd * tg;
+ sd->N = normalize(sd->N);
+ }
}
- }
- if (!(flag & CURVE_KN_TANGENTGNORMAL) && flag & CURVE_KN_TRUETANGENTGNORMAL) {
- sd->N = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd);
- if (gd != 0.0f) {
- sd->N = sd->N - gd * tg ;
- sd->N = normalize(sd->N);
+ if (!(flag & CURVE_KN_TANGENTGNORMAL) && flag & CURVE_KN_TRUETANGENTGNORMAL) {
+ sd->N = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd);
+ if (gd != 0.0f) {
+ sd->N = sd->N - gd * tg ;
+ sd->N = normalize(sd->N);
+ }
}
}
- #ifdef __DPDU__
+#ifdef __DPDU__
/* dPdu/dPdv */
sd->dPdu = tg;
sd->dPdv = cross(tg,sd->Ng);
- #endif
+#endif
if(isect->object != ~0) {
#ifdef __OBJECT_MOTION__
diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h
index cd896ffe133..f9d5bd3dd3f 100644
--- a/intern/cycles/kernel/kernel_camera.h
+++ b/intern/cycles/kernel/kernel_camera.h
@@ -213,7 +213,7 @@ __device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, flo
#ifdef __CAMERA_MOTION__
/* motion blur */
- if(kernel_data.cam.shuttertime == 0.0f)
+ if(kernel_data.cam.shuttertime == -1.0f)
ray->time = TIME_INVALID;
else
ray->time = 0.5f + 0.5f*(time - 0.5f)*kernel_data.cam.shuttertime;
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index e0d0802ae84..6ba3e439329 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -233,8 +233,10 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
if(radius > 0.0f)
D = distant_light_sample(D, radius, randu, randv);
+#ifdef __LAMP_MIS__
else
ls->use_mis = false;
+#endif
ls->P = D;
ls->Ng = D;
@@ -255,6 +257,9 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
ls->D = -D;
ls->t = FLT_MAX;
ls->eval_fac = 1.0f;
+#ifndef __LAMP_MIS__
+ ls->use_mis = true;
+#endif
}
#endif
else {
@@ -266,8 +271,10 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
if(radius > 0.0f)
/* sphere light */
ls->P += sphere_light_sample(P, ls->P, radius, randu, randv);
+#ifdef __LAMP_MIS__
else
ls->use_mis = false;
+#endif
ls->D = normalize_len(ls->P - P, &ls->t);
ls->Ng = -ls->D;
@@ -298,7 +305,9 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
float invarea = data2.x;
if(invarea == 0.0f) {
+#ifdef __LAMP_MIS__
ls->use_mis = false;
+#endif
invarea = 1.0f;
}
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 532c32896d9..1a5df66e6c2 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -949,6 +949,11 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
kernel_path_indirect(kg, rng, sample*num_samples + j, bsdf_ray, buffer,
tp*num_samples_inv, num_samples,
min_ray_pdf, bsdf_pdf, ps, rng_offset+PRNG_BOUNCE_NUM, &L);
+
+ /* for render passes, sum and reset indirect light pass variables
+ * for the next samples */
+ path_radiance_sum_indirect(&L);
+ path_radiance_reset_indirect(&L);
}
}
diff --git a/intern/cycles/kernel/kernel_primitive.h b/intern/cycles/kernel/kernel_primitive.h
index 0851af21e87..323394cd9dc 100644
--- a/intern/cycles/kernel/kernel_primitive.h
+++ b/intern/cycles/kernel/kernel_primitive.h
@@ -106,7 +106,7 @@ __device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
float3 data = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
object_normal_transform(kg, sd, &data);
- return cross(sd->N, normalize(cross(data, sd->N)));;
+ return cross(sd->N, normalize(cross(data, sd->N)));
}
else {
/* otherwise use surface derivatives */
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 0a5a2ab54b0..b7d87427bd3 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -53,7 +53,7 @@ __device_noinline void shader_setup_object_transforms(KernelGlobals *kg, ShaderD
}
#endif
-__device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
+__device void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
const Intersection *isect, const Ray *ray)
{
#ifdef __INSTANCING__
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 102be440978..1236f43e018 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -43,12 +43,12 @@ CCL_NAMESPACE_BEGIN
#ifdef __KERNEL_CPU__
#define __KERNEL_SHADING__
#define __KERNEL_ADV_SHADING__
+#define __NON_PROGRESSIVE__
+#define __LAMP_MIS__
+#define __HAIR__
#ifdef WITH_OSL
#define __OSL__
#endif
-#define __NON_PROGRESSIVE__
-#define __HAIR__
-#define __LAMP_MIS__
#endif
#ifdef __KERNEL_CUDA__
@@ -56,6 +56,9 @@ CCL_NAMESPACE_BEGIN
#if __CUDA_ARCH__ >= 200
#define __KERNEL_ADV_SHADING__
#endif
+#if __CUDA_ARCH__ >= 210
+#define __LAMP_MIS__
+#endif
#endif
#ifdef __KERNEL_OPENCL__
@@ -114,8 +117,8 @@ CCL_NAMESPACE_BEGIN
#define __PASSES__
#define __BACKGROUND_MIS__
#define __AO__
-#define __CAMERA_MOTION__
#define __ANISOTROPIC__
+#define __CAMERA_MOTION__
#define __OBJECT_MOTION__
#endif
//#define __SOBOL_FULL_SCREEN__
@@ -255,6 +258,10 @@ typedef struct PathRadiance {
float3 indirect_glossy;
float3 indirect_transmission;
+ float3 path_diffuse;
+ float3 path_glossy;
+ float3 path_transmission;
+
float4 shadow;
} PathRadiance;
@@ -696,6 +703,7 @@ typedef enum CurveFlag {
CURVE_KN_NORMALCORRECTION = 128, /* correct tangent normal for slope? */
CURVE_KN_TRUETANGENTGNORMAL = 256, /* use tangent normal for geometry? */
CURVE_KN_TANGENTGNORMAL = 512, /* use tangent normal for shader? */
+ CURVE_KN_RIBBONS = 1024, /* use flat curve ribbons */
} CurveFlag;
typedef struct KernelCurves {
@@ -703,7 +711,7 @@ typedef struct KernelCurves {
float normalmix;
float encasing_ratio;
int curveflags;
- int pad;
+ int subdivisions;
} KernelCurves;
diff --git a/intern/cycles/kernel/shaders/node_normal_map.osl b/intern/cycles/kernel/shaders/node_normal_map.osl
index dc25eb8539f..21382fab06f 100644
--- a/intern/cycles/kernel/shaders/node_normal_map.osl
+++ b/intern/cycles/kernel/shaders/node_normal_map.osl
@@ -31,15 +31,23 @@ shader node_normal_map(
if (space == "Tangent") {
vector tangent;
+ vector ninterp;
float tangent_sign;
- getattribute(attr_name, tangent);
- getattribute(attr_sign_name, tangent_sign);
+ // get _unnormalized_ interpolated normal and tangent
+ if(!getattribute(attr_name, tangent) ||
+ !getattribute(attr_sign_name, tangent_sign) ||
+ !getattribute("geom:N", ninterp)) {
+ Normal = normal(0, 0, 0);
+ }
+ else {
+ // apply normal map
+ vector B = tangent_sign * cross(ninterp, tangent);
+ Normal = normalize(mcolor[0] * tangent + mcolor[1] * B + mcolor[2] * ninterp);
- tangent = transform("object", "world", tangent);
-
- vector B = tangent_sign * cross(NormalIn, tangent);
- Normal = normalize(mcolor[0] * tangent + mcolor[1] * B + mcolor[2] * NormalIn);
+ // transform to world space
+ Normal = normalize(transform("object", "world", Normal));
+ }
}
else if (space == "Object")
Normal = normalize(transform("object", "world", vector(mcolor)));
diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h
index 7a1af43b625..d793169261d 100644
--- a/intern/cycles/kernel/svm/svm_tex_coord.h
+++ b/intern/cycles/kernel/svm/svm_tex_coord.h
@@ -248,24 +248,27 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac
}
/* first try to get tangent attribute */
- AttributeElement attr_elem, attr_sign_elem;
+ AttributeElement attr_elem, attr_sign_elem, attr_normal_elem;
int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
int attr_sign_offset = find_attribute(kg, sd, node.w, &attr_sign_elem);
+ int attr_normal_offset = find_attribute(kg, sd, ATTR_STD_VERTEX_NORMAL, &attr_normal_elem);
- if(attr_offset == ATTR_STD_NOT_FOUND || attr_sign_offset == ATTR_STD_NOT_FOUND) {
+ if(attr_offset == ATTR_STD_NOT_FOUND || attr_sign_offset == ATTR_STD_NOT_FOUND || attr_normal_offset == ATTR_STD_NOT_FOUND) {
stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f));
return;
}
- /* ensure orthogonal and normalized (interpolation breaks it) */
+ /* get _unnormalized_ interpolated normal and tangent */
float3 tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
float sign = primitive_attribute_float(kg, sd, attr_sign_elem, attr_sign_offset, NULL, NULL);
+ float3 normal = primitive_attribute_float3(kg, sd, attr_normal_elem, attr_normal_offset, NULL, NULL);
- object_normal_transform(kg, sd, &tangent);
- tangent = cross(sd->N, normalize(cross(tangent, sd->N)));;
+ /* apply normal map */
+ float3 B = sign * cross(normal, tangent);
+ N = normalize(color.x * tangent + color.y * B + color.z * normal);
- float3 B = sign * cross(sd->N, tangent);
- N = normalize(color.x * tangent + color.y * B + color.z * sd->N);
+ /* transform to world space */
+ object_normal_transform(kg, sd, &N);
}
else {
/* object, world space */
diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp
index a78ede979b2..3ca19496b72 100644
--- a/intern/cycles/render/camera.cpp
+++ b/intern/cycles/render/camera.cpp
@@ -216,9 +216,9 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
/* motion blur */
#ifdef __CAMERA_MOTION__
- kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime: 0.0f;
+ kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime: -1.0f;
#else
- kcam->shuttertime = 0.0f;
+ kcam->shuttertime = -1.0f;
#endif
/* type */
diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h
index 9696161180d..197a4da588c 100644
--- a/intern/cycles/render/camera.h
+++ b/intern/cycles/render/camera.h
@@ -90,7 +90,7 @@ public:
Transform worldtocamera;
Transform rastertocamera;
- Transform cameratoraster;;
+ Transform cameratoraster;
float3 dx;
float3 dy;
diff --git a/intern/cycles/render/curves.cpp b/intern/cycles/render/curves.cpp
index 3299503b4ab..9fa867ae723 100644
--- a/intern/cycles/render/curves.cpp
+++ b/intern/cycles/render/curves.cpp
@@ -29,6 +29,52 @@
CCL_NAMESPACE_BEGIN
+/* Curve functions */
+
+void curvebounds(float *lower, float *upper, float3 *p, int dim)
+{
+ float *p0 = &p[0].x;
+ float *p1 = &p[1].x;
+ float *p2 = &p[2].x;
+ float *p3 = &p[3].x;
+ float fc = 0.71f;
+ float curve_coef[4];
+ curve_coef[0] = p1[dim];
+ curve_coef[1] = -fc*p0[dim] + fc*p2[dim];
+ curve_coef[2] = 2.0f * fc * p0[dim] + (fc - 3.0f) * p1[dim] + (3.0f - 2.0f * fc) * p2[dim] - fc * p3[dim];
+ curve_coef[3] = -fc * p0[dim] + (2.0f - fc) * p1[dim] + (fc - 2.0f) * p2[dim] + fc * p3[dim];
+ float discroot = curve_coef[2] * curve_coef[2] - 3 * curve_coef[3] * curve_coef[1];
+ float ta = -1.0f;
+ float tb = -1.0f;
+ if(discroot >= 0) {
+ discroot = sqrt(discroot);
+ ta = (-curve_coef[2] - discroot) / (3 * curve_coef[3]);
+ tb = (-curve_coef[2] + discroot) / (3 * curve_coef[3]);
+ ta = (ta > 1.0f || ta < 0.0f) ? -1.0f : ta;
+ tb = (tb > 1.0f || tb < 0.0f) ? -1.0f : tb;
+ }
+
+ *upper = max(p1[dim],p2[dim]);
+ *lower = min(p1[dim],p2[dim]);
+ float exa = p1[dim];
+ float exb = p2[dim];
+ float t2;
+ float t3;
+ if(ta >= 0.0f) {
+ t2 = ta * ta;
+ t3 = t2 * ta;
+ exa = curve_coef[3] * t3 + curve_coef[2] * t2 + curve_coef[1] * ta + curve_coef[0];
+ }
+ if(tb >= 0.0f) {
+ t2 = tb * tb;
+ t3 = t2 * tb;
+ exb = curve_coef[3] * t3 + curve_coef[2] * t2 + curve_coef[1] * tb + curve_coef[0];
+ }
+ *upper = max(*upper, max(exa,exb));
+ *lower = min(*lower, min(exa,exb));
+
+}
+
/* Hair System Manager */
CurveSystemManager::CurveSystemManager()
@@ -36,16 +82,16 @@ CurveSystemManager::CurveSystemManager()
primitive = CURVE_LINE_SEGMENTS;
line_method = CURVE_CORRECTED;
interpolation = CURVE_CARDINAL;
- triangle_method = CURVE_CAMERA;
+ triangle_method = CURVE_CAMERA_TRIANGLES;
resolution = 3;
segments = 1;
+ subdivisions = 3;
normalmix = 1.0f;
encasing_ratio = 1.01f;
use_curves = true;
use_smooth = true;
- use_cache = true;
use_parents = false;
use_encasing = true;
use_backfacing = false;
@@ -75,31 +121,36 @@ void CurveSystemManager::device_update(Device *device, DeviceScene *dscene, Scen
kcurve->curveflags = 0;
- if(primitive == CURVE_SEGMENTS)
- kcurve->curveflags |= CURVE_KN_INTERPOLATE;
-
- if(line_method == CURVE_ACCURATE)
- kcurve->curveflags |= CURVE_KN_ACCURATE;
- if(line_method == CURVE_CORRECTED)
- kcurve->curveflags |= CURVE_KN_INTERSECTCORRECTION;
- if(line_method == CURVE_POSTCORRECTED)
- kcurve->curveflags |= CURVE_KN_POSTINTERSECTCORRECTION;
-
- if(use_tangent_normal)
- kcurve->curveflags |= CURVE_KN_TANGENTGNORMAL;
- if(use_tangent_normal_correction)
- kcurve->curveflags |= CURVE_KN_NORMALCORRECTION;
- if(use_tangent_normal_geometry)
- kcurve->curveflags |= CURVE_KN_TRUETANGENTGNORMAL;
- if(use_joined)
- kcurve->curveflags |= CURVE_KN_CURVEDATA;
- if(use_backfacing)
- kcurve->curveflags |= CURVE_KN_BACKFACING;
- if(use_encasing)
- kcurve->curveflags |= CURVE_KN_ENCLOSEFILTER;
-
- kcurve->normalmix = normalmix;
- kcurve->encasing_ratio = encasing_ratio;
+ if(use_curves) {
+ if(primitive == CURVE_SEGMENTS || primitive == CURVE_RIBBONS)
+ kcurve->curveflags |= CURVE_KN_INTERPOLATE;
+ if(primitive == CURVE_RIBBONS)
+ kcurve->curveflags |= CURVE_KN_RIBBONS;
+
+ if(line_method == CURVE_ACCURATE)
+ kcurve->curveflags |= CURVE_KN_ACCURATE;
+ if(line_method == CURVE_CORRECTED)
+ kcurve->curveflags |= CURVE_KN_INTERSECTCORRECTION;
+ if(line_method == CURVE_POSTCORRECTED)
+ kcurve->curveflags |= CURVE_KN_POSTINTERSECTCORRECTION;
+
+ if(use_tangent_normal)
+ kcurve->curveflags |= CURVE_KN_TANGENTGNORMAL;
+ if(use_tangent_normal_correction)
+ kcurve->curveflags |= CURVE_KN_NORMALCORRECTION;
+ if(use_tangent_normal_geometry)
+ kcurve->curveflags |= CURVE_KN_TRUETANGENTGNORMAL;
+ if(use_joined)
+ kcurve->curveflags |= CURVE_KN_CURVEDATA;
+ if(use_backfacing)
+ kcurve->curveflags |= CURVE_KN_BACKFACING;
+ if(use_encasing)
+ kcurve->curveflags |= CURVE_KN_ENCLOSEFILTER;
+
+ kcurve->normalmix = normalmix;
+ kcurve->encasing_ratio = encasing_ratio;
+ kcurve->subdivisions = subdivisions;
+ }
if(progress.get_cancel()) return;
@@ -123,14 +174,14 @@ bool CurveSystemManager::modified(const CurveSystemManager& CurveSystemManager)
encasing_ratio == CurveSystemManager.encasing_ratio &&
use_backfacing == CurveSystemManager.use_backfacing &&
normalmix == CurveSystemManager.normalmix &&
- use_cache == CurveSystemManager.use_cache &&
use_smooth == CurveSystemManager.use_smooth &&
triangle_method == CurveSystemManager.triangle_method &&
resolution == CurveSystemManager.resolution &&
use_curves == CurveSystemManager.use_curves &&
use_joined == CurveSystemManager.use_joined &&
segments == CurveSystemManager.segments &&
- use_parents == CurveSystemManager.use_parents);
+ use_parents == CurveSystemManager.use_parents &&
+ subdivisions == CurveSystemManager.subdivisions);
}
bool CurveSystemManager::modified_mesh(const CurveSystemManager& CurveSystemManager)
@@ -143,8 +194,7 @@ bool CurveSystemManager::modified_mesh(const CurveSystemManager& CurveSystemMana
resolution == CurveSystemManager.resolution &&
use_curves == CurveSystemManager.use_curves &&
use_joined == CurveSystemManager.use_joined &&
- segments == CurveSystemManager.segments &&
- use_cache == CurveSystemManager.use_cache);
+ segments == CurveSystemManager.segments);
}
void CurveSystemManager::tag_update(Scene *scene)
diff --git a/intern/cycles/render/curves.h b/intern/cycles/render/curves.h
index bb9ef6d99cf..3a12d33d0a7 100644
--- a/intern/cycles/render/curves.h
+++ b/intern/cycles/render/curves.h
@@ -29,6 +29,8 @@ class DeviceScene;
class Progress;
class Scene;
+void curvebounds(float *lower, float *upper, float3 *p, int dim);
+
typedef enum curve_presets {
CURVE_CUSTOM,
CURVE_TANGENT_SHADING,
@@ -39,13 +41,14 @@ typedef enum curve_presets {
typedef enum curve_primitives {
CURVE_TRIANGLES,
CURVE_LINE_SEGMENTS,
- CURVE_SEGMENTS
+ CURVE_SEGMENTS,
+ CURVE_RIBBONS
} curve_primitives;
typedef enum curve_triangles {
- CURVE_CAMERA,
- CURVE_RIBBONS,
- CURVE_TESSELATED
+ CURVE_CAMERA_TRIANGLES,
+ CURVE_RIBBON_TRIANGLES,
+ CURVE_TESSELATED_TRIANGLES
} curve_triangles;
typedef enum curve_lines {
@@ -98,13 +101,13 @@ public:
int triangle_method;
int resolution;
int segments;
+ int subdivisions;
float normalmix;
float encasing_ratio;
bool use_curves;
bool use_smooth;
- bool use_cache;
bool use_parents;
bool use_encasing;
bool use_backfacing;
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
index 14b219383d0..af27b46771c 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -708,7 +708,8 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
value2_in->value.x = 1.0f;
weight_out = math_node->output("Value");
- disconnect(weight_in);
+ if(weight_in->link)
+ disconnect(weight_in);
}
/* connected to closure mix weight */
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index 230a12f9ff2..e6f8ab4a5d9 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -85,11 +85,21 @@ bool ImageManager::set_animation_frame_update(int frame)
return false;
}
-bool ImageManager::is_float_image(const string& filename)
+bool ImageManager::is_float_image(const string& filename, bool is_builtin)
{
- ImageInput *in = ImageInput::create(filename);
bool is_float = false;
+ if(is_builtin) {
+ if(builtin_image_info_cb) {
+ int width, height, channels;
+ builtin_image_info_cb(filename, is_float, width, height, channels);
+ }
+
+ return is_float;
+ }
+
+ ImageInput *in = ImageInput::create(filename);
+
if(in) {
ImageSpec spec;
@@ -113,13 +123,13 @@ bool ImageManager::is_float_image(const string& filename)
return is_float;
}
-int ImageManager::add_image(const string& filename, bool animated, bool& is_float)
+int ImageManager::add_image(const string& filename, bool is_builtin, bool animated, bool& is_float)
{
Image *img;
size_t slot;
/* load image info and find out if we need a float texture */
- is_float = (pack_images)? false: is_float_image(filename);
+ is_float = (pack_images)? false: is_float_image(filename, is_builtin);
if(is_float) {
/* find existing image */
@@ -150,6 +160,7 @@ int ImageManager::add_image(const string& filename, bool animated, bool& is_floa
/* add new image */
img = new Image();
img->filename = filename;
+ img->is_builtin = is_builtin;
img->need_load = true;
img->animated = animated;
img->users = 1;
@@ -184,6 +195,7 @@ int ImageManager::add_image(const string& filename, bool animated, bool& is_floa
/* add new image */
img = new Image();
img->filename = filename;
+ img->is_builtin = is_builtin;
img->need_load = true;
img->animated = animated;
img->users = 1;
@@ -197,12 +209,12 @@ int ImageManager::add_image(const string& filename, bool animated, bool& is_floa
return slot;
}
-void ImageManager::remove_image(const string& filename)
+void ImageManager::remove_image(const string& filename, bool is_builtin)
{
size_t slot;
for(slot = 0; slot < images.size(); slot++) {
- if(images[slot] && images[slot]->filename == filename) {
+ if(images[slot] && images[slot]->filename == filename && images[slot]->is_builtin == is_builtin) {
/* decrement user count */
images[slot]->users--;
assert(images[slot]->users >= 0);
@@ -220,7 +232,7 @@ void ImageManager::remove_image(const string& filename)
if(slot == images.size()) {
/* see if it's in a float texture slot */
for(slot = 0; slot < float_images.size(); slot++) {
- if(float_images[slot] && float_images[slot]->filename == filename) {
+ if(float_images[slot] && float_images[slot]->filename == filename && float_images[slot]->is_builtin == is_builtin) {
/* decrement user count */
float_images[slot]->users--;
assert(float_images[slot]->users >= 0);
@@ -242,27 +254,43 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
if(img->filename == "")
return false;
- /* load image from file through OIIO */
- ImageInput *in = ImageInput::create(img->filename);
+ ImageInput *in = NULL;
+ int width, height, components;
- if(!in)
- return false;
+ if(!img->is_builtin) {
+ /* load image from file through OIIO */
+ in = ImageInput::create(img->filename);
- ImageSpec spec;
+ if(!in)
+ return false;
- if(!in->open(img->filename, spec)) {
- delete in;
- return false;
+ ImageSpec spec;
+
+ if(!in->open(img->filename, spec)) {
+ delete in;
+ return false;
+ }
+
+ width = spec.width;
+ height = spec.height;
+ components = spec.nchannels;
+ }
+ else {
+ /* load image using builtin images callbacks */
+ if(!builtin_image_info_cb || !builtin_image_pixels_cb)
+ return false;
+
+ bool is_float;
+ builtin_image_info_cb(img->filename, is_float, width, height, components);
}
/* we only handle certain number of components */
- int width = spec.width;
- int height = spec.height;
- int components = spec.nchannels;
-
if(!(components == 1 || components == 3 || components == 4)) {
- in->close();
- delete in;
+ if(in) {
+ in->close();
+ delete in;
+ }
+
return false;
}
@@ -270,14 +298,19 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
uchar *pixels = (uchar*)tex_img.resize(width, height);
int scanlinesize = width*components*sizeof(uchar);
- in->read_image(TypeDesc::UINT8,
- (uchar*)pixels + (height-1)*scanlinesize,
- AutoStride,
- -scanlinesize,
- AutoStride);
+ if(in) {
+ in->read_image(TypeDesc::UINT8,
+ (uchar*)pixels + (height-1)*scanlinesize,
+ AutoStride,
+ -scanlinesize,
+ AutoStride);
- in->close();
- delete in;
+ in->close();
+ delete in;
+ }
+ else {
+ builtin_image_pixels_cb(img->filename, pixels);
+ }
if(components == 3) {
for(int i = width*height-1; i >= 0; i--) {
@@ -304,27 +337,42 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_
if(img->filename == "")
return false;
- /* load image from file through OIIO */
- ImageInput *in = ImageInput::create(img->filename);
+ ImageInput *in = NULL;
+ int width, height, components;
- if(!in)
- return false;
+ if(!img->is_builtin) {
+ /* load image from file through OIIO */
+ in = ImageInput::create(img->filename);
- ImageSpec spec;
+ if(!in)
+ return false;
- if(!in->open(img->filename, spec)) {
- delete in;
- return false;
+ ImageSpec spec;
+
+ if(!in->open(img->filename, spec)) {
+ delete in;
+ return false;
+ }
+
+ /* we only handle certain number of components */
+ width = spec.width;
+ height = spec.height;
+ components = spec.nchannels;
}
+ else {
+ /* load image using builtin images callbacks */
+ if(!builtin_image_info_cb || !builtin_image_float_pixels_cb)
+ return false;
- /* we only handle certain number of components */
- int width = spec.width;
- int height = spec.height;
- int components = spec.nchannels;
+ bool is_float;
+ builtin_image_info_cb(img->filename, is_float, width, height, components);
+ }
if(!(components == 1 || components == 3 || components == 4)) {
- in->close();
- delete in;
+ if(in) {
+ in->close();
+ delete in;
+ }
return false;
}
@@ -332,14 +380,19 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_
float *pixels = (float*)tex_img.resize(width, height);
int scanlinesize = width*components*sizeof(float);
- in->read_image(TypeDesc::FLOAT,
- (uchar*)pixels + (height-1)*scanlinesize,
- AutoStride,
- -scanlinesize,
- AutoStride);
+ if(in) {
+ in->read_image(TypeDesc::FLOAT,
+ (uchar*)pixels + (height-1)*scanlinesize,
+ AutoStride,
+ -scanlinesize,
+ AutoStride);
- in->close();
- delete in;
+ in->close();
+ delete in;
+ }
+ else {
+ builtin_image_float_pixels_cb(img->filename, pixels);
+ }
if(components == 3) {
for(int i = width*height-1; i >= 0; i--) {
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index 4d177174971..e39ac14b60f 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -51,9 +51,9 @@ public:
ImageManager();
~ImageManager();
- int add_image(const string& filename, bool animated, bool& is_float);
- void remove_image(const string& filename);
- bool is_float_image(const string& filename);
+ int add_image(const string& filename, bool is_builtin, bool animated, bool& is_float);
+ void remove_image(const string& filename, bool is_builtin);
+ bool is_float_image(const string& filename, bool is_builtin);
void device_update(Device *device, DeviceScene *dscene, Progress& progress);
void device_free(Device *device, DeviceScene *dscene);
@@ -65,6 +65,9 @@ public:
bool need_update;
+ boost::function<void(const string &filename, bool &is_float, int &width, int &height, int &channels)> builtin_image_info_cb;
+ boost::function<bool(const string &filename, unsigned char *pixels)> builtin_image_pixels_cb;
+ boost::function<bool(const string &filename, float *pixels)> builtin_image_float_pixels_cb;
private:
int tex_num_images;
int tex_num_float_images;
@@ -74,6 +77,7 @@ private:
struct Image {
string filename;
+ bool is_builtin;
bool need_load;
bool animated;
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index 1b94d603a26..04fea1953e7 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -198,8 +198,10 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
bool have_emission = false;
/* skip if we are not visible for BSDFs */
- if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT)))
+ if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) {
+ j++;
continue;
+ }
/* skip if we have no emission shaders */
foreach(uint sindex, mesh->used_shaders) {
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index d4619dcff55..57776e4cfa6 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -43,6 +43,7 @@ Mesh::Mesh()
need_update = true;
transform_applied = false;
transform_negative_scaled = false;
+ transform_normal = transform_identity();
displacement_method = DISPLACE_BUMP;
bounds = BoundBox::empty;
@@ -94,6 +95,7 @@ void Mesh::clear()
transform_applied = false;
transform_negative_scaled = false;
+ transform_normal = transform_identity();
}
void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_)
@@ -151,7 +153,7 @@ void Mesh::add_face_normals()
/* don't compute if already there */
if(attributes.find(ATTR_STD_FACE_NORMAL))
return;
-
+
/* get attributes */
Attribute *attr_fN = attributes.add(ATTR_STD_FACE_NORMAL);
float3 *fN = attr_fN->data_float3();
@@ -181,6 +183,14 @@ void Mesh::add_face_normals()
fN[i] = -fN[i];
}
}
+
+ /* expected to be in local space */
+ if(transform_applied) {
+ Transform ntfm = transform_inverse(transform_normal);
+
+ for(size_t i = 0; i < triangles_size; i++)
+ fN[i] = normalize(transform_direction(&ntfm, fN[i]));
+ }
}
void Mesh::add_vertex_normals()
@@ -188,7 +198,7 @@ void Mesh::add_vertex_normals()
/* don't compute if already there */
if(attributes.find(ATTR_STD_VERTEX_NORMAL))
return;
-
+
/* get attributes */
Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL);
Attribute *attr_vN = attributes.add(ATTR_STD_VERTEX_NORMAL);
@@ -232,10 +242,18 @@ void Mesh::pack_normals(Scene *scene, float4 *normal, float4 *vnormal)
size_t triangles_size = triangles.size();
uint *shader_ptr = (shader.size())? &shader[0]: NULL;
+ bool do_transform = transform_applied;
+ Transform ntfm = transform_normal;
+
for(size_t i = 0; i < triangles_size; i++) {
- normal[i].x = fN[i].x;
- normal[i].y = fN[i].y;
- normal[i].z = fN[i].z;
+ float3 fNi = fN[i];
+
+ if(do_transform)
+ fNi = normalize(transform_direction(&ntfm, fNi));
+
+ normal[i].x = fNi.x;
+ normal[i].y = fNi.y;
+ normal[i].z = fNi.z;
/* stuff shader id in here too */
if(shader_ptr[i] != last_shader || last_smooth != smooth[i]) {
@@ -249,8 +267,14 @@ void Mesh::pack_normals(Scene *scene, float4 *normal, float4 *vnormal)
size_t verts_size = verts.size();
- for(size_t i = 0; i < verts_size; i++)
- vnormal[i] = make_float4(vN[i].x, vN[i].y, vN[i].z, 0.0f);
+ for(size_t i = 0; i < verts_size; i++) {
+ float3 vNi = vN[i];
+
+ if(do_transform)
+ vNi = normalize(transform_direction(&ntfm, vNi));
+
+ vnormal[i] = make_float4(vNi.x, vNi.y, vNi.z, 0.0f);
+ }
}
void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset)
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index b83752ad8df..dca1b00e1ff 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -90,6 +90,7 @@ public:
BoundBox bounds;
bool transform_applied;
bool transform_negative_scaled;
+ Transform transform_normal;
DisplacementMethod displacement_method;
/* Update Flags */
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 14ef3c68ad3..5444299b948 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -142,8 +142,9 @@ ImageTextureNode::ImageTextureNode()
slot = -1;
is_float = -1;
filename = "";
+ is_builtin = false;
color_space = ustring("Color");
- projection = ustring("Flat");;
+ projection = ustring("Flat");
projection_blend = 0.0f;
animated = false;
@@ -155,7 +156,7 @@ ImageTextureNode::ImageTextureNode()
ImageTextureNode::~ImageTextureNode()
{
if(image_manager)
- image_manager->remove_image(filename);
+ image_manager->remove_image(filename, is_builtin);
}
ShaderNode *ImageTextureNode::clone() const
@@ -176,7 +177,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
image_manager = compiler.image_manager;
if(is_float == -1) {
bool is_float_bool;
- slot = image_manager->add_image(filename, animated, is_float_bool);
+ slot = image_manager->add_image(filename, is_builtin, animated, is_float_bool);
is_float = (int)is_float_bool;
}
@@ -237,7 +238,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
tex_mapping.compile(compiler);
if(is_float == -1)
- is_float = (int)image_manager->is_float_image(filename);
+ is_float = (int)image_manager->is_float_image(filename, false);
compiler.parameter("filename", filename.c_str());
if(is_float || color_space != "Color")
@@ -271,6 +272,7 @@ EnvironmentTextureNode::EnvironmentTextureNode()
slot = -1;
is_float = -1;
filename = "";
+ is_builtin = false;
color_space = ustring("Color");
projection = ustring("Equirectangular");
animated = false;
@@ -283,7 +285,7 @@ EnvironmentTextureNode::EnvironmentTextureNode()
EnvironmentTextureNode::~EnvironmentTextureNode()
{
if(image_manager)
- image_manager->remove_image(filename);
+ image_manager->remove_image(filename, is_builtin);
}
ShaderNode *EnvironmentTextureNode::clone() const
@@ -304,7 +306,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
image_manager = compiler.image_manager;
if(slot == -1) {
bool is_float_bool;
- slot = image_manager->add_image(filename, animated, is_float_bool);
+ slot = image_manager->add_image(filename, is_builtin, animated, is_float_bool);
is_float = (int)is_float_bool;
}
@@ -354,7 +356,7 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
tex_mapping.compile(compiler);
if(is_float == -1)
- is_float = (int)image_manager->is_float_image(filename);
+ is_float = (int)image_manager->is_float_image(filename, false);
compiler.parameter("filename", filename.c_str());
compiler.parameter("projection", projection);
@@ -3255,6 +3257,8 @@ void NormalMapNode::attributes(AttributeRequestSet *attributes)
attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
}
+
+ attributes->add(ATTR_STD_VERTEX_NORMAL);
}
ShaderNode::attributes(attributes);
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 564ceee5a5b..8b2d6a0e5c8 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -70,6 +70,7 @@ public:
int slot;
int is_float;
string filename;
+ bool is_builtin;
ustring color_space;
ustring projection;
float projection_blend;
@@ -89,6 +90,7 @@ public:
int slot;
int is_float;
string filename;
+ bool is_builtin;
ustring color_space;
ustring projection;
bool animated;
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index a89f8afd251..8d8087266c1 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -91,38 +91,16 @@ void Object::apply_transform()
for(size_t i = 0; i < mesh->curve_keys.size(); i++)
mesh->curve_keys[i].co = transform_point(&tfm, mesh->curve_keys[i].co);
- Attribute *attr_tangent = mesh->curve_attributes.find(ATTR_STD_CURVE_TANGENT);
- Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL);
- Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
-
- Transform ntfm = transform_transpose(transform_inverse(tfm));
+ /* store matrix to transform later. when accessing these as attributes we
+ * do not want the transform to be applied for consistency between static
+ * and dynamic BVH, so we do it on packing. */
+ mesh->transform_normal = transform_transpose(transform_inverse(tfm));
/* we keep normals pointing in same direction on negative scale, notify
* mesh about this in it (re)calculates normals */
if(transform_negative_scale(tfm))
mesh->transform_negative_scaled = true;
- if(attr_fN) {
- float3 *fN = attr_fN->data_float3();
-
- for(size_t i = 0; i < mesh->triangles.size(); i++)
- fN[i] = transform_direction(&ntfm, fN[i]);
- }
-
- if(attr_vN) {
- float3 *vN = attr_vN->data_float3();
-
- for(size_t i = 0; i < mesh->verts.size(); i++)
- vN[i] = transform_direction(&ntfm, vN[i]);
- }
-
- if(attr_tangent) {
- float3 *tangent = attr_tangent->data_float3();
-
- for(size_t i = 0; i < mesh->curve_keys.size(); i++)
- tangent[i] = transform_direction(&tfm, tangent[i]);
- }
-
if(bounds.valid()) {
mesh->compute_bounds();
compute_bounds(false, 0.0f);
diff --git a/intern/cycles/util/util_cuda.cpp b/intern/cycles/util/util_cuda.cpp
index 12cb0d3e254..6c9ee7c548f 100644
--- a/intern/cycles/util/util_cuda.cpp
+++ b/intern/cycles/util/util_cuda.cpp
@@ -376,21 +376,23 @@ bool cuLibraryInit()
/* cuda 4.0 */
CUDA_LIBRARY_FIND(cuCtxSetCurrent);
-#ifndef WITH_CUDA_BINARIES
-#ifdef _WIN32
- return false; /* runtime build doesn't work at the moment */
-#else
- if(cuCompilerPath() == "")
- return false;
-#endif
+ if(cuHavePrecompiledKernels())
+ result = true;
+#ifndef _WIN32
+ else if(cuCompilerPath() != "")
+ result = true;
#endif
- /* success */
- result = true;
-
return result;
}
+bool cuHavePrecompiledKernels()
+{
+ string cubins_path = path_get("lib");
+
+ return path_exists(cubins_path);
+}
+
string cuCompilerPath()
{
#ifdef _WIN32
diff --git a/intern/cycles/util/util_cuda.h b/intern/cycles/util/util_cuda.h
index 9682f1cfe1d..69cf025de77 100644
--- a/intern/cycles/util/util_cuda.h
+++ b/intern/cycles/util/util_cuda.h
@@ -30,6 +30,7 @@ CCL_NAMESPACE_BEGIN
* matrixMulDynlinkJIT in the CUDA SDK. */
bool cuLibraryInit();
+bool cuHavePrecompiledKernels();
string cuCompilerPath();
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp
index 8c4ec312256..43f15ba0ce6 100644
--- a/intern/cycles/util/util_task.cpp
+++ b/intern/cycles/util/util_task.cpp
@@ -152,7 +152,6 @@ void TaskPool::num_increase()
thread_mutex TaskScheduler::mutex;
int TaskScheduler::users = 0;
vector<thread*> TaskScheduler::threads;
-vector<int> TaskScheduler::thread_level;
volatile bool TaskScheduler::do_exit = false;
list<TaskScheduler::Entry> TaskScheduler::queue;
@@ -179,12 +178,9 @@ void TaskScheduler::init(int num_threads)
/* launch threads that will be waiting for work */
threads.resize(num_threads);
- thread_level.resize(num_threads);
- for(size_t i = 0; i < threads.size(); i++) {
+ for(size_t i = 0; i < threads.size(); i++)
threads[i] = new thread(function_bind(&TaskScheduler::thread_run, i));
- thread_level[i] = 0;
- }
}
users++;
@@ -208,7 +204,6 @@ void TaskScheduler::exit()
}
threads.clear();
- thread_level.clear();
}
}
diff --git a/intern/cycles/util/util_task.h b/intern/cycles/util/util_task.h
index b795ca7524b..5bca3f255af 100644
--- a/intern/cycles/util/util_task.h
+++ b/intern/cycles/util/util_task.h
@@ -111,7 +111,6 @@ protected:
static thread_mutex mutex;
static int users;
static vector<thread*> threads;
- static vector<int> thread_level;
static volatile bool do_exit;
static list<Entry> queue;
diff --git a/intern/dualcon/intern/MemoryAllocator.h b/intern/dualcon/intern/MemoryAllocator.h
index b704542d27b..e673d9498d2 100644
--- a/intern/dualcon/intern/MemoryAllocator.h
+++ b/intern/dualcon/intern/MemoryAllocator.h
@@ -43,6 +43,8 @@
class VirtualMemoryAllocator
{
public:
+virtual ~VirtualMemoryAllocator() {}
+
virtual void *allocate( ) = 0;
virtual void deallocate(void *obj) = 0;
virtual void destroy( ) = 0;
diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h
index 37cde2c2837..c07dc869291 100644
--- a/intern/ffmpeg/ffmpeg_compat.h
+++ b/intern/ffmpeg/ffmpeg_compat.h
@@ -33,6 +33,7 @@
#include <libavcodec/avcodec.h>
#include <libavutil/rational.h>
#include <libavutil/opt.h>
+#include <libavutil/mathematics.h>
#if (LIBAVFORMAT_VERSION_MAJOR > 52) || ((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 101))
#define FFMPEG_HAVE_PARSE_UTILS 1
@@ -75,10 +76,68 @@
#define FFMPEG_FFV1_ALPHA_SUPPORTED
#endif
+#if ((LIBAVUTIL_VERSION_MAJOR < 51) || (LIBAVUTIL_VERSION_MAJOR == 51) && (LIBAVUTIL_VERSION_MINOR < 22))
+static inline
+int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
+{
+ const AVOption *rv = NULL;
+ av_set_string3(obj, name, val, 1, &rv);
+ return rv != NULL;
+}
+
+static inline
+int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags)
+{
+ const AVOption *rv = NULL;
+ rv = av_set_int(obj, name, val);
+ return rv != NULL;
+}
+
+static inline
+int av_opt_set_double(void *obj, const char *name, double val, int search_flags)
+{
+ const AVOption *rv = NULL;
+ rv = av_set_double(obj, name, val);
+ return rv != NULL;
+}
+
+#define AV_OPT_TYPE_INT FF_OPT_TYPE_INT
+#define AV_OPT_TYPE_INT64 FF_OPT_TYPE_INT64
+#define AV_OPT_TYPE_STRING FF_OPT_TYPE_STRING
+#define AV_OPT_TYPE_CONST FF_OPT_TYPE_CONST
+#define AV_OPT_TYPE_DOUBLE FF_OPT_TYPE_DOUBLE
+#define AV_OPT_TYPE_FLOAT FF_OPT_TYPE_FLOAT
+#endif
+
#if ((LIBAVFORMAT_VERSION_MAJOR < 53) || ((LIBAVFORMAT_VERSION_MAJOR == 53) && (LIBAVFORMAT_VERSION_MINOR < 24)) || ((LIBAVFORMAT_VERSION_MAJOR == 53) && (LIBAVFORMAT_VERSION_MINOR < 24) && (LIBAVFORMAT_VERSION_MICRO < 2)))
#define avformat_close_input(x) av_close_input_file(*(x))
#endif
+#if ((LIBAVCODEC_VERSION_MAJOR < 53) || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR < 35))
+static inline
+int avcodec_open2(AVCodecContext *avctx, AVCodec *codec, AVDictionary **options)
+{
+ /* TODO: no options are taking into account */
+ return avcodec_open(avctx, codec);
+}
+#endif
+
+#if ((LIBAVFORMAT_VERSION_MAJOR < 53) || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR < 21))
+static inline
+AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c)
+{
+ /* TODO: no codec is taking into account */
+ return av_new_stream(s, 0);
+}
+
+static inline
+int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
+{
+ /* TODO: no options are taking into account */
+ return av_find_stream_info(ic);
+}
+#endif
+
#if ((LIBAVFORMAT_VERSION_MAJOR > 53) || ((LIBAVFORMAT_VERSION_MAJOR == 53) && (LIBAVFORMAT_VERSION_MINOR > 32)) || ((LIBAVFORMAT_VERSION_MAJOR == 53) && (LIBAVFORMAT_VERSION_MINOR == 24) && (LIBAVFORMAT_VERSION_MICRO >= 100)))
static inline
void my_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index ab5feb287d8..ffdee6c1550 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -860,7 +860,7 @@ extern int GHOST_UseNativePixels(void);
/**
* If window was opened using native pixel size, it returns scaling factor.
*/
-extern float GHOST_GetNativePixelSize(void);
+extern float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle);
#ifdef __cplusplus
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index dfe01521a29..1b3509c1ac3 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -297,10 +297,8 @@ public:
/**
* Native pixel size support (MacBook 'retina').
- * \return The pixel size in float.
*/
virtual bool useNativePixel(void) = 0;
- virtual float getNativePixelSize(void) = 0;
/***************************************************************************************
* Event management functionality
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index 88f130aabe8..4cf0dbfb820 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -305,6 +305,10 @@ public:
*/
virtual GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode mode, GHOST_Rect *bounds, GHOST_TInt32 mouse_ungrab_xy[2]) { return GHOST_kSuccess; }
+
+ virtual float getNativePixelSize(void) = 0;
+
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_IWindow")
#endif
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 868d787b5f9..35dff73f4af 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -183,6 +183,7 @@ typedef enum {
GHOST_kEventDraggingDropDone,
GHOST_kEventOpenMainFile, // Needed for Cocoa to open double-clicked .blend file at startup
+ GHOST_kEventNativeResolutionChange, // Needed for Cocoa when window moves to other display
GHOST_kEventTimer,
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index ba0a6eba36f..be64acf8c94 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -885,9 +885,11 @@ int GHOST_UseNativePixels(void)
return system->useNativePixel();
}
-float GHOST_GetNativePixelSize(void)
+float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle)
{
- GHOST_ISystem *system = GHOST_ISystem::getSystem();
- return system->getNativePixelSize();
+ GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
+ if (window)
+ return window->getNativePixelSize();
+ return 1.0f;
}
diff --git a/intern/ghost/intern/GHOST_Debug.h b/intern/ghost/intern/GHOST_Debug.h
index f0db1b3de8d..9292235a9c7 100644
--- a/intern/ghost/intern/GHOST_Debug.h
+++ b/intern/ghost/intern/GHOST_Debug.h
@@ -58,12 +58,23 @@
# define GHOST_PRINTF(x, ...)
#endif // GHOST_DEBUG
-
-#ifdef GHOST_DEBUG
+#ifdef WITH_ASSERT_ABORT
+# include <stdio.h> //for fprintf()
+# include <stdlib.h> //for abort()
+# define GHOST_ASSERT(x, info) \
+ { \
+ if (!(x)) { \
+ fprintf(stderr, "GHOST_ASSERT failed: "); \
+ fprintf(stderr, info); \
+ fprintf(stderr, "\n"); \
+ abort(); \
+ } \
+ } (void)0
+#elif defined(GHOST_DEBUG)
# define GHOST_ASSERT(x, info) \
{ \
if (!(x)) { \
- GHOST_PRINT("assertion failed: "); \
+ GHOST_PRINT("GHOST_ASSERT failed: "); \
GHOST_PRINT(info); \
GHOST_PRINT("\n"); \
} \
diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
index 83df9971158..0bfc67a9126 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
@@ -52,11 +52,15 @@ GHOST_DisplayManagerWin32::GHOST_DisplayManagerWin32(void)
GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplays(GHOST_TUns8& numDisplays) const
{
- // We do not support multiple monitors at the moment
numDisplays = ::GetSystemMetrics(SM_CMONITORS);
return numDisplays > 0 ? GHOST_kSuccess : GHOST_kFailure;
}
+static BOOL get_dd(DWORD d, DISPLAY_DEVICE* dd)
+{
+ dd->cb = sizeof(DISPLAY_DEVICE);
+ return ::EnumDisplayDevices(NULL, d, dd, 0);
+}
/*
* When you call EnumDisplaySettings with iModeNum set to zero, the operating system
@@ -67,10 +71,12 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplays(GHOST_TUns8& numDisplay
*/
GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const
{
- GHOST_ASSERT((display == kMainDisplay), "GHOST_DisplayManagerWin32::getNumDisplaySettings(): only main displlay is supported");
+ DISPLAY_DEVICE display_device;
+ if (!get_dd(display, &display_device)) return GHOST_kFailure;
+
numSettings = 0;
DEVMODE dm;
- while (::EnumDisplaySettings(NULL, numSettings, &dm)) {
+ while (::EnumDisplaySettings(display_device.DeviceName, numSettings, &dm)) {
numSettings++;
}
return GHOST_kSuccess;
@@ -79,10 +85,12 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplaySettings(GHOST_TUns8 disp
GHOST_TSuccess GHOST_DisplayManagerWin32::getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const
{
- GHOST_ASSERT((display == kMainDisplay), "GHOST_DisplayManagerWin32::getDisplaySetting(): only main display is supported");
+ DISPLAY_DEVICE display_device;
+ if (!get_dd(display, &display_device)) return GHOST_kFailure;
+
GHOST_TSuccess success;
DEVMODE dm;
- if (::EnumDisplaySettings(NULL, index, &dm)) {
+ if (::EnumDisplaySettings(display_device.DeviceName, index, &dm)) {
#ifdef GHOST_DEBUG
printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", dm.dmPelsWidth, dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency);
#endif // GHOST_DEBUG
@@ -112,23 +120,23 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::getDisplaySetting(GHOST_TUns8 display,
GHOST_TSuccess GHOST_DisplayManagerWin32::getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const
{
- GHOST_ASSERT((display == kMainDisplay), "GHOST_DisplayManagerWin32::getCurrentDisplaySetting(): only main display is supported");
- return getDisplaySetting(kMainDisplay, ENUM_CURRENT_SETTINGS, setting);
+ return getDisplaySetting(display, ENUM_CURRENT_SETTINGS, setting);
}
GHOST_TSuccess GHOST_DisplayManagerWin32::setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting)
{
- GHOST_ASSERT((display == kMainDisplay), "GHOST_DisplayManagerWin32::setCurrentDisplaySetting(): only main display is supported");
+ DISPLAY_DEVICE display_device;
+ if (!get_dd(display, &display_device)) return GHOST_kFailure;
GHOST_DisplaySetting match;
findMatch(display, setting, match);
DEVMODE dm;
int i = 0;
- while (::EnumDisplaySettings(NULL, i++, &dm)) {
- if ((dm.dmBitsPerPel == match.bpp) &&
- (dm.dmPelsWidth == match.xPixels) &&
- (dm.dmPelsHeight == match.yPixels) &&
+ while (::EnumDisplaySettings(display_device.DeviceName, i++, &dm)) {
+ if ((dm.dmBitsPerPel == match.bpp ) &&
+ (dm.dmPelsWidth == match.xPixels) &&
+ (dm.dmPelsHeight == match.yPixels) &&
(dm.dmDisplayFrequency == match.frequency))
{
break;
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index 41beeac6b51..080619bc0ac 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -46,7 +46,6 @@
GHOST_System::GHOST_System()
: m_nativePixel(false),
- m_nativePixelSize(1),
m_displayManager(0),
m_timerManager(0),
m_windowManager(0),
@@ -382,9 +381,3 @@ bool GHOST_System::useNativePixel(void)
return 1;
}
-float GHOST_System::getNativePixelSize(void)
-{
- if (m_nativePixel)
- return m_nativePixelSize;
- return 1.0f;
-}
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index 5060f22c509..928bbe6a31b 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -175,9 +175,6 @@ public:
virtual bool useNativePixel(void);
bool m_nativePixel;
- virtual float getNativePixelSize(void);
- float m_nativePixelSize;
-
/***************************************************************************************
* Event management functionality
***************************************************************************************/
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index ac3e22368bc..1665180b687 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -1038,6 +1038,10 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window) );
break;
case GHOST_kEventWindowUpdate:
+ if (m_nativePixel) {
+ window->setNativePixelSize();
+ pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventNativeResolutionChange, window) );
+ }
pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) );
break;
case GHOST_kEventWindowMove:
@@ -1054,6 +1058,13 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
//m_ignoreWindowSizedMessages = true;
}
break;
+ case GHOST_kEventNativeResolutionChange:
+
+ if (m_nativePixel) {
+ window->setNativePixelSize();
+ pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventNativeResolutionChange, window) );
+ }
+
default:
return GHOST_kFailure;
break;
@@ -1592,7 +1603,8 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
}
break;
- /* these events only happen on swiping trackpads */
+ /* these events only happen on swiping trackpads or tablets */
+ /* warning: using tablet + trackpad at same time frustrates this static variable */
case NSEventTypeBeginGesture:
m_hasMultiTouchTrackpad = 1;
break;
@@ -1626,9 +1638,17 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
double dy;
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+ int phase = [event phase];
+
/* with 10.7 nice scrolling deltas are supported */
dx = [event scrollingDeltaX];
dy = [event scrollingDeltaY];
+
+ /* however, wacom tablet (intuos5) needs old deltas, it then has momentum and phase at zero */
+ if (phase == 0 && momentum==NULL) {
+ dx = [event deltaX];
+ dy = [event deltaY];
+ }
#else
/* trying to pretend you have nice scrolls... */
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 75d606a5d79..50d7b372dd6 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -783,8 +783,8 @@ GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType,
void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO *minmax)
{
- minmax->ptMinTrackSize.x = 640;
- minmax->ptMinTrackSize.y = 480;
+ minmax->ptMinTrackSize.x = 320;
+ minmax->ptMinTrackSize.y = 240;
}
#ifdef WITH_INPUT_NDOF
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index f5cb0d9323c..28a228b2777 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -69,8 +69,10 @@
#include <stdio.h> /* for fprintf only */
#include <cstdlib> /* for exit */
-static GHOST_TKey
-convertXKey(KeySym key);
+/* for debugging - so we can breakpoint X11 errors */
+// #define USE_X11_ERROR_HANDLERS
+
+static GHOST_TKey convertXKey(KeySym key);
/* these are for copy and select copy */
static char *txt_cut_buffer = NULL;
@@ -91,6 +93,11 @@ GHOST_SystemX11(
abort(); /* was return before, but this would just mean it will crash later */
}
+#ifdef USE_X11_ERROR_HANDLERS
+ (void) XSetErrorHandler(GHOST_X11_ApplicationErrorHandler);
+ (void) XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler);
+#endif
+
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
/* note -- don't open connection to XIM server here, because the locale
* has to be set before opening the connection but setlocale() has not
@@ -146,6 +153,12 @@ GHOST_SystemX11(
XkbSetDetectableAutoRepeat(m_display, true, NULL);
}
+#ifdef WITH_X11_XINPUT
+ /* initialize incase X11 fails to load */
+ memset(&m_xtablet, 0, sizeof(m_xtablet));
+
+ initXInputDevices();
+#endif
}
GHOST_SystemX11::
@@ -157,6 +170,15 @@ GHOST_SystemX11::
}
#endif
+#ifdef WITH_X11_XINPUT
+ /* close tablet devices */
+ if (m_xtablet.StylusDevice)
+ XCloseDevice(m_display, m_xtablet.StylusDevice);
+
+ if (m_xtablet.EraserDevice)
+ XCloseDevice(m_display, m_xtablet.EraserDevice);
+#endif /* WITH_X11_XINPUT */
+
XCloseDisplay(m_display);
}
@@ -494,12 +516,52 @@ processEvents(
#ifdef WITH_X11_XINPUT
/* set currently using tablet mode (stylus or eraser) depending on device ID */
-static void setTabletMode(GHOST_WindowX11 *window, XID deviceid)
+static void setTabletMode(GHOST_SystemX11 *system, GHOST_WindowX11 *window, XID deviceid)
{
- if (deviceid == window->GetXTablet().StylusID)
- window->GetXTablet().CommonData.Active = GHOST_kTabletModeStylus;
- else if (deviceid == window->GetXTablet().EraserID)
- window->GetXTablet().CommonData.Active = GHOST_kTabletModeEraser;
+ if (deviceid == system->GetXTablet().StylusID)
+ window->GetTabletData()->Active = GHOST_kTabletModeStylus;
+ else if (deviceid == system->GetXTablet().EraserID)
+ window->GetTabletData()->Active = GHOST_kTabletModeEraser;
+}
+#endif /* WITH_X11_XINPUT */
+
+#ifdef WITH_X11_XINPUT
+static bool checkTabletProximity(Display *display, XDevice *device)
+{
+ /* we could have true/false/not-found return value, but for now false is OK */
+
+ /* see: state.c from xinput, to get more data out of the device */
+ XDeviceState *state;
+
+ if (device == NULL) {
+ return false;
+ }
+
+ state = XQueryDeviceState(display, device);
+
+ if (state) {
+ XInputClass *cls = state->data;
+ // printf("%d class%s :\n", state->num_classes,
+ // (state->num_classes > 1) ? "es" : "");
+ for (int loop = 0; loop < state->num_classes; loop++) {
+ switch (cls->c_class) {
+ case ValuatorClass:
+ XValuatorState *val_state = (XValuatorState *)cls;
+ // printf("ValuatorClass Mode=%s Proximity=%s\n",
+ // val_state->mode & 1 ? "Absolute" : "Relative",
+ // val_state->mode & 2 ? "Out" : "In");
+
+ if ((val_state->mode & 2) == 0) {
+ XFreeDeviceState(state);
+ return true;
+ }
+ break;
+ }
+ cls = (XInputClass *) ((char *)cls + cls->length);
+ }
+ XFreeDeviceState(state);
+ }
+ return false;
}
#endif /* WITH_X11_XINPUT */
@@ -512,7 +574,23 @@ GHOST_SystemX11::processEvent(XEvent *xe)
if (!window) {
return;
}
-
+
+#ifdef WITH_X11_XINPUT
+ /* Proximity-Out Events are not reliable, if the tablet is active - check on each event
+ * this adds a little overhead but only while the tablet is in use.
+ * in the futire we could have a ghost call window->CheckTabletProximity()
+ * but for now enough parts of the code are checking 'Active'
+ * - campbell */
+ if (window->GetTabletData()->Active != GHOST_kTabletModeNone) {
+ if (checkTabletProximity(xe->xany.display, m_xtablet.StylusDevice) == false &&
+ checkTabletProximity(xe->xany.display, m_xtablet.EraserDevice) == false)
+ {
+ // printf("proximity disable\n");
+ window->GetTabletData()->Active = GHOST_kTabletModeNone;
+ }
+ }
+#endif /* WITH_X11_XINPUT */
+
switch (xe->type) {
case Expose:
{
@@ -537,7 +615,7 @@ GHOST_SystemX11::processEvent(XEvent *xe)
XMotionEvent &xme = xe->xmotion;
#ifdef WITH_X11_XINPUT
- bool is_tablet = window->GetXTablet().CommonData.Active != GHOST_kTabletModeNone;
+ bool is_tablet = window->GetTabletData()->Active != GHOST_kTabletModeNone;
#else
bool is_tablet = false;
#endif
@@ -983,31 +1061,31 @@ GHOST_SystemX11::processEvent(XEvent *xe)
default: {
#ifdef WITH_X11_XINPUT
- if (xe->type == window->GetXTablet().MotionEvent) {
+ if (xe->type == m_xtablet.MotionEvent) {
XDeviceMotionEvent *data = (XDeviceMotionEvent *)xe;
/* stroke might begin without leading ProxyIn event,
* this happens when window is opened when stylus is already hovering
* around tablet surface */
- setTabletMode(window, data->deviceid);
+ setTabletMode(this, window, data->deviceid);
- window->GetXTablet().CommonData.Pressure =
- data->axis_data[2] / ((float)window->GetXTablet().PressureLevels);
+ window->GetTabletData()->Pressure =
+ data->axis_data[2] / ((float)m_xtablet.PressureLevels);
/* the (short) cast and the &0xffff is bizarre and unexplained anywhere,
* but I got garbage data without it. Found it in the xidump.c source --matt */
- window->GetXTablet().CommonData.Xtilt =
- (short)(data->axis_data[3] & 0xffff) / ((float)window->GetXTablet().XtiltLevels);
- window->GetXTablet().CommonData.Ytilt =
- (short)(data->axis_data[4] & 0xffff) / ((float)window->GetXTablet().YtiltLevels);
+ window->GetTabletData()->Xtilt =
+ (short)(data->axis_data[3] & 0xffff) / ((float)m_xtablet.XtiltLevels);
+ window->GetTabletData()->Ytilt =
+ (short)(data->axis_data[4] & 0xffff) / ((float)m_xtablet.YtiltLevels);
}
- else if (xe->type == window->GetXTablet().ProxInEvent) {
+ else if (xe->type == m_xtablet.ProxInEvent) {
XProximityNotifyEvent *data = (XProximityNotifyEvent *)xe;
- setTabletMode(window, data->deviceid);
+ setTabletMode(this, window, data->deviceid);
}
- else if (xe->type == window->GetXTablet().ProxOutEvent) {
- window->GetXTablet().CommonData.Active = GHOST_kTabletModeNone;
+ else if (xe->type == m_xtablet.ProxOutEvent) {
+ window->GetTabletData()->Active = GHOST_kTabletModeNone;
}
#endif // WITH_X11_XINPUT
break;
@@ -1648,3 +1726,197 @@ GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType,
);
}
#endif
+
+#ifdef WITH_X11_XINPUT
+/*
+ * Dummy function to get around IO Handler exiting if device invalid
+ * Basically it will not crash blender now if you have a X device that
+ * is configured but not plugged in.
+ */
+int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent)
+{
+ fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n",
+ theEvent->error_code, theEvent->request_code);
+
+ /* No exit! - but keep lint happy */
+ return 0;
+}
+
+int GHOST_X11_ApplicationIOErrorHandler(Display *display)
+{
+ fprintf(stderr, "Ignoring Xlib error: error IO\n");
+
+ /* No exit! - but keep lint happy */
+ return 0;
+}
+
+/* These C functions are copied from Wine 1.1.13's wintab.c */
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+
+static bool match_token(const char *haystack, const char *needle)
+{
+ const char *p, *q;
+ for (p = haystack; *p; )
+ {
+ while (*p && isspace(*p))
+ p++;
+ if (!*p)
+ break;
+
+ for (q = needle; *q && *p && tolower(*p) == tolower(*q); q++)
+ p++;
+ if (!*q && (isspace(*p) || !*p))
+ return TRUE;
+
+ while (*p && !isspace(*p))
+ p++;
+ }
+ return FALSE;
+}
+
+
+/* Determining if an X device is a Tablet style device is an imperfect science.
+ * We rely on common conventions around device names as well as the type reported
+ * by Wacom tablets. This code will likely need to be expanded for alternate tablet types
+ *
+ * Wintab refers to any device that interacts with the tablet as a cursor,
+ * (stylus, eraser, tablet mouse, airbrush, etc)
+ * this is not to be confused with wacom x11 configuration "cursor" device.
+ * Wacoms x11 config "cursor" refers to its device slot (which we mirror with
+ * our gSysCursors) for puck like devices (tablet mice essentially).
+ */
+#if 0 // unused
+static BOOL is_tablet_cursor(const char *name, const char *type)
+{
+ int i;
+ static const char *tablet_cursor_whitelist[] = {
+ "wacom",
+ "wizardpen",
+ "acecad",
+ "tablet",
+ "cursor",
+ "stylus",
+ "eraser",
+ "pad",
+ NULL
+ };
+
+ for (i = 0; tablet_cursor_whitelist[i] != NULL; i++) {
+ if (name && match_token(name, tablet_cursor_whitelist[i]))
+ return TRUE;
+ if (type && match_token(type, tablet_cursor_whitelist[i]))
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+static BOOL is_stylus(const char *name, const char *type)
+{
+ int i;
+ static const char *tablet_stylus_whitelist[] = {
+ "stylus",
+ "wizardpen",
+ "acecad",
+ NULL
+ };
+
+ for (i = 0; tablet_stylus_whitelist[i] != NULL; i++) {
+ if (name && match_token(name, tablet_stylus_whitelist[i]))
+ return TRUE;
+ if (type && match_token(type, tablet_stylus_whitelist[i]))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static BOOL is_eraser(const char *name, const char *type)
+{
+ if (name && match_token(name, "eraser"))
+ return TRUE;
+ if (type && match_token(type, "eraser"))
+ return TRUE;
+ return FALSE;
+}
+#undef BOOL
+#undef TRUE
+#undef FALSE
+/* end code copied from wine */
+
+void GHOST_SystemX11::initXInputDevices()
+{
+ static XErrorHandler old_handler = (XErrorHandler) 0;
+ static XIOErrorHandler old_handler_io = (XIOErrorHandler) 0;
+
+ XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
+
+ if (version && (version != (XExtensionVersion *)NoSuchExtension)) {
+ if (version->present) {
+ int device_count;
+ XDeviceInfo *device_info = XListInputDevices(m_display, &device_count);
+ m_xtablet.StylusDevice = NULL;
+ m_xtablet.EraserDevice = NULL;
+
+ /* Install our error handler to override Xlib's termination behavior */
+ old_handler = XSetErrorHandler(GHOST_X11_ApplicationErrorHandler);
+ old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler);
+
+ for (int i = 0; i < device_count; ++i) {
+ char *device_type = device_info[i].type ? XGetAtomName(m_display, device_info[i].type) : NULL;
+
+// printf("Tablet type:'%s', name:'%s', index:%d\n", device_type, device_info[i].name, i);
+
+
+ if (m_xtablet.StylusDevice == NULL && is_stylus(device_info[i].name, device_type)) {
+// printf("\tfound stylus\n");
+ m_xtablet.StylusID = device_info[i].id;
+ m_xtablet.StylusDevice = XOpenDevice(m_display, m_xtablet.StylusID);
+
+ if (m_xtablet.StylusDevice != NULL) {
+ /* Find how many pressure levels tablet has */
+ XAnyClassPtr ici = device_info[i].inputclassinfo;
+ for (int j = 0; j < m_xtablet.StylusDevice->num_classes; ++j) {
+ if (ici->c_class == ValuatorClass) {
+// printf("\t\tfound ValuatorClass\n");
+ XValuatorInfo *xvi = (XValuatorInfo *)ici;
+ m_xtablet.PressureLevels = xvi->axes[2].max_value;
+
+ /* this is assuming that the tablet has the same tilt resolution in both
+ * positive and negative directions. It would be rather weird if it didn't.. */
+ m_xtablet.XtiltLevels = xvi->axes[3].max_value;
+ m_xtablet.YtiltLevels = xvi->axes[4].max_value;
+ break;
+ }
+
+ ici = (XAnyClassPtr)(((char *)ici) + ici->length);
+ }
+ }
+ else {
+ m_xtablet.StylusID = 0;
+ }
+ }
+ else if (m_xtablet.EraserDevice == NULL && is_eraser(device_info[i].name, device_type)) {
+// printf("\tfound eraser\n");
+ m_xtablet.EraserID = device_info[i].id;
+ m_xtablet.EraserDevice = XOpenDevice(m_display, m_xtablet.EraserID);
+ if (m_xtablet.EraserDevice == NULL) m_xtablet.EraserID = 0;
+ }
+
+ if (device_type) {
+ XFree((void *)device_type);
+ }
+ }
+
+ /* Restore handler */
+ (void) XSetErrorHandler(old_handler);
+ (void) XSetIOErrorHandler(old_handler_io);
+
+ XFreeDeviceList(device_info);
+ }
+ XFree(version);
+ }
+}
+
+#endif /* WITH_X11_XINPUT */
diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index 02c0109085a..a5d5d9b7a99 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -39,11 +39,19 @@
#include "GHOST_System.h"
#include "../GHOST_Types.h"
+// For tablets
+#ifdef WITH_X11_XINPUT
+# include <X11/extensions/XInput.h>
+#endif
+
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
# define GHOST_X11_RES_NAME "Blender" /* res_name */
# define GHOST_X11_RES_CLASS "Blender" /* res_class */
#endif
+/* generic error handlers */
+int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent);
+int GHOST_X11_ApplicationIOErrorHandler(Display *display);
class GHOST_WindowX11;
@@ -284,6 +292,27 @@ public:
Atom m_incr;
Atom m_utf8_string;
+#ifdef WITH_X11_XINPUT
+ typedef struct GHOST_TabletX11 {
+ XDevice *StylusDevice;
+ XDevice *EraserDevice;
+
+ XID StylusID, EraserID;
+
+ int MotionEvent;
+ int ProxInEvent;
+ int ProxOutEvent;
+
+ int PressureLevels;
+ int XtiltLevels, YtiltLevels;
+ } GHOST_TabletX11;
+
+ GHOST_TabletX11 &GetXTablet()
+ {
+ return m_xtablet;
+ }
+#endif // WITH_X11_XINPUT
+
private:
Display *m_display;
@@ -291,6 +320,11 @@ private:
XIM m_xim;
#endif
+#ifdef WITH_X11_XINPUT
+ /* Tablet devices */
+ GHOST_TabletX11 m_xtablet;
+#endif
+
/// The vector of windows that need to be updated.
std::vector<GHOST_WindowX11 *> m_dirty_windows;
@@ -313,6 +347,10 @@ private:
bool openX11_IM();
#endif
+#ifdef WITH_X11_XINPUT
+ void initXInputDevices();
+#endif
+
GHOST_WindowX11 *
findGhostWindow(
Window xwind
diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp
index fd3ff4f85f0..ca12abe7324 100644
--- a/intern/ghost/intern/GHOST_Window.cpp
+++ b/intern/ghost/intern/GHOST_Window.cpp
@@ -61,6 +61,8 @@ GHOST_Window::GHOST_Window(
m_cursorGrabAccumPos[0] = 0;
m_cursorGrabAccumPos[1] = 0;
+
+ m_nativePixelSize = 1.0f;
m_fullScreen = state == GHOST_kWindowStateFullScreen;
if (m_fullScreen) {
@@ -194,3 +196,4 @@ bool GHOST_Window::getModifiedState()
{
return m_isUnsavedChanges;
}
+
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index fd870327fd4..f7c67bf7be6 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -257,6 +257,13 @@ public:
{
m_userData = userData;
}
+
+ virtual float getNativePixelSize(void)
+ {
+ if (m_nativePixelSize > 0.0f)
+ return m_nativePixelSize;
+ return 1.0f;
+ }
protected:
/**
@@ -351,6 +358,9 @@ protected:
GHOST_TUns32 m_fullScreenWidth;
/** Full-screen height */
GHOST_TUns32 m_fullScreenHeight;
+
+ /* OSX only, retina screens */
+ float m_nativePixelSize;
};
diff --git a/intern/ghost/intern/GHOST_WindowCarbon.cpp b/intern/ghost/intern/GHOST_WindowCarbon.cpp
index 99d8854667e..36d45b4790c 100644
--- a/intern/ghost/intern/GHOST_WindowCarbon.cpp
+++ b/intern/ghost/intern/GHOST_WindowCarbon.cpp
@@ -182,7 +182,8 @@ GHOST_WindowCarbon::GHOST_WindowCarbon(
(SInt32) this); // Store a pointer to the class in the refCon
#endif
//GHOST_PRINT("GHOST_WindowCarbon::GHOST_WindowCarbon(): creating full-screen OpenGL context\n");
- setDrawingContextType(GHOST_kDrawingContextTypeOpenGL);; installDrawingContext(GHOST_kDrawingContextTypeOpenGL);
+ setDrawingContextType(GHOST_kDrawingContextTypeOpenGL);
+ installDrawingContext(GHOST_kDrawingContextTypeOpenGL);
updateDrawingContext();
activateDrawingContext();
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h
index 3e5c675d4a7..f1388c0b466 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowCocoa.h
@@ -262,6 +262,11 @@ public:
* Hides the progress bar icon
*/
virtual GHOST_TSuccess endProgressBar();
+
+
+ virtual void setNativePixelSize(void);
+
+
protected:
/**
* Tries to install a rendering context in this window.
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index e89dd1b41dc..ccd6cd93d4c 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -74,8 +74,10 @@ extern "C" {
- (void)windowDidMove:(NSNotification *)notification;
- (void)windowWillMove:(NSNotification *)notification;
- (BOOL)windowShouldClose:(id)sender;
+- (void)windowDidChangeBackingProperties:(NSNotification *)notification;
@end
+
@implementation CocoaWindowDelegate : NSObject
- (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa
{
@@ -128,6 +130,11 @@ extern "C" {
}*/
}
+- (void)windowDidChangeBackingProperties:(NSNotification *)notification
+{
+ systemCocoa->handleWindowEvent(GHOST_kEventNativeResolutionChange, associatedWindow);
+}
+
- (BOOL)windowShouldClose:(id)sender;
{
//Let Blender close the window rather than closing immediately
@@ -481,8 +488,8 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
[m_window setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
//Forbid to resize the window below the blender defined minimum one
- minSize.width = 640;
- minSize.height = 480;
+ minSize.width = 320;
+ minSize.height = 240;
[m_window setContentMinSize:minSize];
setTitle(title);
@@ -593,7 +600,7 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
[m_openGLView setWantsBestResolutionOpenGLSurface:YES];
NSRect backingBounds = [m_openGLView convertRectToBacking:[m_openGLView bounds]];
- m_systemCocoa->m_nativePixelSize = (float)backingBounds.size.width / (float)rect.size.width;
+ m_nativePixelSize = (float)backingBounds.size.width / (float)rect.size.width;
}
}
@@ -911,6 +918,19 @@ NSScreen* GHOST_WindowCocoa::getScreen()
return [m_window screen];
}
+/* called for event, when window leaves monitor to another */
+void GHOST_WindowCocoa::setNativePixelSize(void)
+{
+ /* make sure 10.6 keeps running */
+ if ([m_openGLView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) {
+ NSRect backingBounds = [m_openGLView convertRectToBacking:[m_openGLView bounds]];
+
+ GHOST_Rect rect;
+ getClientBounds(rect);
+
+ m_nativePixelSize = (float)backingBounds.size.width / (float)rect.getWidth();
+ }
+}
/**
* \note Fullscreen switch is not actual fullscreen with display capture.
@@ -1029,7 +1049,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
[tmpWindow registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
NSStringPboardType, NSTIFFPboardType, nil]];
//Forbid to resize the window below the blender defined minimum one
- [tmpWindow setContentMinSize:NSMakeSize(640, 480)];
+ [tmpWindow setContentMinSize:NSMakeSize(320, 240)];
//Assign the openGL view to the new window
[tmpWindow setContentView:m_openGLView];
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index 3440e3ce15a..2e9ac94b9c7 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -186,11 +186,6 @@ GHOST_WindowX11(
int natom;
int glxVersionMajor, glxVersionMinor; /* As in GLX major.minor */
-#ifdef WITH_X11_XINPUT
- /* initialize incase X11 fails to load */
- memset(&m_xtablet, 0, sizeof(m_xtablet));
-#endif
-
m_visual = NULL;
if (!glXQueryVersion(m_display, &glxVersionMajor, &glxVersionMinor)) {
@@ -363,8 +358,8 @@ GHOST_WindowX11(
xsizehints->y = top;
xsizehints->width = width;
xsizehints->height = height;
- xsizehints->min_width = 640; /* size hints, could be made apart of the ghost api */
- xsizehints->min_height = 480; /* limits are also arbitrary, but should not allow 1x1 window */
+ xsizehints->min_width = 320; /* size hints, could be made apart of the ghost api */
+ xsizehints->min_height = 240; /* limits are also arbitrary, but should not allow 1x1 window */
xsizehints->max_width = 65535;
xsizehints->max_height = 65535;
XSetWMNormalHints(m_display, m_window, xsizehints);
@@ -461,6 +456,8 @@ GHOST_WindowX11(
#ifdef WITH_X11_XINPUT
initXInputDevices();
+
+ m_tabletData.Active = GHOST_kTabletModeNone;
#endif
/* now set up the rendering context. */
@@ -517,200 +514,30 @@ bool GHOST_WindowX11::createX11_XIC()
#endif
#ifdef WITH_X11_XINPUT
-/*
- * Dummy function to get around IO Handler exiting if device invalid
- * Basically it will not crash blender now if you have a X device that
- * is configured but not plugged in.
- */
-static int ApplicationErrorHandler(Display *display, XErrorEvent *theEvent)
-{
- fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n",
- theEvent->error_code, theEvent->request_code);
-
- /* No exit! - but keep lint happy */
- return 0;
-}
-
-/* These C functions are copied from Wine 1.1.13's wintab.c */
-#define BOOL int
-#define TRUE 1
-#define FALSE 0
-
-static bool match_token(const char *haystack, const char *needle)
-{
- const char *p, *q;
- for (p = haystack; *p; )
- {
- while (*p && isspace(*p))
- p++;
- if (!*p)
- break;
-
- for (q = needle; *q && *p && tolower(*p) == tolower(*q); q++)
- p++;
- if (!*q && (isspace(*p) || !*p))
- return TRUE;
-
- while (*p && !isspace(*p))
- p++;
- }
- return FALSE;
-}
-
-
-/* Determining if an X device is a Tablet style device is an imperfect science.
- * We rely on common conventions around device names as well as the type reported
- * by Wacom tablets. This code will likely need to be expanded for alternate tablet types
- *
- * Wintab refers to any device that interacts with the tablet as a cursor,
- * (stylus, eraser, tablet mouse, airbrush, etc)
- * this is not to be confused with wacom x11 configuration "cursor" device.
- * Wacoms x11 config "cursor" refers to its device slot (which we mirror with
- * our gSysCursors) for puck like devices (tablet mice essentially).
- */
-#if 0 // unused
-static BOOL is_tablet_cursor(const char *name, const char *type)
-{
- int i;
- static const char *tablet_cursor_whitelist[] = {
- "wacom",
- "wizardpen",
- "acecad",
- "tablet",
- "cursor",
- "stylus",
- "eraser",
- "pad",
- NULL
- };
-
- for (i = 0; tablet_cursor_whitelist[i] != NULL; i++) {
- if (name && match_token(name, tablet_cursor_whitelist[i]))
- return TRUE;
- if (type && match_token(type, tablet_cursor_whitelist[i]))
- return TRUE;
- }
- return FALSE;
-}
-#endif
-static BOOL is_stylus(const char *name, const char *type)
-{
- int i;
- static const char *tablet_stylus_whitelist[] = {
- "stylus",
- "wizardpen",
- "acecad",
- NULL
- };
-
- for (i = 0; tablet_stylus_whitelist[i] != NULL; i++) {
- if (name && match_token(name, tablet_stylus_whitelist[i]))
- return TRUE;
- if (type && match_token(type, tablet_stylus_whitelist[i]))
- return TRUE;
- }
-
- return FALSE;
-}
-
-static BOOL is_eraser(const char *name, const char *type)
-{
- if (name && match_token(name, "eraser"))
- return TRUE;
- if (type && match_token(type, "eraser"))
- return TRUE;
- return FALSE;
-}
-#undef BOOL
-#undef TRUE
-#undef FALSE
-/* end code copied from wine */
-
void GHOST_WindowX11::initXInputDevices()
{
- static XErrorHandler old_handler = (XErrorHandler) 0;
XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
if (version && (version != (XExtensionVersion *)NoSuchExtension)) {
if (version->present) {
- int device_count;
- XDeviceInfo *device_info = XListInputDevices(m_display, &device_count);
- m_xtablet.StylusDevice = NULL;
- m_xtablet.EraserDevice = NULL;
- m_xtablet.CommonData.Active = GHOST_kTabletModeNone;
-
- /* Install our error handler to override Xlib's termination behavior */
- old_handler = XSetErrorHandler(ApplicationErrorHandler);
-
- for (int i = 0; i < device_count; ++i) {
- char *device_type = device_info[i].type ? XGetAtomName(m_display, device_info[i].type) : NULL;
-
-// printf("Tablet type:'%s', name:'%s', index:%d\n", device_type, device_info[i].name, i);
-
-
- if (m_xtablet.StylusDevice == NULL && is_stylus(device_info[i].name, device_type)) {
-// printf("\tfound stylus\n");
- m_xtablet.StylusID = device_info[i].id;
- m_xtablet.StylusDevice = XOpenDevice(m_display, m_xtablet.StylusID);
-
- if (m_xtablet.StylusDevice != NULL) {
- /* Find how many pressure levels tablet has */
- XAnyClassPtr ici = device_info[i].inputclassinfo;
- for (int j = 0; j < m_xtablet.StylusDevice->num_classes; ++j) {
- if (ici->c_class == ValuatorClass) {
-// printf("\t\tfound ValuatorClass\n");
- XValuatorInfo *xvi = (XValuatorInfo *)ici;
- m_xtablet.PressureLevels = xvi->axes[2].max_value;
-
- /* this is assuming that the tablet has the same tilt resolution in both
- * positive and negative directions. It would be rather weird if it didn't.. */
- m_xtablet.XtiltLevels = xvi->axes[3].max_value;
- m_xtablet.YtiltLevels = xvi->axes[4].max_value;
- break;
- }
-
- ici = (XAnyClassPtr)(((char *)ici) + ici->length);
- }
- }
- else {
- m_xtablet.StylusID = 0;
- }
- }
- else if (m_xtablet.EraserDevice == NULL && is_eraser(device_info[i].name, device_type)) {
-// printf("\tfound eraser\n");
- m_xtablet.EraserID = device_info[i].id;
- m_xtablet.EraserDevice = XOpenDevice(m_display, m_xtablet.EraserID);
- if (m_xtablet.EraserDevice == NULL) m_xtablet.EraserID = 0;
- }
-
- if (device_type) {
- XFree((void *)device_type);
- }
- }
-
- /* Restore handler */
- (void) XSetErrorHandler(old_handler);
-
- XFreeDeviceList(device_info);
-
-
+ GHOST_SystemX11::GHOST_TabletX11 &xtablet = m_system->GetXTablet();
XEventClass xevents[10], ev;
int dcount = 0;
- if (m_xtablet.StylusDevice) {
- DeviceMotionNotify(m_xtablet.StylusDevice, m_xtablet.MotionEvent, ev);
+ if (xtablet.StylusDevice) {
+ DeviceMotionNotify(xtablet.StylusDevice, xtablet.MotionEvent, ev);
if (ev) xevents[dcount++] = ev;
- ProximityIn(m_xtablet.StylusDevice, m_xtablet.ProxInEvent, ev);
+ ProximityIn(xtablet.StylusDevice, xtablet.ProxInEvent, ev);
if (ev) xevents[dcount++] = ev;
- ProximityOut(m_xtablet.StylusDevice, m_xtablet.ProxOutEvent, ev);
+ ProximityOut(xtablet.StylusDevice, xtablet.ProxOutEvent, ev);
if (ev) xevents[dcount++] = ev;
}
- if (m_xtablet.EraserDevice) {
- DeviceMotionNotify(m_xtablet.EraserDevice, m_xtablet.MotionEvent, ev);
+ if (xtablet.EraserDevice) {
+ DeviceMotionNotify(xtablet.EraserDevice, xtablet.MotionEvent, ev);
if (ev) xevents[dcount++] = ev;
- ProximityIn(m_xtablet.EraserDevice, m_xtablet.ProxInEvent, ev);
+ ProximityIn(xtablet.EraserDevice, xtablet.ProxInEvent, ev);
if (ev) xevents[dcount++] = ev;
- ProximityOut(m_xtablet.EraserDevice, m_xtablet.ProxOutEvent, ev);
+ ProximityOut(xtablet.EraserDevice, xtablet.ProxOutEvent, ev);
if (ev) xevents[dcount++] = ev;
}
@@ -1341,15 +1168,6 @@ GHOST_WindowX11::
XFreeCursor(m_display, m_custom_cursor);
}
-#ifdef WITH_X11_XINPUT
- /* close tablet devices */
- if (m_xtablet.StylusDevice)
- XCloseDevice(m_display, m_xtablet.StylusDevice);
-
- if (m_xtablet.EraserDevice)
- XCloseDevice(m_display, m_xtablet.EraserDevice);
-#endif /* WITH_X11_XINPUT */
-
if (m_context != s_firstContext) {
glXDestroyContext(m_display, m_context);
}
@@ -1392,6 +1210,15 @@ installDrawingContext(
GHOST_TSuccess success;
switch (type) {
case GHOST_kDrawingContextTypeOpenGL:
+ {
+#ifdef WITH_X11_XINPUT
+ /* use our own event handlers to avoid exiting blender,
+ * this would happen for eg:
+ * if you open blender, unplug a tablet, then open a new window. */
+ XErrorHandler old_handler = XSetErrorHandler(GHOST_X11_ApplicationErrorHandler);
+ XIOErrorHandler old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler);
+#endif
+
m_context = glXCreateContext(m_display, m_visual, s_firstContext, True);
if (m_context != NULL) {
if (!s_firstContext) {
@@ -1406,12 +1233,18 @@ installDrawingContext(
success = GHOST_kFailure;
}
+#ifdef WITH_X11_XINPUT
+ /* Restore handler */
+ (void) XSetErrorHandler(old_handler);
+ (void) XSetIOErrorHandler(old_handler_io);
+#endif
break;
-
+ }
case GHOST_kDrawingContextTypeNone:
+ {
success = GHOST_kSuccess;
break;
-
+ }
default:
success = GHOST_kFailure;
}
diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h
index 5b2ffced29c..10d44987647 100644
--- a/intern/ghost/intern/GHOST_WindowX11.h
+++ b/intern/ghost/intern/GHOST_WindowX11.h
@@ -196,32 +196,9 @@ public:
getXWindow(
);
#ifdef WITH_X11_XINPUT
- class XTablet
+ GHOST_TabletData *GetTabletData()
{
-public:
- GHOST_TabletData CommonData;
-
- XDevice *StylusDevice;
- XDevice *EraserDevice;
-
- XID StylusID, EraserID;
-
- int MotionEvent;
- int ProxInEvent;
- int ProxOutEvent;
-
- int PressureLevels;
- int XtiltLevels, YtiltLevels;
- };
-
- XTablet& GetXTablet()
- {
- return m_xtablet;
- }
-
- const GHOST_TabletData *GetTabletData()
- {
- return &m_xtablet.CommonData;
+ return &m_tabletData;
}
#else // WITH_X11_XINPUT
const GHOST_TabletData *GetTabletData()
@@ -387,8 +364,7 @@ private:
#endif
#ifdef WITH_X11_XINPUT
- /* Tablet devices */
- XTablet m_xtablet;
+ GHOST_TabletData m_tabletData;
#endif
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c
index 11fa477c2a4..559d1138ffb 100644
--- a/intern/guardedalloc/intern/mallocn.c
+++ b/intern/guardedalloc/intern/mallocn.c
@@ -68,6 +68,17 @@
//#define DEBUG_MEMCOUNTER
+/* Only for debugging:
+ * defining DEBUG_THREADS will enable check whether memory manager
+ * is locked with a mutex when allocation is called from non-main
+ * thread.
+ *
+ * This helps troubleshooting memory issues caused by the fact
+ * guarded allocator is not thread-safe, however this check will
+ * fail to check allocations from openmp threads.
+ */
+//#define DEBUG_THREADS
+
#ifdef DEBUG_MEMCOUNTER
/* set this to the value that isn't being freed */
# define DEBUG_MEMCOUNTER_ERROR_VAL 0
@@ -122,6 +133,12 @@ typedef struct MemHead {
#endif
#endif
+#ifdef DEBUG_THREADS
+# include <assert.h>
+# include <pthread.h>
+static pthread_t mainid;
+#endif
+
typedef struct MemTail {
int tag3, pad;
} MemTail;
@@ -206,6 +223,20 @@ static void print_error(const char *str, ...)
static void mem_lock_thread(void)
{
+#ifdef DEBUG_THREADS
+ static int initialized = 0;
+
+ if (initialized == 0) {
+ /* assume first allocation happens from main thread */
+ mainid = pthread_self();
+ initialized = 1;
+ }
+
+ if (!pthread_equal(pthread_self(), mainid) && thread_lock_callback == NULL) {
+ assert(!"Memory function is called from non-main thread without lock");
+ }
+#endif
+
#ifdef DEBUG_OMP_MALLOC
assert(omp_in_parallel() == 0);
#endif
diff --git a/intern/locale/boost_locale_wrapper.cpp b/intern/locale/boost_locale_wrapper.cpp
index 80e75298d70..ebd2dd652c7 100644
--- a/intern/locale/boost_locale_wrapper.cpp
+++ b/intern/locale/boost_locale_wrapper.cpp
@@ -33,6 +33,7 @@
static std::string messages_path;
static std::string default_domain;
+static std::string locale_str;
void bl_locale_init(const char *_messages_path, const char *_default_domain)
{
@@ -52,6 +53,7 @@ void bl_locale_init(const char *_messages_path, const char *_default_domain)
void bl_locale_set(const char *locale)
{
boost::locale::generator gen;
+ std::locale _locale;
// Specify location of dictionaries.
gen.add_messages_path(messages_path);
gen.add_messages_domain(default_domain);
@@ -59,7 +61,8 @@ void bl_locale_set(const char *locale)
try {
if (locale && locale[0]) {
- std::locale::global(gen(locale));
+ _locale = gen(locale);
+ std::locale::global(_locale);
}
else {
#ifdef __APPLE__
@@ -85,9 +88,11 @@ void bl_locale_set(const char *locale)
if (locale_osx == "")
fprintf(stderr, "Locale set: failed to read AppleLocale read from defaults\n");
- std::locale::global(gen(locale_osx.c_str()));
+ _locale = gen(locale_osx.c_str());
+ std::locale::global(_locale);
#else
- std::locale::global(gen(""));
+ _locale = gen("");
+ std::locale::global(_locale);
#endif
}
// Note: boost always uses "C" LC_NUMERIC by default!
@@ -95,6 +100,22 @@ void bl_locale_set(const char *locale)
catch(std::exception const &e) {
std::cout << "bl_locale_set(" << locale << "): " << e.what() << " \n";
}
+
+ /* Generate the locale string (useful to know which locale we are actually using in case of "default" one). */
+#define LOCALE_INFO std::use_facet<boost::locale::info>(_locale)
+
+ locale_str = LOCALE_INFO.language();
+ if (LOCALE_INFO.country() != "") {
+ locale_str += "_" + LOCALE_INFO.country();
+ }
+ if (LOCALE_INFO.variant() != "") {
+ locale_str += "@" + LOCALE_INFO.variant();
+ }
+}
+
+const char *bl_locale_get(void)
+{
+ return locale_str.c_str();
}
const char *bl_locale_pgettext(const char *msgctxt, const char *msgid)
@@ -115,5 +136,4 @@ const char *bl_locale_pgettext(const char *msgctxt, const char *msgid)
// std::cout << "bl_locale_pgettext(" << msgctxt << ", " << msgid << "): " << e.what() << " \n";
return msgid;
}
-}
-
+} \ No newline at end of file
diff --git a/intern/locale/boost_locale_wrapper.h b/intern/locale/boost_locale_wrapper.h
index e7956d216f1..4e3a1f848d2 100644
--- a/intern/locale/boost_locale_wrapper.h
+++ b/intern/locale/boost_locale_wrapper.h
@@ -40,7 +40,8 @@ extern "C" {
void bl_locale_init(const char *messages_path, const char *default_domain);
void bl_locale_set(const char *locale);
-const char* bl_locale_pgettext(const char *msgctxt, const char *msgid);
+const char *bl_locale_get(void);
+const char *bl_locale_pgettext(const char *msgctxt, const char *msgid);
#ifdef __cplusplus
}