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-06 02:24:05 +0400
committerTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2013-01-06 02:24:05 +0400
commitfeccbaabbd39c18b2f552964ebd8dfab4eeaed89 (patch)
tree0069f654883a7a02dd320649ce61bd7933748111 /intern
parenta22096e8019c461128a0907e4026859996ec1b5c (diff)
parent37ba969c74840142682cf22f34610f3b65b86cf4 (diff)
Merged changes in the trunk up to revision 53584.
Conflicts resolved: release/scripts/startup/bl_ui/properties_render.py source/blender/blenloader/intern/readfile.c source/blender/editors/interface/interface_templates.c source/blender/makesrna/RNA_enum_types.h Also made additional code updates for: r53355 UIList - Python-extendable list of UI items r53460 Alpha premul pipeline cleanup
Diffstat (limited to 'intern')
-rw-r--r--intern/cycles/blender/CMakeLists.txt1
-rw-r--r--intern/cycles/blender/addon/__init__.py2
-rw-r--r--intern/cycles/blender/addon/properties.py189
-rw-r--r--intern/cycles/blender/addon/ui.py89
-rw-r--r--intern/cycles/blender/blender_curves.cpp1130
-rw-r--r--intern/cycles/blender/blender_mesh.cpp59
-rw-r--r--intern/cycles/blender/blender_object.cpp26
-rw-r--r--intern/cycles/blender/blender_session.cpp18
-rw-r--r--intern/cycles/blender/blender_shader.cpp4
-rw-r--r--intern/cycles/blender/blender_sync.cpp5
-rw-r--r--intern/cycles/blender/blender_sync.h9
-rw-r--r--intern/cycles/blender/blender_util.h14
-rw-r--r--intern/cycles/bvh/bvh.cpp133
-rw-r--r--intern/cycles/bvh/bvh.h9
-rw-r--r--intern/cycles/bvh/bvh_build.cpp55
-rw-r--r--intern/cycles/bvh/bvh_build.h2
-rw-r--r--intern/cycles/bvh/bvh_params.h5
-rw-r--r--intern/cycles/bvh/bvh_sort.cpp2
-rw-r--r--intern/cycles/bvh/bvh_split.cpp55
-rw-r--r--intern/cycles/device/device.h1
-rw-r--r--intern/cycles/device/device_cuda.cpp40
-rw-r--r--intern/cycles/kernel/CMakeLists.txt3
-rw-r--r--intern/cycles/kernel/kernel_attribute.h50
-rw-r--r--intern/cycles/kernel/kernel_bvh.h272
-rw-r--r--intern/cycles/kernel/kernel_curve.h141
-rw-r--r--intern/cycles/kernel/kernel_emission.h12
-rw-r--r--intern/cycles/kernel/kernel_light.h66
-rw-r--r--intern/cycles/kernel/kernel_passes.h4
-rw-r--r--intern/cycles/kernel/kernel_path.h5
-rw-r--r--intern/cycles/kernel/kernel_primitive.h185
-rw-r--r--intern/cycles/kernel/kernel_shader.h114
-rw-r--r--intern/cycles/kernel/kernel_textures.h5
-rw-r--r--intern/cycles/kernel/kernel_triangle.h77
-rw-r--r--intern/cycles/kernel/kernel_types.h64
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp50
-rw-r--r--intern/cycles/kernel/osl/osl_services.h3
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp11
-rw-r--r--intern/cycles/kernel/osl/osl_shader.h2
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/shaders/node_hair_info.osl (renamed from intern/cycles/util/util_attribute.h)25
-rw-r--r--intern/cycles/kernel/shaders/stdosl.h15
-rw-r--r--intern/cycles/kernel/svm/svm.h6
-rw-r--r--intern/cycles/kernel/svm/svm_attribute.h35
-rw-r--r--intern/cycles/kernel/svm/svm_geometry.h49
-rw-r--r--intern/cycles/kernel/svm/svm_tex_coord.h19
-rw-r--r--intern/cycles/kernel/svm/svm_types.h10
-rw-r--r--intern/cycles/render/CMakeLists.txt2
-rw-r--r--intern/cycles/render/attribute.cpp205
-rw-r--r--intern/cycles/render/attribute.h46
-rw-r--r--intern/cycles/render/curves.cpp160
-rw-r--r--intern/cycles/render/curves.h134
-rw-r--r--intern/cycles/render/light.cpp48
-rw-r--r--intern/cycles/render/mesh.cpp391
-rw-r--r--intern/cycles/render/mesh.h27
-rw-r--r--intern/cycles/render/mesh_displace.cpp28
-rw-r--r--intern/cycles/render/nodes.cpp57
-rw-r--r--intern/cycles/render/nodes.h7
-rw-r--r--intern/cycles/render/object.cpp46
-rw-r--r--intern/cycles/render/object.h1
-rw-r--r--intern/cycles/render/scene.cpp12
-rw-r--r--intern/cycles/render/scene.h7
-rw-r--r--intern/cycles/render/session.cpp8
-rw-r--r--intern/cycles/subd/subd_dice.cpp2
-rw-r--r--intern/cycles/util/CMakeLists.txt2
-rw-r--r--intern/cycles/util/util_attribute.cpp51
-rw-r--r--intern/cycles/util/util_boundbox.h7
-rw-r--r--intern/cycles/util/util_types.h18
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm26
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm5
-rw-r--r--intern/locale/boost_locale_wrapper.cpp59
-rw-r--r--intern/smoke/CMakeLists.txt2
71 files changed, 3771 insertions, 652 deletions
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt
index 88363758364..710e8ba6a90 100644
--- a/intern/cycles/blender/CMakeLists.txt
+++ b/intern/cycles/blender/CMakeLists.txt
@@ -24,6 +24,7 @@ set(SRC
blender_mesh.cpp
blender_object.cpp
blender_particles.cpp
+ blender_curves.cpp
blender_python.cpp
blender_session.cpp
blender_shader.cpp
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index 6d1b6d4f56e..dddf7bafb14 100644
--- a/intern/cycles/blender/addon/__init__.py
+++ b/intern/cycles/blender/addon/__init__.py
@@ -21,7 +21,7 @@
bl_info = {
"name": "Cycles Render Engine",
"author": "",
- "blender": (2, 6, 5),
+ "blender": (2, 60, 5),
"location": "Info header, render engine menu",
"description": "Cycles Render Engine integration",
"warning": "",
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 26fc7a81936..2bc4afe969e 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -64,6 +64,38 @@ enum_panorama_types = (
"Similar to most fisheye modern lens, takes sensor dimensions into consideration"),
)
+enum_curve_presets = (
+ ('CUSTOM', "Custom", "Set general parameters"),
+ ('TANGENT_SHADING', "Tangent Normal", "Use planar geometry and tangent normals"),
+ ('TRUE_NORMAL', "True Normal", "Use true normals (good for thin strands)"),
+ ('ACCURATE_PRESET', "Accurate", "Use best settings (suitable for glass materials)"),
+ )
+
+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)"),
+ )
+
+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"),
+ )
+
+enum_line_curves = (
+ ('ACCURATE', "Accurate", "Always take into consideration strand width for intersections"),
+ ('QT_CORRECTED', "Corrected", "Ignore width for initial intersection and correct later"),
+ ('ENDCORRECTED', "Correct found", "Ignore width for all intersections and only correct closest"),
+ ('QT_UNCORRECTED', "Uncorrected", "Calculate intersections without considering width"),
+ )
+
+enum_curves_interpolation = (
+ ('LINEAR', "Linear interpolation", "Use Linear interpolation between segments"),
+ ('CARDINAL', "Cardinal interpolation", "Use cardinal interpolation between segments"),
+ ('BSPLINE', "B-spline interpolation", "Use b-spline interpolation between segments"),
+ )
+
class CyclesRenderSettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
@@ -237,7 +269,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
)
cls.film_transparent = BoolProperty(
name="Transparent",
- description="World background is transparent",
+ description="World background is transparent with premultiplied alpha",
default=False,
)
@@ -573,6 +605,157 @@ class CyclesMeshSettings(bpy.types.PropertyGroup):
del bpy.types.Curve.cycles
del bpy.types.MetaBall.cycles
+class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
+ @classmethod
+ def register(cls):
+ bpy.types.Scene.cycles_curves = PointerProperty(
+ name="Cycles Hair Rendering Settings",
+ description="Cycles hair rendering settings",
+ type=cls,
+ )
+ cls.preset = EnumProperty(
+ name="Mode",
+ description="Hair rendering mode",
+ items=enum_curve_presets,
+ default='TRUE_NORMAL',
+ )
+ cls.primitive = EnumProperty(
+ name="Primitive",
+ description="Type of primitive used for hair rendering",
+ items=enum_curve_primitives,
+ default='LINE_SEGMENTS',
+ )
+ cls.triangle_method = EnumProperty(
+ name="Mesh Geometry",
+ description="Method for creating triangle geometry",
+ items=enum_triangle_curves,
+ default='CAMERA',
+ )
+ cls.line_method = EnumProperty(
+ name="Intersection Method",
+ description="Method for line segment intersection",
+ items=enum_line_curves,
+ default='ACCURATE',
+ )
+ cls.interpolation = EnumProperty(
+ name="Interpolation",
+ description="Interpolation method",
+ items=enum_curves_interpolation,
+ default='BSPLINE',
+ )
+ cls.use_backfacing = BoolProperty(
+ name="Check back-faces",
+ description="Test back-faces of strands",
+ default=False,
+ )
+ cls.use_encasing = BoolProperty(
+ name="Exclude encasing",
+ description="Ignore strands encasing a ray's initial location",
+ default=True,
+ )
+ cls.use_tangent_normal_geometry = BoolProperty(
+ name="Tangent normal geometry",
+ description="Use the tangent normal for actual normal",
+ default=False,
+ )
+ cls.use_tangent_normal = BoolProperty(
+ name="Tangent normal default",
+ description="Use the tangent normal for all normals",
+ default=False,
+ )
+ cls.use_tangent_normal_correction = BoolProperty(
+ name="Strand slope correction",
+ 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",
+ default=False,
+ )
+ cls.use_smooth = BoolProperty(
+ name="Smooth Strands",
+ description="Use vertex normals",
+ default=True,
+ )
+ cls.use_joined = BoolProperty(
+ name="Join",
+ description="Fill gaps between segments (requires more memory)",
+ default=False,
+ )
+ cls.use_curves = BoolProperty(
+ 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)",
+ min=1, max=64,
+ default=1,
+ )
+ cls.resolution = IntProperty(
+ name="Resolution",
+ description="Resolution of generated mesh",
+ min=3, max=64,
+ default=3,
+ )
+ cls.normalmix = FloatProperty(
+ name="Normal mix",
+ description="Scale factor for tangent normal removal (zero gives ray normal)",
+ min=0, max=2.0,
+ default=1,
+ )
+ cls.encasing_ratio = FloatProperty(
+ name="Encasing ratio",
+ description="Scale factor for encasing strand width",
+ min=0, max=100.0,
+ default=1.01,
+ )
+
+ @classmethod
+ def unregister(cls):
+ del bpy.types.Scene.cycles_curves
+
+class CyclesCurveSettings(bpy.types.PropertyGroup):
+ @classmethod
+ def register(cls):
+ bpy.types.ParticleSettings.cycles = PointerProperty(
+ name="Cycles Hair Settings",
+ description="Cycles hair settings",
+ type=cls,
+ )
+ cls.root_width = FloatProperty(
+ name="Root Size Multiplier",
+ description="Multiplier of particle size for the strand's width at root",
+ min=0.0, max=1000.0,
+ default=1.0,
+ )
+ cls.tip_width = FloatProperty(
+ name="Tip Size Multiplier",
+ description="Multiplier of particle size for the strand's width at tip",
+ min=0.0, max=1000.0,
+ default=0.0,
+ )
+ cls.shape = FloatProperty(
+ name="Strand Shape",
+ description="Strand shape parameter",
+ min=-1.0, max=1.0,
+ default=0.0,
+ )
+ cls.use_closetip = BoolProperty(
+ name="Close tip",
+ description="Set tip radius to zero",
+ default=True,
+ )
+
+ @classmethod
+ def unregister(cls):
+ del bpy.types.ParticleSettings.cycles
def register():
bpy.utils.register_class(CyclesRenderSettings)
@@ -582,6 +765,8 @@ def register():
bpy.utils.register_class(CyclesWorldSettings)
bpy.utils.register_class(CyclesVisibilitySettings)
bpy.utils.register_class(CyclesMeshSettings)
+ bpy.utils.register_class(CyclesCurveRenderSettings)
+ bpy.utils.register_class(CyclesCurveSettings)
def unregister():
@@ -592,3 +777,5 @@ def unregister():
bpy.utils.unregister_class(CyclesWorldSettings)
bpy.utils.unregister_class(CyclesMeshSettings)
bpy.utils.unregister_class(CyclesVisibilitySettings)
+ bpy.utils.unregister_class(CyclesCurveRenderSettings)
+ bpy.utils.unregister_class(CyclesCurveSettings)
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 7b19fde8f71..554a9204c7f 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -290,7 +290,7 @@ class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
rd = scene.render
row = layout.row()
- row.template_list(rd, "layers", rd.layers, "active_index", rows=2)
+ row.template_list("RENDER_UL_renderlayers", "", rd, "layers", rd.layers, "active_index", rows=2)
col = row.column(align=True)
col.operator("scene.render_layer_add", icon='ZOOMIN', text="")
@@ -407,7 +407,7 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
if ob:
row = layout.row()
- row.template_list(ob, "material_slots", ob, "active_material_index", rows=2)
+ row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=2)
col = row.column(align=True)
col.operator("object.material_slot_add", icon='ZOOMIN', text="")
@@ -962,7 +962,7 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel):
part = psys.settings
row = layout.row()
- row.template_list(part, "texture_slots", part, "active_texture_index", rows=2)
+ row.template_list("TEXTURE_UL_texslots", "", part, "texture_slots", part, "active_texture_index", rows=2)
col = row.column(align=True)
col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
@@ -975,6 +975,89 @@ 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):
+ 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')
+ 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="")
+
+ 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")
+
+ row = layout.row()
+ row.prop(cscene, "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")
+
+ row = layout.row()
+ row.prop(cscene, "segments", text="Segments")
+ row.prop(cscene, "normalmix", text="Ray Mix")
+
+ 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")
+
+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
+ 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')
+ 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")
+ row.prop(cpsys, "tip_width", text="Tip")
+
class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel):
bl_label = "Simplify"
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
new file mode 100644
index 00000000000..4fad7d45162
--- /dev/null
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -0,0 +1,1130 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "attribute.h"
+#include "mesh.h"
+#include "object.h"
+#include "scene.h"
+#include "curves.h"
+
+#include "blender_sync.h"
+#include "blender_util.h"
+
+#include "util_foreach.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Utilities */
+
+/* Hair curve functions */
+
+void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4]);
+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 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);
+void ExportCurveTriangleRibbons(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments);
+void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int resolution, int segments);
+void ExportCurveSegments(Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments);
+void ExportCurveTriangleUVs(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, int vert_offset, int resol);
+
+ParticleCurveData::ParticleCurveData()
+{
+}
+
+ParticleCurveData::~ParticleCurveData()
+{
+ psys_firstcurve.clear();
+ psys_curvenum.clear();
+ psys_shader.clear();
+ psys_rootradius.clear();
+ psys_tipradius.clear();
+ psys_shape.clear();
+
+ curve_firstkey.clear();
+ curve_keynum.clear();
+ curve_length.clear();
+ curve_uv.clear();
+ curve_vcol.clear();
+
+ curvekey_co.clear();
+ curvekey_time.clear();
+}
+
+void interp_weights(float t, float data[4], int type)
+{
+ float t2, t3, fc;
+
+ if(type == CURVE_LINEAR) {
+ data[0] = 0.0f;
+ data[1] = -t + 1.0f;
+ data[2] = t;
+ data[3] = 0.0f;
+ }
+ else if(type == CURVE_CARDINAL) {
+ t2 = t * t;
+ t3 = t2 * t;
+ fc = 0.71f;
+
+ 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;
+ }
+ else if(type == CURVE_BSPLINE) {
+ t2 = t * t;
+ t3 = t2 * t;
+
+ data[0] = -0.16666666f * t3 + 0.5f * t2 - 0.5f * t + 0.16666666f;
+ data[1] = 0.5f * t3 - t2 + 0.66666666f;
+ data[2] = -0.5f * t3 + 0.5f * t2 + 0.5f * t + 0.16666666f;
+ data[3] = 0.16666666f * t3;
+ }
+}
+
+void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4])
+{
+ p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3];
+ p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3];
+ p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3];
+}
+
+float shaperadius(float shape, float root, float tip, float time)
+{
+ float radius = 1.0f - time;
+ if(shape != 0.0f) {
+ if(shape < 0.0f)
+ radius = (float)pow(1.0f - time, 1.f + shape);
+ else
+ radius = (float)pow(1.0f - time, 1.f / (1.f - shape));
+ }
+ return (radius * (root - tip)) + tip;
+}
+
+/* curve functions */
+
+void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData, int interpolation)
+{
+ float3 ckey_loc1 = CData->curvekey_co[key];
+ float3 ckey_loc2 = ckey_loc1;
+ float3 ckey_loc3 = CData->curvekey_co[key+1];
+ float3 ckey_loc4 = ckey_loc3;
+
+ if(key > CData->curve_firstkey[curve])
+ ckey_loc1 = CData->curvekey_co[key - 1];
+
+ if(key < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)
+ ckey_loc4 = CData->curvekey_co[key + 2];
+
+
+ float time1 = CData->curvekey_time[key]/CData->curve_length[curve];
+ float time2 = CData->curvekey_time[key + 1]/CData->curve_length[curve];
+
+ float dfra = (time2 - time1) / (float)segno;
+
+ if(time)
+ *time = (dfra * seg) + time1;
+
+ float t[4];
+
+ interp_weights((float)seg / (float)segno, t, interpolation);
+
+ if(keyloc)
+ 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)
+{
+
+ int curvenum = 0;
+ int keyno = 0;
+
+ if(!(mesh && b_mesh && b_ob && CData))
+ return false;
+
+ Transform tfm = get_transform(b_ob->matrix_world());
+ Transform itfm = transform_quick_inverse(tfm);
+
+ 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((const PointerRNA)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 draw_step = b_psys.settings().draw_step();
+ int ren_step = (int)pow((float)2.0f,(float)draw_step);
+ /*b_psys.settings().render_step(draw_step);*/
+
+ int totparts = b_psys.particles.length();
+ int totchild = b_psys.child_particles.length() * b_psys.settings().draw_percentage() / 100;
+ int totcurves = totchild;
+
+ if(use_parents || b_psys.settings().child_type() == 0)
+ totcurves += totparts;
+
+ 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"));
+
+ int pa_no = 0;
+ if(!use_parents && !(b_psys.settings().child_type() == 0))
+ pa_no = totparts;
+
+ for(; pa_no < totparts+totchild; pa_no++) {
+
+ CData->curve_firstkey.push_back(keyno);
+ CData->curve_keynum.push_back(ren_step+1);
+
+ float curve_length = 0.0f;
+ float3 pcKey;
+ for(int step_no = 0; step_no <= ren_step; step_no++) {
+ float nco[3];
+ b_psys.co_hair(*b_ob, psmd, pa_no, step_no, nco);
+ float3 cKey = make_float3(nco[0],nco[1],nco[2]);
+ cKey = transform_point(&itfm, cKey);
+ 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++;
+ }
+ CData->curve_length.push_back(curve_length);
+
+ curvenum++;
+
+ }
+ }
+
+ }
+ }
+
+ return true;
+
+}
+
+bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents)
+{
+ int keyno = 0;
+
+ if(!(mesh && b_mesh && b_ob && CData))
+ return false;
+
+ Transform tfm = get_transform(b_ob->matrix_world());
+ Transform itfm = transform_quick_inverse(tfm);
+
+ 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((const PointerRNA)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 draw_step = b_psys.settings().draw_step();
+ int ren_step = (int)pow((float)2.0f,(float)draw_step);
+ /*b_psys.settings().render_step(draw_step);*/
+
+ int totparts = b_psys.particles.length();
+ int totchild = b_psys.child_particles.length() * b_psys.settings().draw_percentage() / 100;
+ int totcurves = totchild;
+
+ if (use_parents || b_psys.settings().child_type() == 0)
+ totcurves += totparts;
+
+ if (totcurves == 0)
+ continue;
+
+ int pa_no = 0;
+ if(!use_parents && !(b_psys.settings().child_type() == 0))
+ pa_no = totparts;
+
+ BL::ParticleSystem::particles_iterator b_pa;
+ b_psys.particles.begin(b_pa);
+ for(; pa_no < totparts+totchild; pa_no++) {
+
+ /*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_psys.uv_on_emitter(psmd, *b_pa, pa_no, &uv.x);
+ CData->curve_uv.push_back(uv);
+
+ if(pa_no < totparts && b_pa != b_psys.particles.end())
+ ++b_pa;
+
+ }
+ }
+
+ }
+ }
+
+ return true;
+
+}
+
+bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, int vcol_num)
+{
+ int keyno = 0;
+
+ if(!(mesh && b_mesh && b_ob && CData))
+ return false;
+
+ Transform tfm = get_transform(b_ob->matrix_world());
+ Transform itfm = transform_quick_inverse(tfm);
+
+ 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((const PointerRNA)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 draw_step = b_psys.settings().draw_step();
+ int ren_step = (int)pow((float)2.0f,(float)draw_step);
+ /*b_psys.settings().render_step(draw_step);*/
+
+ int totparts = b_psys.particles.length();
+ int totchild = b_psys.child_particles.length() * b_psys.settings().draw_percentage() / 100;
+ int totcurves = totchild;
+
+ if (use_parents || b_psys.settings().child_type() == 0)
+ totcurves += totparts;
+
+ if (totcurves == 0)
+ continue;
+
+ int pa_no = 0;
+ if(!use_parents && !(b_psys.settings().child_type() == 0))
+ pa_no = totparts;
+
+ BL::ParticleSystem::particles_iterator b_pa;
+ b_psys.particles.begin(b_pa);
+ for(; pa_no < totparts+totchild; pa_no++) {
+
+ /*add uvs*/
+ BL::Mesh::tessface_vertex_colors_iterator l;
+ b_mesh->tessface_vertex_colors.begin(l);
+
+ float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
+ if(b_mesh->tessface_vertex_colors.length())
+ b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
+ CData->curve_vcol.push_back(vcol);
+
+ if(pa_no < totparts && b_pa != b_psys.particles.end())
+ ++b_pa;
+
+ }
+ }
+
+ }
+ }
+
+ return true;
+
+}
+
+void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, float3 RotCam)
+{
+ int vertexno = mesh->verts.size();
+ int vertexindex = vertexno;
+
+ for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
+ for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+
+ for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
+
+ int subv = 1;
+ float3 xbasis;
+
+ float3 v1;
+
+ if(curvekey == CData->curve_firstkey[curve]) {
+ subv = 0;
+ v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey];
+ }
+ else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)
+ v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[max(curvekey - 2, CData->curve_firstkey[curve])];
+ else
+ v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1];
+
+
+ for (; subv <= segments; subv++) {
+
+ float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
+ float time = 0.0f;
+
+ if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
+ ickey_loc = CData->curvekey_co[curvekey];
+ else
+ InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
+
+ float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
+
+ if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
+ radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
+
+ if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) && (subv == segments))
+ radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
+
+ xbasis = normalize(cross(v1,RotCam - ickey_loc));
+ float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
+ float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
+ mesh->verts.push_back(ickey_loc_shfl);
+ mesh->verts.push_back(ickey_loc_shfr);
+ if(subv!=0) {
+ mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], use_smooth);
+ mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], use_smooth);
+ }
+ vertexindex += 2;
+ }
+ }
+ }
+ }
+
+ mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
+ mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
+ mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
+ mesh->add_face_normals();
+ mesh->add_vertex_normals();
+ mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
+
+ /* texture coords still needed */
+}
+
+void ExportCurveTriangleRibbons(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments)
+{
+ int vertexno = mesh->verts.size();
+ int vertexindex = vertexno;
+
+ for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
+ for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+
+ float3 firstxbasis = cross(make_float3(1.0f,0.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]]);
+ if(len_squared(firstxbasis)!= 0.0f)
+ firstxbasis = normalize(firstxbasis);
+ else
+ firstxbasis = normalize(cross(make_float3(0.0f,1.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]]));
+
+ for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
+
+ float3 xbasis = firstxbasis;
+ float3 v1;
+ float3 v2;
+
+ if(curvekey == CData->curve_firstkey[curve]) {
+ v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
+ v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
+ }
+ else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
+ v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
+ v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
+ }
+ else {
+ v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
+ v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
+ }
+
+ xbasis = cross(v1,v2);
+
+ if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
+ firstxbasis = normalize(xbasis);
+ break;
+ }
+ }
+
+ for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
+
+ int subv = 1;
+ float3 v1;
+ float3 v2;
+ float3 xbasis;
+
+ if(curvekey == CData->curve_firstkey[curve]) {
+ subv = 0;
+ v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
+ v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
+ }
+ else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
+ v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
+ v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
+ }
+ else {
+ v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
+ v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
+ }
+
+ xbasis = cross(v1,v2);
+
+ if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
+ xbasis = normalize(xbasis);
+ firstxbasis = xbasis;
+ }
+ else
+ xbasis = firstxbasis;
+
+ for (; subv <= segments; subv++) {
+
+ float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
+ float time = 0.0f;
+
+ if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
+ ickey_loc = CData->curvekey_co[curvekey];
+ else
+ InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
+
+ float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
+
+ if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
+ radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
+
+ if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) && (subv == segments))
+ radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
+
+ float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
+ float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
+ mesh->verts.push_back(ickey_loc_shfl);
+ mesh->verts.push_back(ickey_loc_shfr);
+ if(subv!=0) {
+ mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], use_smooth);
+ mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], use_smooth);
+ }
+ vertexindex += 2;
+ }
+ }
+ }
+ }
+
+ mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
+ mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
+ mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
+ mesh->add_face_normals();
+ mesh->add_vertex_normals();
+ mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
+ /* texture coords still needed */
+
+}
+
+void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int resolution, int segments)
+{
+ int vertexno = mesh->verts.size();
+ int vertexindex = vertexno;
+
+ for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
+ for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+
+ float3 firstxbasis = cross(make_float3(1.0f,0.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]]);
+ if(len_squared(firstxbasis)!= 0.0f)
+ firstxbasis = normalize(firstxbasis);
+ else
+ firstxbasis = normalize(cross(make_float3(0.0f,1.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]]));
+
+
+ for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
+
+ float3 xbasis = firstxbasis;
+ float3 v1;
+ float3 v2;
+
+ if(curvekey == CData->curve_firstkey[curve]) {
+ v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
+ v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
+ }
+ else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
+ v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
+ v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
+ }
+ else {
+ v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
+ v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
+ }
+
+ xbasis = cross(v1,v2);
+
+ if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
+ firstxbasis = normalize(xbasis);
+ break;
+ }
+ }
+
+ for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
+
+ int subv = 1;
+ float3 xbasis;
+ float3 ybasis;
+ float3 v1;
+ float3 v2;
+
+ if(curvekey == CData->curve_firstkey[curve]) {
+ subv = 0;
+ v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
+ v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
+ }
+ else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
+ v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
+ v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
+ }
+ else {
+ v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
+ v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
+ }
+
+ xbasis = cross(v1,v2);
+
+ if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
+ xbasis = normalize(xbasis);
+ firstxbasis = xbasis;
+ }
+ else
+ xbasis = firstxbasis;
+
+ ybasis = normalize(cross(xbasis,v2));
+
+ for (; subv <= segments; subv++) {
+
+ float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
+ float time = 0.0f;
+
+ if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
+ ickey_loc = CData->curvekey_co[curvekey];
+ else
+ InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
+
+ float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
+
+ if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
+ radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
+
+ if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) && (subv == segments))
+ radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
+
+ float angle = 2 * M_PI_F / (float)resolution;
+ for(int section = 0 ; section < resolution; section++) {
+ float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis);
+ mesh->verts.push_back(ickey_loc_shf);
+ }
+
+ if(subv!=0) {
+ for(int section = 0 ; section < resolution - 1; section++) {
+ mesh->add_triangle(vertexindex - resolution + section, vertexindex + section, vertexindex - resolution + section + 1, CData->psys_shader[sys], use_smooth);
+ mesh->add_triangle(vertexindex + section + 1, vertexindex - resolution + section + 1, vertexindex + section, CData->psys_shader[sys], use_smooth);
+ }
+ mesh->add_triangle(vertexindex-1, vertexindex + resolution - 1, vertexindex - resolution, CData->psys_shader[sys], use_smooth);
+ mesh->add_triangle(vertexindex, vertexindex - resolution , vertexindex + resolution - 1, CData->psys_shader[sys], use_smooth);
+ }
+ vertexindex += resolution;
+ }
+ }
+ }
+ }
+
+ mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
+ mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
+ mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
+ mesh->add_face_normals();
+ mesh->add_vertex_normals();
+ mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
+
+ /* texture coords still needed */
+}
+
+static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments)
+{
+ int num_keys = 0;
+ int num_curves = 0;
+
+ if(!(mesh->curves.empty() && mesh->curve_keys.empty()))
+ return;
+
+ Attribute *attr_uv = NULL, *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);
+
+ for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
+
+ if(CData->psys_curvenum[sys] == 0)
+ continue;
+
+ for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+
+ if(CData->curve_keynum[curve] <= 1)
+ continue;
+
+ size_t num_curve_keys = 0;
+
+ for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
+
+ int subv = 1;
+ if(curvekey == CData->curve_firstkey[curve])
+ subv = 0;
+
+ for (; subv <= segments; subv++) {
+
+ float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
+ float time = 0.0f;
+
+ if((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
+ ickey_loc = CData->curvekey_co[curvekey];
+ else
+ InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
+
+ float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
+
+ if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
+ radius =0.0f;
+
+ mesh->add_curve_key(ickey_loc, radius);
+ if(attr_intercept)
+ attr_intercept->add(time);
+
+ num_curve_keys++;
+ }
+ }
+
+ 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++;
+ }
+ }
+
+ /* check allocation*/
+ if((mesh->curve_keys.size() != num_keys) || (mesh->curves.size() != num_curves)) {
+ /* allocation failed -> clear data */
+ mesh->curve_keys.clear();
+ mesh->curves.clear();
+ mesh->curve_attributes.clear();
+ }
+}
+
+void ExportCurveTriangleUVs(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, int vert_offset, int resol)
+{
+ float time = 0.0f;
+ float prevtime = 0.0f;
+
+ Attribute *attr = mesh->attributes.find(ATTR_STD_UV);
+ if (attr == NULL)
+ return;
+
+ float3 *uvdata = attr->data_float3();
+
+ int vertexindex = vert_offset;
+
+ for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
+ for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+
+ for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
+
+ int subv = 1;
+
+ if (curvekey == CData->curve_firstkey[curve])
+ subv = 0;
+
+ for (; subv <= segments; subv++) {
+
+ float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
+
+ InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
+
+ if(subv!=0) {
+ for(int section = 0 ; section < resol; section++) {
+ uvdata[vertexindex] = CData->curve_uv[curve];
+ uvdata[vertexindex].z = prevtime;
+ vertexindex++;
+ uvdata[vertexindex] = CData->curve_uv[curve];
+ uvdata[vertexindex].z = time;
+ vertexindex++;
+ uvdata[vertexindex] = CData->curve_uv[curve];
+ uvdata[vertexindex].z = prevtime;
+ vertexindex++;
+ uvdata[vertexindex] = CData->curve_uv[curve];
+ uvdata[vertexindex].z = time;
+ vertexindex++;
+ uvdata[vertexindex] = CData->curve_uv[curve];
+ uvdata[vertexindex].z = prevtime;
+ vertexindex++;
+ uvdata[vertexindex] = CData->curve_uv[curve];
+ uvdata[vertexindex].z = time;
+ vertexindex++;
+ }
+ }
+
+ prevtime = time;
+ }
+ }
+ }
+ }
+
+}
+/* Hair Curve Sync */
+
+void BlenderSync::sync_curve_settings()
+{
+ PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves");
+
+ int preset = get_enum(csscene, "preset");
+
+ CurveSystemManager *curve_system_manager = scene->curve_system_manager;
+ CurveSystemManager prev_curve_system_manager = *curve_system_manager;
+
+ curve_system_manager->use_curves = get_boolean(csscene, "use_curves");
+
+ if(preset == CURVE_CUSTOM) {
+ /*custom properties*/
+ curve_system_manager->primitive = get_enum(csscene, "primitive");
+ curve_system_manager->line_method = get_enum(csscene, "line_method");
+ curve_system_manager->interpolation = get_enum(csscene, "interpolation");
+ curve_system_manager->triangle_method = get_enum(csscene, "triangle_method");
+ 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->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");
+ curve_system_manager->use_joined = get_boolean(csscene, "use_joined");
+ curve_system_manager->use_tangent_normal = get_boolean(csscene, "use_tangent_normal");
+ curve_system_manager->use_tangent_normal_geometry = get_boolean(csscene, "use_tangent_normal_geometry");
+ curve_system_manager->use_tangent_normal_correction = get_boolean(csscene, "use_tangent_normal_correction");
+ }
+ else {
+ curve_system_manager->primitive = CURVE_LINE_SEGMENTS;
+ 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;
+
+ switch(preset) {
+ case CURVE_TANGENT_SHADING:
+ /*tangent shading*/
+ curve_system_manager->line_method = CURVE_UNCORRECTED;
+ curve_system_manager->use_encasing = true;
+ curve_system_manager->use_backfacing = false;
+ curve_system_manager->use_tangent_normal = true;
+ curve_system_manager->use_tangent_normal_geometry = true;
+ curve_system_manager->use_tangent_normal_correction = false;
+ break;
+ case CURVE_TRUE_NORMAL:
+ /*True Normal*/
+ curve_system_manager->line_method = CURVE_CORRECTED;
+ curve_system_manager->use_encasing = true;
+ curve_system_manager->use_backfacing = false;
+ curve_system_manager->use_tangent_normal = false;
+ curve_system_manager->use_tangent_normal_geometry = false;
+ curve_system_manager->use_tangent_normal_correction = false;
+ break;
+ case CURVE_ACCURATE_PRESET:
+ /*Accurate*/
+ curve_system_manager->line_method = CURVE_ACCURATE;
+ curve_system_manager->use_encasing = false;
+ curve_system_manager->use_backfacing = true;
+ curve_system_manager->use_tangent_normal = false;
+ curve_system_manager->use_tangent_normal_geometry = false;
+ curve_system_manager->use_tangent_normal_correction = false;
+ break;
+ }
+
+ }
+
+ if(curve_system_manager->modified_mesh(prev_curve_system_manager))
+ {
+ BL::BlendData::objects_iterator b_ob;
+
+ for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
+ if(object_is_mesh(*b_ob)) {
+ BL::Object::particle_systems_iterator b_psys;
+ for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) {
+ if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR)) {
+ BL::ID key = BKE_object_is_modified(*b_ob)? *b_ob: b_ob->data();
+ mesh_map.set_recalc(key);
+ object_map.set_recalc(*b_ob);
+ }
+ }
+ }
+ }
+ }
+
+ if(curve_system_manager->modified(prev_curve_system_manager))
+ curve_system_manager->tag_update(scene);
+
+}
+
+void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool object_updated)
+{
+ /* Clear stored curve data */
+ mesh->curve_keys.clear();
+ mesh->curves.clear();
+ mesh->curve_attributes.clear();
+
+ /* obtain general settings */
+ bool use_curves = scene->curve_system_manager->use_curves;
+
+ if(!(use_curves && b_ob.mode() == b_ob.mode_OBJECT)) {
+ mesh->compute_bounds();
+ return;
+ }
+
+ int primitive = scene->curve_system_manager->primitive;
+ int interpolation = scene->curve_system_manager->interpolation;
+ int triangle_method = scene->curve_system_manager->triangle_method;
+ 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;
+
+ /* extract particle hair data - should be combined with connecting to mesh later*/
+
+ 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);
+
+ /* attach strands to mesh */
+ BL::Object b_CamOb = b_scene.camera();
+ float3 RotCam = make_float3(0.0f, 0.0f, 0.0f);
+ if(b_CamOb) {
+ Transform ctfm = get_transform(b_CamOb.matrix_world());
+ Transform tfm = get_transform(b_ob.matrix_world());
+ Transform itfm = transform_quick_inverse(tfm);
+ RotCam = transform_point(&itfm, make_float3(ctfm.x.w, ctfm.y.w, ctfm.z.w));
+ }
+
+ if(primitive == CURVE_TRIANGLES){
+ int vert_num = mesh->triangles.size() * 3;
+ if(triangle_method == CURVE_CAMERA) {
+ ExportCurveTrianglePlanes(mesh, &CData, interpolation, use_smooth, segments, RotCam);
+ ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, 1);
+ }
+ else if(triangle_method == CURVE_RIBBONS) {
+ ExportCurveTriangleRibbons(mesh, &CData, interpolation, use_smooth, segments);
+ ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, 1);
+ }
+ else {
+ ExportCurveTriangleGeometry(mesh, &CData, interpolation, use_smooth, resolution, segments);
+ ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, resolution);
+ }
+
+ }
+ else {
+ ExportCurveSegments(scene, mesh, &CData, interpolation, segments);
+ int ckey_num = mesh->curve_keys.size();
+
+ /*export tangents or curve data? - not functional yet*/
+ if(export_tgs && ckey_num > 1) {
+ Attribute *attr_tangent = mesh->curve_attributes.add(ATTR_STD_CURVE_TANGENT);
+ float3 *data_tangent = attr_tangent->data_float3();
+
+ for(int ck = 0; ck < ckey_num; ck++) {
+ float3 tg = normalize(normalize(mesh->curve_keys[min(ck + 1, ckey_num - 1)].co - mesh->curve_keys[ck].co) -
+ normalize(mesh->curve_keys[max(ck - 1, 0)].co - mesh->curve_keys[ck].co));
+
+ data_tangent[ck] = tg;
+ }
+ }
+
+ /* 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);
+
+ 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;
+ }
+ }
+
+ /* create vertex color attributes */
+ BL::Mesh::tessface_vertex_colors_iterator l;
+ int vcol_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;
+
+ /*error occurs with more than one vertex colour attribute so avoided*/
+ if(vcol_num!=0)
+ break;
+
+ 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, 0);
+
+ 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]);
+ }
+
+ }
+
+ }
+
+ mesh->compute_bounds();
+}
+
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index c9748756d43..1dd7800dfa4 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -147,7 +147,7 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_la
if(active_render)
attr = mesh->attributes.add(ATTR_STD_UV_TANGENT, name);
else
- attr = mesh->attributes.add(name, TypeDesc::TypeVector, Attribute::CORNER);
+ attr = mesh->attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER);
float3 *tangent = attr->data_float3();
@@ -161,7 +161,7 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_la
if(active_render)
attr_sign = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign);
else
- attr_sign = mesh->attributes.add(name_sign, TypeDesc::TypeFloat, Attribute::CORNER);
+ attr_sign = mesh->attributes.add(name_sign, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER);
tangent_sign = attr_sign->data_float();
}
@@ -223,10 +223,19 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
int shader = used_shaders[mi];
bool smooth = f->use_smooth();
- mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
-
- if(n == 4)
- mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth);
+ if(n == 4) {
+ if(len_squared(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) == 0.0f ||
+ len_squared(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])) == 0.0f) {
+ mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth);
+ mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth);
+ }
+ else {
+ mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
+ mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth);
+ }
+ }
+ else
+ mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
nverts.push_back(n);
}
@@ -240,7 +249,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
continue;
Attribute *attr = mesh->attributes.add(
- ustring(l->name().c_str()), TypeDesc::TypeColor, Attribute::CORNER);
+ ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER);
BL::MeshColorLayer::data_iterator c;
float3 *fdata = attr->data_float3();
@@ -279,7 +288,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
if(active_render)
attr = mesh->attributes.add(std, name);
else
- attr = mesh->attributes.add(name, TypeDesc::TypePoint, Attribute::CORNER);
+ attr = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
BL::MeshTextureFaceLayer::data_iterator t;
float3 *fdata = attr->data_float3();
@@ -319,14 +328,9 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
* is available in the api. */
if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
- float3 loc = get_float3(b_mesh.texspace_location());
- float3 size = get_float3(b_mesh.texspace_size());
- if(size.x != 0.0f) size.x = 0.5f/size.x;
- if(size.y != 0.0f) size.y = 0.5f/size.y;
- if(size.z != 0.0f) size.z = 0.5f/size.z;
-
- loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
+ float3 loc, size;
+ mesh_texture_space(b_mesh, loc, size);
float3 *generated = attr->data_float3();
size_t i = 0;
@@ -376,7 +380,7 @@ static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, con
/* Sync */
-Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
+Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris)
{
/* test if we can instance or if the object is modified */
BL::ID b_ob_data = b_ob.data();
@@ -435,16 +439,24 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");
vector<Mesh::Triangle> oldtriangle = mesh->triangles;
+
+ /* compares curve_keys rather than strands in order to handle quick hair adjustsments in dynamic BVH - other methods could probably do this better*/
+ vector<Mesh::CurveKey> oldcurve_keys = mesh->curve_keys;
mesh->clear();
mesh->used_shaders = used_shaders;
mesh->name = ustring(b_ob_data.name().c_str());
if(b_mesh) {
- if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
- create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
- else
- create_mesh(scene, mesh, b_mesh, used_shaders);
+ if(!(hide_tris && experimental && is_cpu)) {
+ if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
+ create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
+ else
+ create_mesh(scene, mesh, b_mesh, used_shaders);
+ }
+
+ if(experimental && is_cpu)
+ sync_curves(mesh, b_mesh, b_ob, object_updated);
/* free derived mesh */
b_data.meshes.remove(b_mesh);
@@ -471,6 +483,13 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
rebuild = true;
}
+
+ if(oldcurve_keys.size() != mesh->curve_keys.size())
+ rebuild = true;
+ else if(oldcurve_keys.size()) {
+ if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(Mesh::CurveKey)*oldcurve_keys.size()) != 0)
+ rebuild = true;
+ }
mesh->tag_update(scene, rebuild);
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 38f27bcf2af..ad701266c5b 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -196,7 +196,7 @@ void BlenderSync::sync_background_light()
/* Object */
-Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob, Transform& tfm, uint layer_flag, int motion)
+Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob, Transform& tfm, uint layer_flag, int motion, bool hide_tris)
{
BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
@@ -247,7 +247,7 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0;
/* mesh sync */
- object->mesh = sync_mesh(b_ob, object_updated);
+ object->mesh = sync_mesh(b_ob, object_updated, hide_tris);
/* sspecial case not tracked by object update flags */
if(use_holdout != object->use_holdout) {
@@ -390,7 +390,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id();
/* sync object and mesh or light data */
- Object *object = sync_object(*b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion);
+ Object *object = sync_object(*b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion, false);
/* sync possible particle data, note particle_id
* starts counting at 1, first is dummy particle */
@@ -412,9 +412,23 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
/* check if we should render or hide particle emitter */
BL::Object::particle_systems_iterator b_psys;
- for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys)
- if(b_psys->settings().use_render_emitter())
+ bool hair_present = false;
+ bool show_emitter = false;
+ bool hide_tris = false;
+
+ for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) {
+
+ if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR))
+ hair_present = true;
+
+ if(b_psys->settings().use_render_emitter()) {
hide = false;
+ show_emitter = true;
+ }
+ }
+
+ if(hair_present && !show_emitter)
+ hide_tris = true;
/* hide original object for duplis */
BL::Object parent = b_ob->parent();
@@ -424,7 +438,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
if(!hide) {
/* object itself */
Transform tfm = get_transform(b_ob->matrix_world());
- sync_object(*b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion);
+ sync_object(*b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion, hide_tris);
}
}
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index b8ed942f5b6..770b71afcdc 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -96,7 +96,7 @@ void BlenderSession::create_session()
session->set_pause(BlenderSync::get_session_pause(b_scene, background));
/* create sync */
- sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress);
+ sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, session_params.device.type == DEVICE_CPU);
sync->sync_data(b_v3d, b_engine.camera_override());
if(b_rv3d)
@@ -107,6 +107,8 @@ void BlenderSession::create_session()
/* set buffer parameters */
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, b_v3d, b_rv3d, scene->camera, width, height);
session->reset(buffer_params, session_params.samples);
+
+ b_engine.use_highlight_tiles(session_params.progressive_refine == false);
}
void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_)
@@ -143,12 +145,14 @@ void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_)
session->stats.mem_peak = session->stats.mem_used;
/* sync object should be re-created */
- sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress);
+ sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, session_params.device.type == DEVICE_CPU);
sync->sync_data(b_v3d, b_engine.camera_override());
sync->sync_camera(b_engine.camera_override(), width, height);
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, PointerRNA_NULL, PointerRNA_NULL, scene->camera, width, height);
session->reset(buffer_params, session_params.samples);
+
+ b_engine.use_highlight_tiles(session_params.progressive_refine == false);
}
void BlenderSession::free_session()
@@ -252,7 +256,15 @@ void BlenderSession::do_write_update_render_tile(RenderTile& rtile, bool do_upda
if (do_update_only) {
/* update only needed */
- update_render_result(b_rr, b_rlay, rtile);
+
+ if (rtile.sample != 0) {
+ /* sample would be zero at initial tile update, which is only needed
+ * to tag tile form blender side as IN PROGRESS for proper highlight
+ * no buffers should be sent to blender yet
+ */
+ update_render_result(b_rr, b_rlay, rtile);
+ }
+
end_render_result(b_engine, b_rr, true);
}
else {
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 848a9a199f9..ddbd7f935e4 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -447,6 +447,10 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
node = new ParticleInfoNode();
break;
}
+ case BL::ShaderNode::type_HAIR_INFO: {
+ node = new HairInfoNode();
+ break;
+ }
case BL::ShaderNode::type_BUMP: {
node = new BumpNode();
break;
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index d455bdbe8e2..b9860ca90f2 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -28,6 +28,7 @@
#include "object.h"
#include "scene.h"
#include "shader.h"
+#include "curves.h"
#include "device.h"
@@ -41,7 +42,7 @@ CCL_NAMESPACE_BEGIN
/* Constructor */
-BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_, Progress &progress_)
+BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_, Progress &progress_, bool is_cpu_)
: b_engine(b_engine_),
b_data(b_data_), b_scene(b_scene_),
shader_map(&scene_->shaders),
@@ -56,6 +57,7 @@ BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::
{
scene = scene_;
preview = preview_;
+ is_cpu = is_cpu_;
}
BlenderSync::~BlenderSync()
@@ -141,6 +143,7 @@ void BlenderSync::sync_data(BL::SpaceView3D b_v3d, BL::Object b_override, const
sync_integrator();
sync_film();
sync_shaders();
+ sync_curve_settings();
sync_objects(b_v3d);
sync_motion(b_v3d, b_override);
}
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index d3d21fbdf72..5050743f1cf 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -50,7 +50,7 @@ class ShaderNode;
class BlenderSync {
public:
- BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_, Progress &progress_);
+ BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_, Progress &progress_, bool is_cpu_);
~BlenderSync();
/* sync */
@@ -78,10 +78,12 @@ private:
void sync_world(bool update_all);
void sync_render_layers(BL::SpaceView3D b_v3d, const char *layer);
void sync_shaders();
+ void sync_curve_settings();
void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree);
- Mesh *sync_mesh(BL::Object b_ob, bool object_updated);
- Object *sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_object, Transform& tfm, uint layer_flag, int motion);
+ Mesh *sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris);
+ void sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool object_updated);
+ Object *sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_object, Transform& tfm, uint layer_flag, int motion, bool hide_tris);
void sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object b_ob, Transform& tfm);
void sync_background_light();
void sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion);
@@ -113,6 +115,7 @@ private:
Scene *scene;
bool preview;
bool experimental;
+ bool is_cpu;
struct RenderLayerInfo {
RenderLayerInfo()
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index fbcbe15ec5a..88c98860794 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -242,6 +242,20 @@ static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, co
return path;
}
+/* Texture Space */
+
+static inline void mesh_texture_space(BL::Mesh b_mesh, float3& loc, float3& size)
+{
+ loc = get_float3(b_mesh.texspace_location());
+ size = get_float3(b_mesh.texspace_size());
+
+ if(size.x != 0.0f) size.x = 0.5f/size.x;
+ if(size.y != 0.0f) size.y = 0.5f/size.y;
+ if(size.z != 0.0f) size.z = 0.5f/size.z;
+
+ loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
+}
+
/* ID Map
*
* Utility class to keep in sync with blender data.
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index b58a34f9942..412b44031e6 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -75,6 +75,8 @@ bool BVH::cache_read(CacheData& key)
foreach(Object *ob, objects) {
key.add(ob->mesh->verts);
key.add(ob->mesh->triangles);
+ key.add(ob->mesh->curve_keys);
+ key.add(ob->mesh->curves);
key.add(&ob->bounds, sizeof(ob->bounds));
key.add(&ob->visibility, sizeof(ob->visibility));
key.add(&ob->mesh->transform_applied, sizeof(bool));
@@ -91,6 +93,7 @@ bool BVH::cache_read(CacheData& key)
value.read(pack.nodes);
value.read(pack.object_node);
value.read(pack.tri_woop);
+ value.read(pack.prim_segment);
value.read(pack.prim_visibility);
value.read(pack.prim_index);
value.read(pack.prim_object);
@@ -112,6 +115,7 @@ void BVH::cache_write(CacheData& key)
value.add(pack.nodes);
value.add(pack.object_node);
value.add(pack.tri_woop);
+ value.add(pack.prim_segment);
value.add(pack.prim_visibility);
value.add(pack.prim_index);
value.add(pack.prim_object);
@@ -157,10 +161,11 @@ void BVH::build(Progress& progress)
}
/* build nodes */
+ vector<int> prim_segment;
vector<int> prim_index;
vector<int> prim_object;
- BVHBuild bvh_build(objects, prim_index, prim_object, params, progress);
+ BVHBuild bvh_build(objects, prim_segment, prim_index, prim_object, params, progress);
BVHNode *root = bvh_build.run();
if(progress.get_cancel()) {
@@ -169,6 +174,7 @@ void BVH::build(Progress& progress)
}
/* todo: get rid of this copy */
+ pack.prim_segment = prim_segment;
pack.prim_index = prim_index;
pack.prim_object = prim_object;
@@ -182,8 +188,8 @@ void BVH::build(Progress& progress)
}
/* pack triangles */
- progress.set_substatus("Packing BVH triangles");
- pack_triangles();
+ progress.set_substatus("Packing BVH triangles and strands");
+ pack_primitives();
if(progress.get_cancel()) {
root->deleteSubtree();
@@ -215,8 +221,8 @@ void BVH::build(Progress& progress)
void BVH::refit(Progress& progress)
{
- progress.set_substatus("Packing BVH triangles");
- pack_triangles();
+ progress.set_substatus("Packing BVH primitives");
+ pack_primitives();
if(progress.get_cancel()) return;
@@ -263,7 +269,52 @@ void BVH::pack_triangle(int idx, float4 woop[3])
}
}
-void BVH::pack_triangles()
+/* Curves*/
+
+void BVH::pack_curve_segment(int idx, float4 woop[3])
+{
+ int tob = pack.prim_object[idx];
+ const Mesh *mesh = objects[tob]->mesh;
+ int tidx = pack.prim_index[idx];
+ int segment = pack.prim_segment[idx];
+ int k0 = mesh->curves[tidx].first_key + segment;
+ int k1 = mesh->curves[tidx].first_key + segment + 1;
+ float3 v0 = mesh->curve_keys[k0].co;
+ float3 v1 = mesh->curve_keys[k1].co;
+
+ float3 d0 = v1 - v0;
+ float l = len(d0);
+
+ /*Plan
+ *Transform tfm = make_transform(
+ * location <3> , l,
+ * extra curve data <3> , StrID,
+ * nextkey, flags/tip?, 0, 0);
+ */
+ Attribute *attr_tangent = mesh->curve_attributes.find(ATTR_STD_CURVE_TANGENT);
+ float3 tg0 = make_float3(1.0f, 0.0f, 0.0f);
+ float3 tg1 = make_float3(1.0f, 0.0f, 0.0f);
+
+ if(attr_tangent) {
+ const float3 *data_tangent = attr_tangent->data_float3();
+
+ tg0 = data_tangent[k0];
+ tg1 = data_tangent[k1];
+ }
+
+ Transform tfm = make_transform(
+ tg0.x, tg0.y, tg0.z, l,
+ tg1.x, tg1.y, tg1.z, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 1);
+
+ woop[0] = tfm.x;
+ woop[1] = tfm.y;
+ woop[2] = tfm.z;
+
+}
+
+void BVH::pack_primitives()
{
int nsize = TRI_NODE_SIZE;
size_t tidx_size = pack.prim_index.size();
@@ -277,7 +328,11 @@ void BVH::pack_triangles()
if(pack.prim_index[i] != -1) {
float4 woop[3];
- pack_triangle(i, woop);
+ if(pack.prim_segment[i] != ~0)
+ pack_curve_segment(i, woop);
+ else
+ pack_triangle(i, woop);
+
memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
int tob = pack.prim_object[i];
@@ -300,11 +355,15 @@ void BVH::pack_instances(size_t nodes_size)
/* adjust primitive index to point to the triangle in the global array, for
* meshes with transform applied and already in the top level BVH */
for(size_t i = 0; i < pack.prim_index.size(); i++)
- if(pack.prim_index[i] != -1)
- pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
+ if(pack.prim_index[i] != -1) {
+ if(pack.prim_segment[i] != ~0)
+ pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curve_offset;
+ else
+ pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
+ }
/* track offsets of instanced BVH data in global array */
- size_t tri_offset = pack.prim_index.size();
+ size_t prim_offset = pack.prim_index.size();
size_t nodes_offset = nodes_size;
/* clear array that gives the node indexes for instanced objects */
@@ -339,6 +398,7 @@ void BVH::pack_instances(size_t nodes_size)
mesh_map.clear();
pack.prim_index.resize(prim_index_size);
+ pack.prim_segment.resize(prim_index_size);
pack.prim_object.resize(prim_index_size);
pack.prim_visibility.resize(prim_index_size);
pack.tri_woop.resize(tri_woop_size);
@@ -346,6 +406,7 @@ void BVH::pack_instances(size_t nodes_size)
pack.object_node.resize(objects.size());
int *pack_prim_index = (pack.prim_index.size())? &pack.prim_index[0]: NULL;
+ int *pack_prim_segment = (pack.prim_segment.size())? &pack.prim_segment[0]: NULL;
int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL;
uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL;
float4 *pack_tri_woop = (pack.tri_woop.size())? &pack.tri_woop[0]: NULL;
@@ -376,6 +437,7 @@ void BVH::pack_instances(size_t nodes_size)
int noffset = nodes_offset/nsize;
int mesh_tri_offset = mesh->tri_offset;
+ int mesh_curve_offset = mesh->curve_offset;
/* fill in node indexes for instances */
if((bvh->pack.is_leaf.size() != 0) && bvh->pack.is_leaf[0])
@@ -389,10 +451,16 @@ void BVH::pack_instances(size_t nodes_size)
if(bvh->pack.prim_index.size()) {
size_t bvh_prim_index_size = bvh->pack.prim_index.size();
int *bvh_prim_index = &bvh->pack.prim_index[0];
+ int *bvh_prim_segment = &bvh->pack.prim_segment[0];
uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
for(size_t i = 0; i < bvh_prim_index_size; i++) {
- pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
+ if(bvh->pack.prim_segment[i] != ~0)
+ pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset;
+ else
+ pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
+
+ pack_prim_segment[pack_prim_index_offset] = bvh_prim_segment[i];
pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
pack_prim_index_offset++;
@@ -401,7 +469,7 @@ void BVH::pack_instances(size_t nodes_size)
/* merge triangle intersection data */
if(bvh->pack.tri_woop.size()) {
- memcpy(pack_tri_woop+pack_tri_woop_offset, &bvh->pack.tri_woop[0],
+ memcpy(pack_tri_woop + pack_tri_woop_offset, &bvh->pack.tri_woop[0],
bvh->pack.tri_woop.size()*sizeof(float4));
pack_tri_woop_offset += bvh->pack.tri_woop.size();
}
@@ -420,8 +488,8 @@ void BVH::pack_instances(size_t nodes_size)
int4 data = bvh_nodes[i + nsize_bbox];
if(bvh_is_leaf && bvh_is_leaf[j]) {
- data.x += tri_offset;
- data.y += tri_offset;
+ data.x += prim_offset;
+ data.y += prim_offset;
}
else {
data.x += (data.x < 0)? -noffset: noffset;
@@ -443,7 +511,7 @@ void BVH::pack_instances(size_t nodes_size)
}
nodes_offset += bvh->pack.nodes.size();
- tri_offset += bvh->pack.prim_index.size();
+ prim_offset += bvh->pack.prim_index.size();
}
}
@@ -544,25 +612,38 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
if(leaf) {
/* refit leaf node */
- for(int tri = c0; tri < c1; tri++) {
- int tidx = pack.prim_index[tri];
- int tob = pack.prim_object[tri];
+ for(int prim = c0; prim < c1; prim++) {
+ int pidx = pack.prim_index[prim];
+ int tob = pack.prim_object[prim];
Object *ob = objects[tob];
- if(tidx == -1) {
+ if(pidx == -1) {
/* object instance */
bbox.grow(ob->bounds);
}
else {
- /* triangles */
+ /* primitives */
const Mesh *mesh = ob->mesh;
- int tri_offset = (params.top_level)? mesh->tri_offset: 0;
- const int *vidx = mesh->triangles[tidx - tri_offset].v;
- const float3 *vpos = &mesh->verts[0];
- bbox.grow(vpos[vidx[0]]);
- bbox.grow(vpos[vidx[1]]);
- bbox.grow(vpos[vidx[2]]);
+ if(pack.prim_segment[prim] != ~0) {
+ /* curves */
+ int str_offset = (params.top_level)? mesh->curve_offset: 0;
+ 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);
+ }
+ else {
+ /* triangles */
+ int tri_offset = (params.top_level)? mesh->tri_offset: 0;
+ const int *vidx = mesh->triangles[pidx - tri_offset].v;
+ const float3 *vpos = &mesh->verts[0];
+
+ bbox.grow(vpos[vidx[0]]);
+ bbox.grow(vpos[vidx[1]]);
+ bbox.grow(vpos[vidx[2]]);
+ }
}
visibility |= ob->visibility;
diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h
index 549f1e3ac1d..00c146143b8 100644
--- a/intern/cycles/bvh/bvh.h
+++ b/intern/cycles/bvh/bvh.h
@@ -51,7 +51,9 @@ struct PackedBVH {
/* object index to BVH node index mapping for instances */
array<int> object_node;
/* precomputed triangle intersection data, one triangle is 4x float4 */
- array<float4> tri_woop;
+ array<float4> tri_woop;
+ /* primitive type - triangle or strand (should be moved to flag?) */
+ array<int> prim_segment;
/* visibility visibilitys for primitives */
array<uint> prim_visibility;
/* mapping from BVH primitive index to true primitive index, as primitives
@@ -101,9 +103,10 @@ protected:
bool cache_read(CacheData& key);
void cache_write(CacheData& key);
- /* triangles */
- void pack_triangles();
+ /* triangles and strands*/
+ void pack_primitives();
void pack_triangle(int idx, float4 woop[3]);
+ void pack_curve_segment(int idx, float4 woop[3]);
/* merge instance BVH's */
void pack_instances(size_t nodes_size);
diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp
index 705b805a3a9..38fb1a15a13 100644
--- a/intern/cycles/bvh/bvh_build.cpp
+++ b/intern/cycles/bvh/bvh_build.cpp
@@ -48,9 +48,10 @@ public:
/* Constructor / Destructor */
BVHBuild::BVHBuild(const vector<Object*>& objects_,
- vector<int>& prim_index_, vector<int>& prim_object_,
+ vector<int>& prim_segment_, vector<int>& prim_index_, vector<int>& prim_object_,
const BVHParams& params_, Progress& progress_)
: objects(objects_),
+ prim_segment(prim_segment_),
prim_index(prim_index_),
prim_object(prim_object_),
params(params_),
@@ -73,25 +74,55 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh,
BoundBox bounds = BoundBox::empty;
for(int k = 0; k < 3; k++) {
- float3 pt = mesh->verts[t.v[k]];
- bounds.grow(pt);
+ float3 co = mesh->verts[t.v[k]];
+ bounds.grow(co);
}
if(bounds.valid()) {
- references.push_back(BVHReference(bounds, j, i));
+ references.push_back(BVHReference(bounds, j, i, ~0));
root.grow(bounds);
center.grow(bounds.center2());
}
}
+
+ for(uint j = 0; j < mesh->curves.size(); j++) {
+ Mesh::Curve curve = mesh->curves[j];
+
+ 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);
+
+ if(bounds.valid()) {
+ references.push_back(BVHReference(bounds, j, i, k));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ }
}
void BVHBuild::add_reference_object(BoundBox& root, BoundBox& center, Object *ob, int i)
{
- references.push_back(BVHReference(ob->bounds, -1, i));
+ references.push_back(BVHReference(ob->bounds, -1, i, false));
root.grow(ob->bounds);
center.grow(ob->bounds.center2());
}
+static size_t count_curve_segments(Mesh *mesh)
+{
+ size_t num = 0, num_curves = mesh->curves.size();
+
+ for(size_t i = 0; i < num_curves; i++)
+ num += mesh->curves[i].num_keys - 1;
+
+ return num;
+}
+
void BVHBuild::add_references(BVHRange& root)
{
/* reserve space for references */
@@ -99,13 +130,17 @@ void BVHBuild::add_references(BVHRange& root)
foreach(Object *ob, objects) {
if(params.top_level) {
- if(ob->mesh->transform_applied)
+ if(ob->mesh->transform_applied) {
num_alloc_references += ob->mesh->triangles.size();
+ num_alloc_references += count_curve_segments(ob->mesh);
+ }
else
num_alloc_references++;
}
- else
+ else {
num_alloc_references += ob->mesh->triangles.size();
+ num_alloc_references += count_curve_segments(ob->mesh);
+ }
}
references.reserve(num_alloc_references);
@@ -162,6 +197,7 @@ BVHNode* BVHBuild::run()
progress_total = references.size();
progress_original_total = progress_total;
+ prim_segment.resize(references.size());
prim_index.resize(references.size());
prim_object.resize(references.size());
@@ -319,10 +355,12 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start,
if(start == prim_index.size()) {
assert(params.use_spatial_split);
+ prim_segment.push_back(ref->prim_segment());
prim_index.push_back(ref->prim_index());
prim_object.push_back(ref->prim_object());
}
else {
+ prim_segment[start] = ref->prim_segment();
prim_index[start] = ref->prim_index();
prim_object[start] = ref->prim_object();
}
@@ -345,6 +383,7 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start,
BVHNode* BVHBuild::create_leaf_node(const BVHRange& range)
{
+ vector<int>& p_segment = prim_segment;
vector<int>& p_index = prim_index;
vector<int>& p_object = prim_object;
BoundBox bounds = BoundBox::empty;
@@ -358,10 +397,12 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range)
if(range.start() + num == prim_index.size()) {
assert(params.use_spatial_split);
+ p_segment.push_back(ref.prim_segment());
p_index.push_back(ref.prim_index());
p_object.push_back(ref.prim_object());
}
else {
+ p_segment[range.start() + num] = ref.prim_segment();
p_index[range.start() + num] = ref.prim_index();
p_object[range.start() + num] = ref.prim_object();
}
diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h
index 44ef918b326..3df4da1739a 100644
--- a/intern/cycles/bvh/bvh_build.h
+++ b/intern/cycles/bvh/bvh_build.h
@@ -44,6 +44,7 @@ public:
/* Constructor/Destructor */
BVHBuild(
const vector<Object*>& objects,
+ vector<int>& prim_segment,
vector<int>& prim_index,
vector<int>& prim_object,
const BVHParams& params,
@@ -87,6 +88,7 @@ protected:
int num_original_references;
/* output primitive indexes and objects */
+ vector<int>& prim_segment;
vector<int>& prim_index;
vector<int>& prim_object;
diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h
index a78496d841d..f7bc79f71e6 100644
--- a/intern/cycles/bvh/bvh_params.h
+++ b/intern/cycles/bvh/bvh_params.h
@@ -98,19 +98,22 @@ class BVHReference
public:
__forceinline BVHReference() {}
- __forceinline BVHReference(const BoundBox& bounds_, int prim_index_, int prim_object_)
+ __forceinline BVHReference(const BoundBox& bounds_, int prim_index_, int prim_object_, int prim_segment)
: rbounds(bounds_)
{
rbounds.min.w = __int_as_float(prim_index_);
rbounds.max.w = __int_as_float(prim_object_);
+ segment = prim_segment;
}
__forceinline const BoundBox& bounds() const { return rbounds; }
__forceinline int prim_index() const { return __float_as_int(rbounds.min.w); }
__forceinline int prim_object() const { return __float_as_int(rbounds.max.w); }
+ __forceinline int prim_segment() const { return segment; }
protected:
BoundBox rbounds;
+ uint segment;
};
/* BVH Range
diff --git a/intern/cycles/bvh/bvh_sort.cpp b/intern/cycles/bvh/bvh_sort.cpp
index bef384be592..91994be5b96 100644
--- a/intern/cycles/bvh/bvh_sort.cpp
+++ b/intern/cycles/bvh/bvh_sort.cpp
@@ -43,6 +43,8 @@ public:
else if(ra.prim_object() > rb.prim_object()) return false;
else if(ra.prim_index() < rb.prim_index()) return true;
else if(ra.prim_index() > rb.prim_index()) return false;
+ else if(ra.prim_segment() < rb.prim_segment()) return true;
+ else if(ra.prim_segment() > rb.prim_segment()) return false;
return false;
}
diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp
index 263c5834428..03ff69d7b6d 100644
--- a/intern/cycles/bvh/bvh_split.cpp
+++ b/intern/cycles/bvh/bvh_split.cpp
@@ -252,14 +252,41 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH
/* loop over vertices/edges. */
Object *ob = builder->objects[ref.prim_object()];
const Mesh *mesh = ob->mesh;
- const int *inds = mesh->triangles[ref.prim_index()].v;
- const float3 *verts = &mesh->verts[0];
- const float3* v1 = &verts[inds[2]];
-
- for(int i = 0; i < 3; i++) {
- const float3* v0 = v1;
- int vindex = inds[i];
- v1 = &verts[vindex];
+
+ if (ref.prim_segment() == ~0) {
+ const int *inds = mesh->triangles[ref.prim_index()].v;
+ const float3 *verts = &mesh->verts[0];
+ const float3* v1 = &verts[inds[2]];
+
+ for(int i = 0; i < 3; i++) {
+ const float3* v0 = v1;
+ int vindex = inds[i];
+ v1 = &verts[vindex];
+ float v0p = (*v0)[dim];
+ float v1p = (*v1)[dim];
+
+ /* insert vertex to the boxes it belongs to. */
+ if(v0p <= pos)
+ left_bounds.grow(*v0);
+
+ if(v0p >= pos)
+ right_bounds.grow(*v0);
+
+ /* edge intersects the plane => insert intersection to both boxes. */
+ if((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
+ float3 t = lerp(*v0, *v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
+ left_bounds.grow(t);
+ right_bounds.grow(t);
+ }
+ }
+ }
+ else {
+ /* curve split: NOTE - Currently ignores curve width and needs to be fixed.*/
+ const int k0 = mesh->curves[ref.prim_index()].first_key + ref.prim_segment();
+ const int k1 = k0 + 1;
+ const float3* v0 = &mesh->curve_keys[k0].co;
+ const float3* v1 = &mesh->curve_keys[k1].co;
+
float v0p = (*v0)[dim];
float v1p = (*v1)[dim];
@@ -270,6 +297,12 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH
if(v0p >= pos)
right_bounds.grow(*v0);
+ if(v1p <= pos)
+ left_bounds.grow(*v1);
+
+ if(v1p >= pos)
+ right_bounds.grow(*v1);
+
/* edge intersects the plane => insert intersection to both boxes. */
if((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
float3 t = lerp(*v0, *v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
@@ -284,9 +317,9 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH
left_bounds.intersect(ref.bounds());
right_bounds.intersect(ref.bounds());
- /* set referecnes */
- left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object());
- right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object());
+ /* set references */
+ left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object(), ref.prim_segment());
+ right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object(), ref.prim_segment());
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index 9840687b76a..7b31b9ba157 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -84,6 +84,7 @@ public:
/* info */
DeviceInfo info;
virtual const string& error_message() { return error_msg; }
+ bool have_error() { return !error_message().empty(); }
/* statistics */
Stats &stats;
diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp
index 14f8cfa8767..040f3044457 100644
--- a/intern/cycles/device/device_cuda.cpp
+++ b/intern/cycles/device/device_cuda.cpp
@@ -124,7 +124,7 @@ public:
if(error_msg == "") \
error_msg = message; \
fprintf(stderr, "%s\n", message.c_str()); \
- cuda_abort(); \
+ /*cuda_abort();*/ \
} \
}
@@ -326,7 +326,8 @@ public:
void mem_copy_to(device_memory& mem)
{
cuda_push_context();
- cuda_assert(cuMemcpyHtoD(cuda_device_ptr(mem.device_pointer), (void*)mem.data_pointer, mem.memory_size()))
+ if(mem.device_pointer)
+ cuda_assert(cuMemcpyHtoD(cuda_device_ptr(mem.device_pointer), (void*)mem.data_pointer, mem.memory_size()))
cuda_pop_context();
}
@@ -336,8 +337,13 @@ public:
size_t size = elem*w*h;
cuda_push_context();
- cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset,
- (CUdeviceptr)((uchar*)mem.device_pointer + offset), size))
+ if(mem.device_pointer) {
+ cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset,
+ (CUdeviceptr)((uchar*)mem.device_pointer + offset), size))
+ }
+ else {
+ memset((char*)mem.data_pointer + offset, 0, size);
+ }
cuda_pop_context();
}
@@ -346,7 +352,8 @@ public:
memset((void*)mem.data_pointer, 0, mem.memory_size());
cuda_push_context();
- cuda_assert(cuMemsetD8(cuda_device_ptr(mem.device_pointer), 0, mem.memory_size()))
+ if(mem.device_pointer)
+ cuda_assert(cuMemsetD8(cuda_device_ptr(mem.device_pointer), 0, mem.memory_size()))
cuda_pop_context();
}
@@ -390,13 +397,18 @@ public:
default: assert(0); return;
}
- CUtexref texref;
+ CUtexref texref = NULL;
cuda_push_context();
cuda_assert(cuModuleGetTexRef(&texref, cuModule, name))
+ if(!texref) {
+ cuda_pop_context();
+ return;
+ }
+
if(interpolation) {
- CUarray handle;
+ CUarray handle = NULL;
CUDA_ARRAY_DESCRIPTOR desc;
desc.Width = mem.data_width;
@@ -406,6 +418,11 @@ public:
cuda_assert(cuArrayCreate(&handle, &desc))
+ if(!handle) {
+ cuda_pop_context();
+ return;
+ }
+
if(mem.data_height > 1) {
CUDA_MEMCPY2D param;
memset(&param, 0, sizeof(param));
@@ -481,6 +498,9 @@ public:
void path_trace(RenderTile& rtile, int sample)
{
+ if(have_error())
+ return;
+
cuda_push_context();
CUfunction cuPathTrace;
@@ -546,6 +566,9 @@ public:
void tonemap(DeviceTask& task, device_ptr buffer, device_ptr rgba)
{
+ if(have_error())
+ return;
+
cuda_push_context();
CUfunction cuFilmConvert;
@@ -615,6 +638,9 @@ public:
void shader(DeviceTask& task)
{
+ if(have_error())
+ return;
+
cuda_push_context();
CUfunction cuDisplace;
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index fde881c0a06..6d5b9a063a0 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -20,12 +20,12 @@ set(SRC
set(SRC_HEADERS
kernel.h
kernel_accumulate.h
- kernel_attribute.h
kernel_bvh.h
kernel_camera.h
kernel_compat_cpu.h
kernel_compat_cuda.h
kernel_compat_opencl.h
+ kernel_curve.h
kernel_differential.h
kernel_displace.h
kernel_emission.h
@@ -37,6 +37,7 @@ set(SRC_HEADERS
kernel_object.h
kernel_passes.h
kernel_path.h
+ kernel_primitive.h
kernel_projection.h
kernel_random.h
kernel_shader.h
diff --git a/intern/cycles/kernel/kernel_attribute.h b/intern/cycles/kernel/kernel_attribute.h
deleted file mode 100644
index b7ad731c883..00000000000
--- a/intern/cycles/kernel/kernel_attribute.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2011, Blender Foundation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef __KERNEL_ATTRIBUTE_CL__
-#define __KERNEL_ATTRIBUTE_CL__
-
-CCL_NAMESPACE_BEGIN
-
-/* note: declared in kernel.h, have to add it here because kernel.h is not available */
-bool kernel_osl_use(KernelGlobals *kg);
-
-__device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id)
-{
-#ifdef __OSL__
- if (kg->osl) {
- return OSLShader::find_attribute(kg, sd, id);
- }
- else
-#endif
- {
- /* for SVM, find attribute by unique id */
- uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride;
- uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
-
- while(attr_map.x != id)
- attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset);
-
- /* return result */
- return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
- }
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __KERNEL_ATTRIBUTE_CL__ */
diff --git a/intern/cycles/kernel/kernel_bvh.h b/intern/cycles/kernel/kernel_bvh.h
index d70485fd6cf..2cb29207b05 100644
--- a/intern/cycles/kernel/kernel_bvh.h
+++ b/intern/cycles/kernel/kernel_bvh.h
@@ -205,6 +205,145 @@ __device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *ise
}
}
+#ifdef __HAIR__
+__device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
+ float3 P, float3 idir, uint visibility, int object, int curveAddr, int segment)
+{
+ /* curve Intersection check */
+
+ int flags = kernel_data.curve_kernel_data.curveflags;
+
+ int prim = kernel_tex_fetch(__prim_index, curveAddr);
+ float4 v00 = kernel_tex_fetch(__curves, prim);
+
+ int k0 = __float_as_int(v00.x) + segment;
+ int k1 = k0 + 1;
+
+ 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);
+ float3 p1 = float4_to_float3(P1);
+ float3 p2 = float4_to_float3(P2);
+ float3 dif = P - p1;
+ float3 dir = 1.0f/idir;
+
+ float sp_r = mr + 0.5f * l;
+ float3 sphere_dif = P - ((p1 + p2) * 0.5f);
+ float sphere_b = dot(dir,sphere_dif);
+ sphere_dif = sphere_dif - sphere_b * dir;
+ sphere_b = dot(dir,sphere_dif);
+ float sdisc = sphere_b * sphere_b - len_squared(sphere_dif) + sp_r * sp_r;
+ if(sdisc < 0.0f)
+ return;
+
+ /* obtain parameters and test midpoint distance for suitable modes*/
+ float3 tg = (p2 - p1) / l;
+ float gd = (r2 - r1) / l;
+ float dirz = dot(dir,tg);
+ float difz = dot(dif,tg);
+
+ float a = 1.0f - (dirz*dirz*(1 + gd*gd));
+ float halfb = (dot(dir,dif) - dirz*(difz + gd*(difz*gd + r1)));
+
+ float tcentre = -halfb/a;
+ float zcentre = difz + (dirz * tcentre);
+
+ if((tcentre > isect->t) && !(flags & CURVE_KN_ACCURATE))
+ return;
+ if((zcentre < 0 || zcentre > l) && !(flags & CURVE_KN_ACCURATE) && !(flags & CURVE_KN_INTERSECTCORRECTION))
+ return;
+
+ /* test minimum separation*/
+ float3 cprod = cross(tg, dir);
+ float3 cprod2 = cross(tg, dif);
+ float cprodsq = len_squared(cprod);
+ float cprod2sq = len_squared(cprod2);
+ float distscaled = dot(cprod,dif);
+
+ if(cprodsq == 0)
+ distscaled = cprod2sq;
+ else
+ distscaled = (distscaled*distscaled)/cprodsq;
+
+ if(distscaled > mr*mr)
+ return;
+
+ /* calculate true intersection*/
+ float3 tdif = P - p1 + tcentre * dir;
+ float tdifz = dot(tdif,tg);
+ float tb = 2*(dot(dir,tdif) - dirz*(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*a*tc;
+
+ if (td < 0.0f)
+ return;
+
+ float rootd = 0.0f;
+ float correction = 0.0f;
+ if(flags & CURVE_KN_ACCURATE) {
+ rootd = sqrtf(td);
+ correction = ((-tb - rootd)/(2*a));
+ }
+
+ float t = tcentre + correction;
+
+ if(t < isect->t) {
+
+ if(flags & CURVE_KN_INTERSECTCORRECTION) {
+ rootd = sqrtf(td);
+ correction = ((-tb - rootd)/(2*a));
+ t = tcentre + correction;
+ }
+
+ float z = zcentre + (dirz * correction);
+ bool backface = false;
+
+ if(flags & CURVE_KN_BACKFACING && (t < 0.0f || z < 0 || z > l)) {
+ backface = true;
+ correction = ((-tb + rootd)/(2*a));
+ t = tcentre + correction;
+ z = zcentre + (dirz * correction);
+ }
+
+ if(t > 0.0f && t < isect->t && z >= 0 && z <= l) {
+
+ if (flags & CURVE_KN_ENCLOSEFILTER) {
+
+ float enc_ratio = kernel_data.curve_kernel_data.encasing_ratio;
+ if((dot(P - p1, tg) > -r1 * enc_ratio) && (dot(P - p2, tg) < r2 * enc_ratio)) {
+ float a2 = 1.0f - (dirz*dirz*(1 + gd*gd*enc_ratio*enc_ratio));
+ float c2 = dot(dif,dif) - difz * difz * (1 + gd*gd*enc_ratio*enc_ratio) - r1*r1*enc_ratio*enc_ratio - 2*r1*difz*gd*enc_ratio;
+ if(a2*c2 < 0.0f)
+ return;
+ }
+ }
+
+#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 = z/l;
+ isect->v = td/(4*a*a);
+ isect->t = t;
+
+ if(backface)
+ isect->u = -isect->u;
+ }
+ }
+ }
+}
+#endif
+
__device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
{
/* traversal stack in CUDA thread-local memory */
@@ -281,10 +420,16 @@ __device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint
nodeAddr = traversalStack[stackPtr];
--stackPtr;
- /* triangle intersection */
+ /* primitive intersection */
while(primAddr < primAddr2) {
- /* intersect ray against triangle */
- bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
+ /* 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);
+ else
+#endif
+ bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
/* shadow ray early termination */
if(visibility == PATH_RAY_SHADOW_OPAQUE && isect->prim != ~0)
@@ -401,10 +546,16 @@ __device_inline bool bvh_intersect_motion(KernelGlobals *kg, const Ray *ray, con
nodeAddr = traversalStack[stackPtr];
--stackPtr;
- /* triangle intersection */
+ /* primitive intersection */
while(primAddr < primAddr2) {
- /* intersect ray against triangle */
- bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
+ /* 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);
+ else
+#endif
+ bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
/* shadow ray early termination */
if(visibility == PATH_RAY_SHADOW_OPAQUE && isect->prim != ~0)
@@ -457,12 +608,15 @@ __device_inline float3 ray_offset(float3 P, float3 Ng)
{
#ifdef __INTERSECTION_REFINE__
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 int epsilon_i = 32;
float3 res;
/* x component */
- if(fabsf(P.x) < epsilon_f) {
+ if(fabsf(P.x) < epsilon_test) {
res.x = P.x + Ng.x*epsilon_f;
}
else {
@@ -472,7 +626,7 @@ __device_inline float3 ray_offset(float3 P, float3 Ng)
}
/* y component */
- if(fabsf(P.y) < epsilon_f) {
+ if(fabsf(P.y) < epsilon_test) {
res.y = P.y + Ng.y*epsilon_f;
}
else {
@@ -482,7 +636,7 @@ __device_inline float3 ray_offset(float3 P, float3 Ng)
}
/* z component */
- if(fabsf(P.z) < epsilon_f) {
+ if(fabsf(P.z) < epsilon_test) {
res.z = P.z + Ng.z*epsilon_f;
}
else {
@@ -542,5 +696,105 @@ __device_inline float3 bvh_triangle_refine(KernelGlobals *kg, ShaderData *sd, co
#endif
}
+#ifdef __HAIR__
+__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;
+ float3 P = ray->P;
+ float3 D = ray->D;
+
+ if(isect->object != ~0) {
+#ifdef __OBJECT_MOTION__
+ Transform tfm = sd->ob_itfm;
+#else
+ Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
+#endif
+
+ P = transform_point(&tfm, P);
+ D = transform_direction(&tfm, D*t);
+ D = normalize_len(D, &t);
+ }
+
+ int prim = kernel_tex_fetch(__prim_index, isect->prim);
+ float4 v00 = kernel_tex_fetch(__curves, prim);
+
+ int k0 = __float_as_int(v00.x) + isect->segment;
+ int k1 = k0 + 1;
+
+ 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;
+ 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);
+
+ #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 = normalize(sd->Ng);
+ 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;
+
+ 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;
+ 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__
+ /* dPdu/dPdv */
+ sd->dPdu = tg;
+ sd->dPdv = cross(tg,sd->Ng);
+ #endif
+
+ if(isect->object != ~0) {
+#ifdef __OBJECT_MOTION__
+ Transform tfm = sd->ob_tfm;
+#else
+ Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
+#endif
+
+ P = transform_point(&tfm, P);
+ }
+
+ return P;
+}
+#endif
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_curve.h b/intern/cycles/kernel/kernel_curve.h
new file mode 100644
index 00000000000..e065717888c
--- /dev/null
+++ b/intern/cycles/kernel/kernel_curve.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef __HAIR__
+
+/* curve attributes */
+
+__device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
+{
+ if(elem == ATTR_ELEMENT_CURVE) {
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx) *dx = 0.0f;
+ if(dy) *dy = 0.0f;
+#endif
+
+ return kernel_tex_fetch(__attributes_float, offset + sd->prim);
+ }
+ else if(elem == ATTR_ELEMENT_CURVE_KEY) {
+ float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
+ int k0 = __float_as_int(curvedata.x) + sd->segment;
+ int k1 = k0 + 1;
+
+ float f0 = kernel_tex_fetch(__attributes_float, offset + k0);
+ float f1 = kernel_tex_fetch(__attributes_float, offset + k1);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx) *dx = sd->du.dx*(f1 - f0);
+ if(dy) *dy = 0.0f;
+#endif
+
+ return (1.0f - sd->u)*f0 + sd->u*f1;
+ }
+ else {
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx) *dx = 0.0f;
+ if(dy) *dy = 0.0f;
+#endif
+
+ return 0.0f;
+ }
+}
+
+__device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
+{
+ if(elem == ATTR_ELEMENT_CURVE) {
+ /* idea: we can't derive any useful differentials here, but for tiled
+ * mipmap image caching it would be useful to avoid reading the highest
+ * detail level always. maybe a derivative based on the hair density
+ * could be computed somehow? */
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
+ if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
+#endif
+
+ return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim));
+ }
+ else if(elem == ATTR_ELEMENT_CURVE_KEY) {
+ float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
+ int k0 = __float_as_int(curvedata.x) + sd->segment;
+ int k1 = k0 + 1;
+
+ float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k0));
+ float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k1));
+
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx) *dx = sd->du.dx*(f1 - f0);
+ if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
+#endif
+
+ return (1.0f - sd->u)*f0 + sd->u*f1;
+ }
+ else {
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
+ if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
+#endif
+
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+}
+
+/* hair info node functions */
+
+__device float curve_thickness(KernelGlobals *kg, ShaderData *sd)
+{
+ float r = 0.0f;
+
+ if(sd->segment != ~0) {
+ float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
+ int k0 = __float_as_int(curvedata.x) + sd->segment;
+ int k1 = k0 + 1;
+
+ float4 P1 = kernel_tex_fetch(__curve_keys, k0);
+ float4 P2 = kernel_tex_fetch(__curve_keys, k1);
+ r = (P2.w - P1.w) * sd->u + P1.w;
+ }
+
+ return r*2.0f;
+}
+
+__device float3 curve_tangent_normal(KernelGlobals *kg, ShaderData *sd)
+{
+ float3 tgN = make_float3(0.0f,0.0f,0.0f);
+
+ if(sd->segment != ~0) {
+ float normalmix = kernel_data.curve_kernel_data.normalmix;
+
+ tgN = -(-sd->I - sd->dPdu * (dot(sd->dPdu,-sd->I) * normalmix / len_squared(sd->dPdu)));
+ tgN = normalize(tgN);
+
+ /* need to find suitable scaled gd for corrected normal */
+#if 0
+ if (kernel_data.curve_kernel_data.use_tangent_normal_correction)
+ tgN = normalize(tgN - gd * sd->dPdu);
+#endif
+ }
+
+ return tgN;
+}
+
+#endif
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index e56633c9358..d5506ad1dd0 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -47,7 +47,13 @@ __device float3 direct_emissive_eval(KernelGlobals *kg, float rando,
else
#endif
{
- shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time);
+#ifdef __HAIR__
+ if(ls->type == LIGHT_STRAND)
+ shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time, ls->prim);
+ else
+#endif
+ shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time);
+
ls->Ng = sd.Ng;
/* no path flag, we're evaluating this for all closures. that's weak but
@@ -150,7 +156,11 @@ __device float3 indirect_emission(KernelGlobals *kg, ShaderData *sd, float t, in
/* evaluate emissive closure */
float3 L = shader_emissive_eval(kg, sd);
+#ifdef __HAIR__
+ if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_SAMPLE_AS_LIGHT) && (sd->segment == ~0)) {
+#else
if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_SAMPLE_AS_LIGHT)) {
+#endif
/* multiple importance sampling, get triangle light pdf,
* and compute weight with respect to BSDF pdf */
float pdf = triangle_light_pdf(kg, sd->Ng, sd->I, t);
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 97ae2d3db87..ea0e4d014fe 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -326,6 +326,61 @@ __device float triangle_light_pdf(KernelGlobals *kg,
return (t*t*kernel_data.integrator.pdf_triangles)/cos_pi;
}
+#ifdef __HAIR__
+/* Strand Light */
+
+__device void curve_segment_light_sample(KernelGlobals *kg, int prim, int object,
+ int segment, float randu, float randv, float time, LightSample *ls)
+{
+ /* this strand code needs completion */
+ float4 v00 = kernel_tex_fetch(__curves, prim);
+
+ int k0 = __float_as_int(v00.x) + segment;
+ int k1 = k0 + 1;
+
+ 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;
+ float3 tg = float4_to_float3(P2 - P1) / l;
+ float3 xc = make_float3(tg.x * tg.z, tg.y * tg.z, -(tg.x * tg.x + tg.y * tg.y));
+ if (dot(xc, xc) == 0.0f)
+ xc = make_float3(tg.x * tg.y, -(tg.x * tg.x + tg.z * tg.z), tg.z * tg.y);
+ xc = normalize(xc);
+ float3 yc = cross(tg, xc);
+ float gd = ((r2 - r1)/l);
+
+ /* normal currently ignores gradient */
+ ls->Ng = sinf(2 * M_PI_F * randv) * xc + cosf(2 * M_PI_F * randv) * yc;
+ ls->P = randu * l * tg + (gd * l + r1) * ls->Ng;
+ ls->object = object;
+ ls->prim = prim;
+ ls->t = 0.0f;
+ ls->type = LIGHT_STRAND;
+ ls->eval_fac = 1.0f;
+ ls->shader = __float_as_int(v00.z);
+
+#ifdef __INSTANCING__
+ /* instance transform */
+ if(ls->object >= 0) {
+#ifdef __OBJECT_MOTION__
+ Transform itfm;
+ Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm);
+#else
+ Transform tfm = object_fetch_transform(kg, ls->object, OBJECT_TRANSFORM);
+ Transform itfm = object_fetch_transform(kg, ls->object, OBJECT_INVERSE_TRANSFORM);
+#endif
+
+ ls->P = transform_point(&tfm, ls->P);
+ ls->Ng = normalize(transform_direction(&tfm, ls->Ng));
+ }
+#endif
+}
+#endif
+
/* Light Distribution */
__device int light_distribution_sample(KernelGlobals *kg, float randt)
@@ -365,10 +420,19 @@ __device void light_sample(KernelGlobals *kg, float randt, float randu, float ra
/* fetch light data */
float4 l = kernel_tex_fetch(__light_distribution, index);
int prim = __float_as_int(l.y);
+#ifdef __HAIR__
+ int segment = __float_as_int(l.z);
+#endif
if(prim >= 0) {
int object = __float_as_int(l.w);
- triangle_light_sample(kg, prim, object, randu, randv, time, ls);
+
+#ifdef __HAIR__
+ if (segment != ~0)
+ curve_segment_light_sample(kg, prim, object, segment, randu, randv, time, ls);
+ else
+#endif
+ triangle_light_sample(kg, prim, object, randu, randv, time, ls);
}
else {
int point = -prim-1;
diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h
index 7f8b611ba14..727639386ed 100644
--- a/intern/cycles/kernel/kernel_passes.h
+++ b/intern/cycles/kernel/kernel_passes.h
@@ -70,11 +70,11 @@ __device_inline void kernel_write_data_passes(KernelGlobals *kg, __global float
kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, sample, normal);
}
if(flag & PASS_UV) {
- float3 uv = triangle_uv(kg, sd);
+ float3 uv = primitive_uv(kg, sd);
kernel_write_pass_float3(buffer + kernel_data.film.pass_uv, sample, uv);
}
if(flag & PASS_MOTION) {
- float4 speed = triangle_motion_vector(kg, sd);
+ float4 speed = primitive_motion_vector(kg, sd);
kernel_write_pass_float4(buffer + kernel_data.film.pass_motion, sample, speed);
kernel_write_pass_float(buffer + kernel_data.film.pass_motion_weight, sample, 1.0f);
}
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 8da21751cbe..20feaf50a2e 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -24,9 +24,10 @@
#include "kernel_montecarlo.h"
#include "kernel_projection.h"
#include "kernel_object.h"
-#include "kernel_attribute.h"
-#include "kernel_projection.h"
#include "kernel_triangle.h"
+#include "kernel_curve.h"
+#include "kernel_primitive.h"
+#include "kernel_projection.h"
#ifdef __QBVH__
#include "kernel_qbvh.h"
#else
diff --git a/intern/cycles/kernel/kernel_primitive.h b/intern/cycles/kernel/kernel_primitive.h
new file mode 100644
index 00000000000..0851af21e87
--- /dev/null
+++ b/intern/cycles/kernel/kernel_primitive.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KERNEL_ATTRIBUTE_CL__
+#define __KERNEL_ATTRIBUTE_CL__
+
+CCL_NAMESPACE_BEGIN
+
+/* attribute lookup */
+
+__device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id, AttributeElement *elem)
+{
+ if(sd->object == ~0)
+ return (int)ATTR_STD_NOT_FOUND;
+
+#ifdef __OSL__
+ if (kg->osl) {
+ return OSLShader::find_attribute(kg, sd, id, elem);
+ }
+ else
+#endif
+ {
+ /* for SVM, find attribute by unique id */
+ uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride;
+#ifdef __HAIR__
+ attr_offset = (sd->segment == ~0)? attr_offset: attr_offset + ATTR_PRIM_CURVE;
+#endif
+ uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+
+ while(attr_map.x != id) {
+ attr_offset += ATTR_PRIM_TYPES;
+ attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+ }
+
+ *elem = (AttributeElement)attr_map.y;
+
+ /* return result */
+ return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
+ }
+}
+
+__device float primitive_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
+{
+#ifdef __HAIR__
+ if(sd->segment == ~0)
+#endif
+ return triangle_attribute_float(kg, sd, elem, offset, dx, dy);
+#ifdef __HAIR__
+ else
+ return curve_attribute_float(kg, sd, elem, offset, dx, dy);
+#endif
+}
+
+__device float3 primitive_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
+{
+#ifdef __HAIR__
+ if(sd->segment == ~0)
+#endif
+ return triangle_attribute_float3(kg, sd, elem, offset, dx, dy);
+#ifdef __HAIR__
+ else
+ return curve_attribute_float3(kg, sd, elem, offset, dx, dy);
+#endif
+}
+
+__device float3 primitive_uv(KernelGlobals *kg, ShaderData *sd)
+{
+ AttributeElement elem_uv;
+ int offset_uv = find_attribute(kg, sd, ATTR_STD_UV, &elem_uv);
+
+ if(offset_uv == ATTR_STD_NOT_FOUND)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ float3 uv = primitive_attribute_float3(kg, sd, elem_uv, offset_uv, NULL, NULL);
+ uv.z = 1.0f;
+ return uv;
+}
+
+__device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
+{
+#ifdef __HAIR__
+ if(sd->segment != ~0)
+ return normalize(sd->dPdu);
+#endif
+
+ /* try to create spherical tangent from generated coordinates */
+ AttributeElement attr_elem;
+ int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED, &attr_elem);
+
+ if(attr_offset != ATTR_STD_NOT_FOUND) {
+ 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)));;
+ }
+ else {
+ /* otherwise use surface derivatives */
+ return normalize(sd->dPdu);
+ }
+}
+
+/* motion */
+
+__device float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd)
+{
+ float3 motion_pre = sd->P, motion_post = sd->P;
+
+ /* deformation motion */
+ AttributeElement elem_pre, elem_post;
+ int offset_pre = find_attribute(kg, sd, ATTR_STD_MOTION_PRE, &elem_pre);
+ int offset_post = find_attribute(kg, sd, ATTR_STD_MOTION_POST, &elem_post);
+
+ if(offset_pre != ATTR_STD_NOT_FOUND)
+ motion_pre = primitive_attribute_float3(kg, sd, elem_pre, offset_pre, NULL, NULL);
+ if(offset_post != ATTR_STD_NOT_FOUND)
+ motion_post = primitive_attribute_float3(kg, sd, elem_post, offset_post, NULL, NULL);
+
+ /* object motion. note that depending on the mesh having motion vectors, this
+ * transformation was set match the world/object space of motion_pre/post */
+ Transform tfm;
+
+ tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE);
+ motion_pre = transform_point(&tfm, motion_pre);
+
+ tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST);
+ motion_post = transform_point(&tfm, motion_post);
+
+ float3 P;
+
+ /* camera motion, for perspective/orthographic motion.pre/post will be a
+ * world-to-raster matrix, for panorama it's world-to-camera */
+ if (kernel_data.cam.type != CAMERA_PANORAMA) {
+ tfm = kernel_data.cam.worldtoraster;
+ P = transform_perspective(&tfm, sd->P);
+
+ tfm = kernel_data.cam.motion.pre;
+ motion_pre = transform_perspective(&tfm, motion_pre);
+
+ tfm = kernel_data.cam.motion.post;
+ motion_post = transform_perspective(&tfm, motion_post);
+ }
+ else {
+ tfm = kernel_data.cam.worldtocamera;
+ P = normalize(transform_point(&tfm, sd->P));
+ P = float2_to_float3(direction_to_panorama(kg, P));
+ P.x *= kernel_data.cam.width;
+ P.y *= kernel_data.cam.height;
+
+ tfm = kernel_data.cam.motion.pre;
+ motion_pre = normalize(transform_point(&tfm, motion_pre));
+ motion_pre = float2_to_float3(direction_to_panorama(kg, motion_pre));
+ motion_pre.x *= kernel_data.cam.width;
+ motion_pre.y *= kernel_data.cam.height;
+
+ tfm = kernel_data.cam.motion.post;
+ motion_post = normalize(transform_point(&tfm, motion_post));
+ motion_post = float2_to_float3(direction_to_panorama(kg, motion_post));
+ motion_post.x *= kernel_data.cam.width;
+ motion_post.y *= kernel_data.cam.height;
+ }
+
+ motion_pre = motion_pre - P;
+ motion_post = P - motion_post;
+
+ return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __KERNEL_ATTRIBUTE_CL__ */
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 47b4d02e5bf..0a5a2ab54b0 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -56,24 +56,11 @@ __device_noinline void shader_setup_object_transforms(KernelGlobals *kg, ShaderD
__device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
const Intersection *isect, const Ray *ray)
{
- /* fetch triangle data */
- int prim = kernel_tex_fetch(__prim_index, isect->prim);
- float4 Ns = kernel_tex_fetch(__tri_normal, prim);
- float3 Ng = make_float3(Ns.x, Ns.y, Ns.z);
- int shader = __float_as_int(Ns.w);
-
- /* triangle */
#ifdef __INSTANCING__
sd->object = (isect->object == ~0)? kernel_tex_fetch(__prim_object, isect->prim): isect->object;
#endif
- sd->prim = prim;
-#ifdef __UV__
- sd->u = isect->u;
- sd->v = isect->v;
-#endif
- sd->flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*2);
- sd->flag |= kernel_tex_fetch(__object_flag, sd->object);
+ sd->flag = kernel_tex_fetch(__object_flag, sd->object);
/* matrices and time */
#ifdef __OBJECT_MOTION__
@@ -81,23 +68,63 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
sd->time = ray->time;
#endif
- /* vectors */
- sd->P = bvh_triangle_refine(kg, sd, isect, ray);
- sd->Ng = Ng;
- sd->N = Ng;
- sd->I = -ray->D;
- sd->shader = shader;
+ sd->prim = kernel_tex_fetch(__prim_index, isect->prim);
sd->ray_length = isect->t;
- /* smooth normal */
- if(sd->shader & SHADER_SMOOTH_NORMAL)
- sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
+#ifdef __HAIR__
+ if(kernel_tex_fetch(__prim_segment, isect->prim) != ~0) {
+ /* Strand Shader setting*/
+ float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
+
+ sd->shader = __float_as_int(curvedata.z);
+ sd->segment = isect->segment;
+
+ float tcorr = isect->t;
+ if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_POSTINTERSECTCORRECTION) {
+ tcorr = (isect->u < 0)? tcorr + sqrtf(isect->v) : tcorr - sqrtf(isect->v);
+ sd->ray_length = tcorr;
+ }
+
+ sd->P = bvh_curve_refine(kg, sd, isect, ray, tcorr);
+ }
+ else {
+#endif
+ /* fetch triangle data */
+ float4 Ns = kernel_tex_fetch(__tri_normal, sd->prim);
+ float3 Ng = make_float3(Ns.x, Ns.y, Ns.z);
+ sd->shader = __float_as_int(Ns.w);
+
+#ifdef __HAIR__
+ sd->segment = ~0;
+#endif
+
+#ifdef __UV__
+ sd->u = isect->u;
+ sd->v = isect->v;
+#endif
+
+ /* vectors */
+ sd->P = bvh_triangle_refine(kg, sd, isect, ray);
+ sd->Ng = Ng;
+ sd->N = Ng;
+
+ /* smooth normal */
+ if(sd->shader & SHADER_SMOOTH_NORMAL)
+ sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
#ifdef __DPDU__
- /* dPdu/dPdv */
- triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
+ /* dPdu/dPdv */
+ triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
+#endif
+
+#ifdef __HAIR__
+ }
#endif
+ sd->I = -ray->D;
+
+ sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
+
#ifdef __INSTANCING__
if(isect->object != ~0) {
/* instance transform */
@@ -135,7 +162,7 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
__device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
const float3 P, const float3 Ng, const float3 I,
- int shader, int object, int prim, float u, float v, float t, float time)
+ int shader, int object, int prim, float u, float v, float t, float time, int segment = ~0)
{
/* vectors */
sd->P = P;
@@ -143,11 +170,15 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
sd->Ng = Ng;
sd->I = I;
sd->shader = shader;
+#ifdef __HAIR__
+ sd->segment = segment;
+#endif
/* primitive */
#ifdef __INSTANCING__
sd->object = object;
#endif
+ /* currently no access to bvh prim index for strand sd->prim - this will cause errors with needs fixing*/
sd->prim = prim;
#ifdef __UV__
sd->u = u;
@@ -183,8 +214,13 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
#endif
/* smooth normal */
+#ifdef __HAIR__
+ if(sd->shader & SHADER_SMOOTH_NORMAL && sd->segment == ~0) {
+ sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
+#else
if(sd->shader & SHADER_SMOOTH_NORMAL) {
sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
+#endif
#ifdef __INSTANCING__
if(instanced)
@@ -194,10 +230,17 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
#ifdef __DPDU__
/* dPdu/dPdv */
+#ifdef __HAIR__
+ if(sd->prim == ~0 || sd->segment != ~0) {
+ sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
+ sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
+ }
+#else
if(sd->prim == ~0) {
sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
}
+#endif
else {
triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
@@ -279,6 +322,9 @@ __device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData
sd->object = ~0;
#endif
sd->prim = ~0;
+#ifdef __HAIR__
+ sd->segment = ~0;
+#endif
#ifdef __UV__
sd->u = 0.0f;
sd->v = 0.0f;
@@ -732,8 +778,20 @@ __device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd, Shader
__device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect)
{
int prim = kernel_tex_fetch(__prim_index, isect->prim);
- float4 Ns = kernel_tex_fetch(__tri_normal, prim);
- int shader = __float_as_int(Ns.w);
+ int shader = 0;
+
+#ifdef __HAIR__
+ if(kernel_tex_fetch(__prim_segment, isect->prim) == ~0) {
+#endif
+ float4 Ns = kernel_tex_fetch(__tri_normal, prim);
+ shader = __float_as_int(Ns.w);
+#ifdef __HAIR__
+ }
+ else {
+ float4 str = kernel_tex_fetch(__curves, prim);
+ shader = __float_as_int(str.z);
+ }
+#endif
int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*2);
return (flag & SD_HAS_SURFACE_TRANSPARENT) != 0;
diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h
index 29f6b3f072c..e27de95e7ab 100644
--- a/intern/cycles/kernel/kernel_textures.h
+++ b/intern/cycles/kernel/kernel_textures.h
@@ -27,6 +27,7 @@
/* bvh */
KERNEL_TEX(float4, texture_float4, __bvh_nodes)
KERNEL_TEX(float4, texture_float4, __tri_woop)
+KERNEL_TEX(uint, texture_uint, __prim_segment)
KERNEL_TEX(uint, texture_uint, __prim_visibility)
KERNEL_TEX(uint, texture_uint, __prim_index)
KERNEL_TEX(uint, texture_uint, __prim_object)
@@ -42,6 +43,10 @@ KERNEL_TEX(float4, texture_float4, __tri_vnormal)
KERNEL_TEX(float4, texture_float4, __tri_vindex)
KERNEL_TEX(float4, texture_float4, __tri_verts)
+/* curves */
+KERNEL_TEX(float4, texture_float4, __curves)
+KERNEL_TEX(float4, texture_float4, __curve_keys)
+
/* attributes */
KERNEL_TEX(uint4, texture_uint4, __attributes_map)
KERNEL_TEX(float, texture_float, __attributes_float)
diff --git a/intern/cycles/kernel/kernel_triangle.h b/intern/cycles/kernel/kernel_triangle.h
index 570ae52d6c2..d346137760f 100644
--- a/intern/cycles/kernel/kernel_triangle.h
+++ b/intern/cycles/kernel/kernel_triangle.h
@@ -190,82 +190,5 @@ __device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *s
}
}
-/* motion */
-
-__device float4 triangle_motion_vector(KernelGlobals *kg, ShaderData *sd)
-{
- float3 motion_pre = sd->P, motion_post = sd->P;
-
- /* deformation motion */
- int offset_pre = find_attribute(kg, sd, ATTR_STD_MOTION_PRE);
- int offset_post = find_attribute(kg, sd, ATTR_STD_MOTION_POST);
-
- if(offset_pre != ATTR_STD_NOT_FOUND)
- motion_pre = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_pre, NULL, NULL);
- if(offset_post != ATTR_STD_NOT_FOUND)
- motion_post = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_post, NULL, NULL);
-
- /* object motion. note that depending on the mesh having motion vectors, this
- * transformation was set match the world/object space of motion_pre/post */
- Transform tfm;
-
- tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE);
- motion_pre = transform_point(&tfm, motion_pre);
-
- tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST);
- motion_post = transform_point(&tfm, motion_post);
-
- float3 P;
-
- /* camera motion, for perspective/orthographic motion.pre/post will be a
- * world-to-raster matrix, for panorama it's world-to-camera */
- if (kernel_data.cam.type != CAMERA_PANORAMA) {
- tfm = kernel_data.cam.worldtoraster;
- P = transform_perspective(&tfm, sd->P);
-
- tfm = kernel_data.cam.motion.pre;
- motion_pre = transform_perspective(&tfm, motion_pre);
-
- tfm = kernel_data.cam.motion.post;
- motion_post = transform_perspective(&tfm, motion_post);
- }
- else {
- tfm = kernel_data.cam.worldtocamera;
- P = normalize(transform_point(&tfm, sd->P));
- P = float2_to_float3(direction_to_panorama(kg, P));
- P.x *= kernel_data.cam.width;
- P.y *= kernel_data.cam.height;
-
- tfm = kernel_data.cam.motion.pre;
- motion_pre = normalize(transform_point(&tfm, motion_pre));
- motion_pre = float2_to_float3(direction_to_panorama(kg, motion_pre));
- motion_pre.x *= kernel_data.cam.width;
- motion_pre.y *= kernel_data.cam.height;
-
- tfm = kernel_data.cam.motion.post;
- motion_post = normalize(transform_point(&tfm, motion_post));
- motion_post = float2_to_float3(direction_to_panorama(kg, motion_post));
- motion_post.x *= kernel_data.cam.width;
- motion_post.y *= kernel_data.cam.height;
- }
-
- motion_pre = motion_pre - P;
- motion_post = P - motion_post;
-
- return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y);
-}
-
-__device float3 triangle_uv(KernelGlobals *kg, ShaderData *sd)
-{
- int offset_uv = find_attribute(kg, sd, ATTR_STD_UV);
-
- if(offset_uv == ATTR_STD_NOT_FOUND)
- return make_float3(0.0f, 0.0f, 0.0f);
-
- float3 uv = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, offset_uv, NULL, NULL);
- uv.z = 1.0f;
- return uv;
-}
-
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index d11b96503d9..2bd6b5859f3 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -47,6 +47,7 @@ CCL_NAMESPACE_BEGIN
#define __OSL__
#endif
#define __NON_PROGRESSIVE__
+#define __HAIR__
#endif
#ifdef __KERNEL_CUDA__
@@ -116,7 +117,6 @@ CCL_NAMESPACE_BEGIN
#define __ANISOTROPIC__
#define __OBJECT_MOTION__
#endif
-
//#define __SOBOL_FULL_SCREEN__
/* Shader Evaluation */
@@ -292,7 +292,8 @@ typedef enum LightType {
LIGHT_BACKGROUND,
LIGHT_AREA,
LIGHT_AO,
- LIGHT_SPOT
+ LIGHT_SPOT,
+ LIGHT_STRAND
} LightType;
/* Camera Type */
@@ -343,18 +344,44 @@ typedef struct Intersection {
float t, u, v;
int prim;
int object;
+ int segment;
} Intersection;
/* Attributes */
+#define ATTR_PRIM_TYPES 2
+#define ATTR_PRIM_CURVE 1
+
typedef enum AttributeElement {
+ ATTR_ELEMENT_NONE,
+ ATTR_ELEMENT_VALUE,
ATTR_ELEMENT_FACE,
ATTR_ELEMENT_VERTEX,
ATTR_ELEMENT_CORNER,
- ATTR_ELEMENT_VALUE,
- ATTR_ELEMENT_NONE
+ ATTR_ELEMENT_CURVE,
+ ATTR_ELEMENT_CURVE_KEY
} AttributeElement;
+typedef enum AttributeStandard {
+ ATTR_STD_NONE = 0,
+ ATTR_STD_VERTEX_NORMAL,
+ ATTR_STD_FACE_NORMAL,
+ ATTR_STD_UV,
+ ATTR_STD_UV_TANGENT,
+ ATTR_STD_UV_TANGENT_SIGN,
+ ATTR_STD_GENERATED,
+ ATTR_STD_POSITION_UNDEFORMED,
+ ATTR_STD_POSITION_UNDISPLACED,
+ ATTR_STD_MOTION_PRE,
+ ATTR_STD_MOTION_POST,
+ ATTR_STD_PARTICLE,
+ ATTR_STD_CURVE_TANGENT,
+ ATTR_STD_CURVE_INTERCEPT,
+ ATTR_STD_NUM,
+
+ ATTR_STD_NOT_FOUND = ~0
+} AttributeStandard;
+
/* Closure data */
#define MAX_CLOSURE 8
@@ -436,6 +463,11 @@ typedef struct ShaderData {
/* primitive id if there is one, ~0 otherwise */
int prim;
+
+#ifdef __HAIR__
+ /* for curves, segment number in curve, ~0 for triangles */
+ int segment;
+#endif
/* parametric coordinates
* - barycentric weights for triangles */
float u, v;
@@ -650,6 +682,29 @@ typedef struct KernelBVH {
int pad2;
} KernelBVH;
+typedef enum CurveFlag {
+ /* runtime flags */
+ CURVE_KN_BACKFACING = 1, /* backside of cylinder? */
+ CURVE_KN_ENCLOSEFILTER = 2, /* don't consider strands surrounding start point? */
+ CURVE_KN_CURVEDATA = 4, /* curve data available? */
+ CURVE_KN_INTERPOLATE = 8, /* render as a curve? - not supported yet */
+ CURVE_KN_ACCURATE = 16, /* use accurate intersections test? */
+ CURVE_KN_INTERSECTCORRECTION = 32, /* correct for width after determing closest midpoint? */
+ CURVE_KN_POSTINTERSECTCORRECTION = 64, /* correct for width after intersect? */
+ 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? */
+} CurveFlag;
+
+typedef struct KernelCurves {
+ /* strand intersect and normal parameters - many can be changed to flags*/
+ float normalmix;
+ float encasing_ratio;
+ int curveflags;
+ int pad;
+
+} KernelCurves;
+
typedef struct KernelData {
KernelCamera cam;
KernelFilm film;
@@ -657,6 +712,7 @@ typedef struct KernelData {
KernelSunSky sunsky;
KernelIntegrator integrator;
KernelBVH bvh;
+ KernelCurves curve_kernel_data;
} KernelData;
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 498d10f385b..28742d56e3b 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -37,9 +37,10 @@
#include "kernel_differential.h"
#include "kernel_object.h"
#include "kernel_bvh.h"
-#include "kernel_attribute.h"
-#include "kernel_projection.h"
#include "kernel_triangle.h"
+#include "kernel_curve.h"
+#include "kernel_primitive.h"
+#include "kernel_projection.h"
#include "kernel_accumulate.h"
#include "kernel_shader.h"
@@ -74,6 +75,11 @@ ustring OSLRenderServices::u_geom_numpolyvertices("geom:numpolyvertices");
ustring OSLRenderServices::u_geom_trianglevertices("geom:trianglevertices");
ustring OSLRenderServices::u_geom_polyvertices("geom:polyvertices");
ustring OSLRenderServices::u_geom_name("geom:name");
+#ifdef __HAIR__
+ustring OSLRenderServices::u_is_curve("geom:is_curve");
+ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness");
+ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
+#endif
ustring OSLRenderServices::u_path_ray_length("path:ray_length");
ustring OSLRenderServices::u_trace("trace");
ustring OSLRenderServices::u_hit("hit");
@@ -495,14 +501,14 @@ static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OS
attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor)
{
float3 fval[3];
- fval[0] = triangle_attribute_float3(kg, sd, attr.elem, attr.offset,
- (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
+ fval[0] = primitive_attribute_float3(kg, sd, attr.elem, attr.offset,
+ (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
return set_attribute_float3(fval, type, derivatives, val);
}
else if (attr.type == TypeDesc::TypeFloat) {
float fval[3];
- fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset,
- (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
+ fval[0] = primitive_attribute_float(kg, sd, attr.elem, attr.offset,
+ (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
return set_attribute_float(fval, type, derivatives, val);
}
else {
@@ -593,10 +599,13 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD
float3 f = particle_angular_velocity(kg, particle_id);
return set_attribute_float3(f, type, derivatives, val);
}
+
+ /* Geometry Attributes */
else if (name == u_geom_numpolyvertices) {
return set_attribute_int(3, type, derivatives, val);
}
- else if (name == u_geom_trianglevertices || name == u_geom_polyvertices) {
+ else if ((name == u_geom_trianglevertices || name == u_geom_polyvertices)
+ && sd->segment == ~0) {
float3 P[3];
triangle_vertices(kg, sd->prim, P);
@@ -612,6 +621,22 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD
ustring object_name = kg->osl->object_names[sd->object];
return set_attribute_string(object_name, type, derivatives, val);
}
+
+#ifdef __HAIR__
+ /* Hair Attributes */
+ else if (name == u_is_curve) {
+ float f = (sd->segment != ~0);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_curve_thickness) {
+ float f = curve_thickness(kg, sd);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_curve_tangent_normal) {
+ float3 f = curve_tangent_normal(kg, sd);
+ return set_attribute_float3(f, type, derivatives, val);
+ }
+#endif
else
return false;
}
@@ -634,7 +659,7 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri
{
KernelGlobals *kg = kernel_globals;
ShaderData *sd = (ShaderData *)renderstate;
- int object, tri;
+ int object, prim, segment;
/* lookup of attribute on another object */
if (object_name != u_empty || sd == NULL) {
@@ -644,17 +669,20 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri
return false;
object = it->second;
- tri = ~0;
+ prim = ~0;
+ segment = ~0;
}
else {
object = sd->object;
- tri = sd->prim;
+ prim = sd->prim;
+ segment = sd->segment;
if (object == ~0)
return get_background_attribute(kg, sd, name, type, derivatives, val);
}
/* find attribute on object */
+ object = object*ATTR_PRIM_TYPES + (segment != ~0);
OSLGlobals::AttributeMap& attribute_map = kg->osl->attribute_map[object];
OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
@@ -663,7 +691,7 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri
if (attr.elem != ATTR_ELEMENT_VALUE) {
/* triangle and vertex attributes */
- if (tri != ~0)
+ if (prim != ~0)
return get_mesh_attribute(kg, sd, attr, type, derivatives, val);
}
else {
diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h
index cd4a4163209..50c50b9952c 100644
--- a/intern/cycles/kernel/osl/osl_services.h
+++ b/intern/cycles/kernel/osl/osl_services.h
@@ -130,6 +130,9 @@ public:
static ustring u_geom_trianglevertices;
static ustring u_geom_polyvertices;
static ustring u_geom_name;
+ static ustring u_is_curve;
+ static ustring u_curve_thickness;
+ static ustring u_curve_tangent_normal;
static ustring u_path_ray_length;
static ustring u_trace;
static ustring u_hit;
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
index 3ff032374fc..59e307bb408 100644
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ b/intern/cycles/kernel/osl/osl_shader.cpp
@@ -26,9 +26,10 @@
#include "osl_services.h"
#include "osl_shader.h"
-#include "util_attribute.h"
#include "util_foreach.h"
+#include "attribute.h"
+
#include <OSL/oslexec.h>
CCL_NAMESPACE_BEGIN
@@ -453,15 +454,17 @@ float3 OSLShader::volume_eval_phase(const ShaderClosure *sc, const float3 omega_
/* Attributes */
-int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id)
+int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem)
{
/* for OSL, a hash map is used to lookup the attribute by name. */
- OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[sd->object];
- ustring stdname(std::string("std::") + std::string(attribute_standard_name((AttributeStandard)id)));
+ int object = sd->object*ATTR_PRIM_TYPES + (sd->segment != ~0);
+ OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[object];
+ ustring stdname(std::string("geom:") + std::string(Attribute::standard_name((AttributeStandard)id)));
OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
if (it != attr_map.end()) {
const OSLGlobals::Attribute &osl_attr = it->second;
+ *elem = osl_attr.elem;
/* return result */
return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset;
}
diff --git a/intern/cycles/kernel/osl/osl_shader.h b/intern/cycles/kernel/osl/osl_shader.h
index 2e46a2de42c..2062c651162 100644
--- a/intern/cycles/kernel/osl/osl_shader.h
+++ b/intern/cycles/kernel/osl/osl_shader.h
@@ -74,7 +74,7 @@ public:
const float3 omega_in, const float3 omega_out);
/* attributes */
- static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id);
+ static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt
index 70fc8610c98..acae46f1615 100644
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/shaders/CMakeLists.txt
@@ -27,6 +27,7 @@ set(SRC_OSL
node_glass_bsdf.osl
node_glossy_bsdf.osl
node_gradient_texture.osl
+ node_hair_info.osl
node_holdout.osl
node_hsv.osl
node_image_texture.osl
diff --git a/intern/cycles/util/util_attribute.h b/intern/cycles/kernel/shaders/node_hair_info.osl
index 334864c7f44..cbb3b98383f 100644
--- a/intern/cycles/util/util_attribute.h
+++ b/intern/cycles/kernel/shaders/node_hair_info.osl
@@ -1,5 +1,5 @@
/*
- * Copyright 2011, Blender Foundation.
+ * Copyright 2012, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -16,16 +16,17 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __UTIL_ATTRIBUTE_H__
-#define __UTIL_ATTRIBUTE_H__
+#include "stdosl.h"
-#include "util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-const char *attribute_standard_name(AttributeStandard std);
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_ATTRIBUTE_H__ */
+shader node_hair_info(
+ output float IsStrand = 0.0,
+ output float Intercept = 0.0,
+ output float Thickness = 0.0,
+ output normal TangentNormal = N)
+{
+ getattribute("geom:is_curve", IsStrand);
+ getattribute("geom:curve_intercept", Intercept);
+ getattribute("geom:curve_thickness", Thickness);
+ getattribute("geom:curve_tangent_normal", TangentNormal);
+}
diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h
index 69ca6b32c36..f340eaff95f 100644
--- a/intern/cycles/kernel/shaders/stdosl.h
+++ b/intern/cycles/kernel/shaders/stdosl.h
@@ -161,6 +161,15 @@ vector cross (vector a, vector b) BUILTIN;
float dot (vector a, vector b) BUILTIN;
float length (vector v) BUILTIN;
float distance (point a, point b) BUILTIN;
+float distance (point a, point b, point q)
+{
+ vector d = b - a;
+ float dd = dot(d, d);
+ if(dd == 0.0)
+ return distance(q, a);
+ float t = dot(q - a, d)/dd;
+ return distance(q, a + clamp(t, 0.0, 1.0)*d);
+}
normal normalize (normal v) BUILTIN;
vector normalize (vector v) BUILTIN;
vector faceforward (vector N, vector I, vector Nref) BUILTIN;
@@ -304,7 +313,7 @@ color transformc (string to, color x)
r = color (dot (vector(0.299, 0.587, 0.114), (vector)x),
dot (vector(0.596, -0.275, -0.321), (vector)x),
dot (vector(0.212, -0.523, 0.311), (vector)x));
- else if (to == "xyz")
+ else if (to == "XYZ")
r = color (dot (vector(0.412453, 0.357580, 0.180423), (vector)x),
dot (vector(0.212671, 0.715160, 0.072169), (vector)x),
dot (vector(0.019334, 0.119193, 0.950227), (vector)x));
@@ -366,7 +375,7 @@ color transformc (string from, string to, color x)
r = color (dot (vector(1, 0.9557, 0.6199), (vector)x),
dot (vector(1, -0.2716, -0.6469), (vector)x),
dot (vector(1, -1.1082, 1.7051), (vector)x));
- else if (from == "xyz")
+ else if (from == "XYZ")
r = color (dot (vector( 3.240479, -1.537150, -0.498535), (vector)x),
dot (vector(-0.969256, 1.875991, 0.041556), (vector)x),
dot (vector( 0.055648, -0.204043, 1.057311), (vector)x));
@@ -409,6 +418,8 @@ int startswith (string s, string prefix) BUILTIN;
int endswith (string s, string suffix) BUILTIN;
string substr (string s, int start, int len) BUILTIN;
string substr (string s, int start) { return substr (s, start, strlen(s)); }
+float strtof (string str) BUILTIN;
+int strtoi (string str) BUILTIN;
// Define concat in terms of shorter concat
string concat (string a, string b, string c) {
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index ec7978066c2..1f4857c0924 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -301,6 +301,12 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT
case NODE_PARTICLE_INFO:
svm_node_particle_info(kg, sd, stack, node.y, node.z);
break;
+#ifdef __HAIR__
+ case NODE_HAIR_INFO:
+ svm_node_hair_info(kg, sd, stack, node.y, node.z);
+ break;
+#endif
+
#endif
case NODE_CONVERT:
svm_node_convert(sd, stack, node.y, node.z, node.w);
diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h
index ed70a6dc423..2beec995151 100644
--- a/intern/cycles/kernel/svm/svm_attribute.h
+++ b/intern/cycles/kernel/svm/svm_attribute.h
@@ -28,10 +28,15 @@ __device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd,
/* find attribute by unique id */
uint id = node.y;
uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride;
+#ifdef __HAIR__
+ attr_offset = (sd->segment == ~0)? attr_offset: attr_offset + ATTR_PRIM_CURVE;
+#endif
uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
-
- while(attr_map.x != id)
- attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset);
+
+ while(attr_map.x != id) {
+ attr_offset += ATTR_PRIM_TYPES;
+ attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+ }
/* return result */
*elem = (AttributeElement)attr_map.y;
@@ -61,21 +66,21 @@ __device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uin
/* fetch and store attribute */
if(type == NODE_ATTR_FLOAT) {
if(mesh_type == NODE_ATTR_FLOAT) {
- float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL);
+ float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL);
stack_store_float(stack, out_offset, f);
}
else {
- float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL);
+ float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
stack_store_float(stack, out_offset, average(f));
}
}
else {
if(mesh_type == NODE_ATTR_FLOAT3) {
- float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL);
+ float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
stack_store_float3(stack, out_offset, f);
}
else {
- float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL);
+ float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL);
stack_store_float3(stack, out_offset, make_float3(f, f, f));
}
}
@@ -94,24 +99,24 @@ __device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *st
if(type == NODE_ATTR_FLOAT) {
if(mesh_type == NODE_ATTR_FLOAT) {
float dx;
- float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL);
+ float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL);
stack_store_float(stack, out_offset, f+dx);
}
else {
float3 dx;
- float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL);
+ float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL);
stack_store_float(stack, out_offset, average(f+dx));
}
}
else {
if(mesh_type == NODE_ATTR_FLOAT3) {
float3 dx;
- float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL);
+ float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL);
stack_store_float3(stack, out_offset, f+dx);
}
else {
float dx;
- float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL);
+ float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL);
stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx));
}
}
@@ -130,24 +135,24 @@ __device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *st
if(type == NODE_ATTR_FLOAT) {
if(mesh_type == NODE_ATTR_FLOAT) {
float dy;
- float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy);
+ float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy);
stack_store_float(stack, out_offset, f+dy);
}
else {
float3 dy;
- float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy);
+ float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy);
stack_store_float(stack, out_offset, average(f+dy));
}
}
else {
if(mesh_type == NODE_ATTR_FLOAT3) {
float3 dy;
- float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy);
+ float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy);
stack_store_float3(stack, out_offset, f+dy);
}
else {
float dy;
- float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy);
+ float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy);
stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy));
}
}
diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h
index c4d03c1f948..a04f4ea0fa7 100644
--- a/intern/cycles/kernel/svm/svm_geometry.h
+++ b/intern/cycles/kernel/svm/svm_geometry.h
@@ -28,23 +28,7 @@ __device void svm_node_geometry(KernelGlobals *kg, ShaderData *sd, float *stack,
case NODE_GEOM_P: data = sd->P; break;
case NODE_GEOM_N: data = sd->N; break;
#ifdef __DPDU__
- case NODE_GEOM_T: {
- /* try to create spherical tangent from generated coordinates */
- int attr_offset = (sd->object != ~0)? find_attribute(kg, sd, ATTR_STD_GENERATED): ATTR_STD_NOT_FOUND;
-
- if(attr_offset != ATTR_STD_NOT_FOUND) {
- data = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL);
- data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
- object_normal_transform(kg, sd, &data);
- data = cross(sd->N, normalize(cross(data, sd->N)));;
- }
- else {
- /* otherwise use surface derivatives */
- data = normalize(sd->dPdu);
- }
-
- break;
- }
+ case NODE_GEOM_T: data = primitive_tangent(kg, sd); break;
#endif
case NODE_GEOM_I: data = sd->I; break;
case NODE_GEOM_Ng: data = sd->Ng; break;
@@ -160,5 +144,36 @@ __device void svm_node_particle_info(KernelGlobals *kg, ShaderData *sd, float *s
}
}
+#ifdef __HAIR__
+
+/* Hair Info */
+
+__device void svm_node_hair_info(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset)
+{
+ float data;
+ float3 data3;
+
+ switch(type) {
+ case NODE_INFO_CURVE_IS_STRAND: {
+ data = (sd->segment != ~0);
+ stack_store_float(stack, out_offset, data);
+ break;
+ }
+ case NODE_INFO_CURVE_INTERCEPT:
+ break; /* handled as attribute */
+ case NODE_INFO_CURVE_THICKNESS: {
+ data = curve_thickness(kg, sd);
+ stack_store_float(stack, out_offset, data);
+ break;
+ }
+ case NODE_INFO_CURVE_TANGENT_NORMAL: {
+ data3 = curve_tangent_normal(kg, sd);
+ stack_store_float3(stack, out_offset, data3);
+ break;
+ }
+ }
+}
+#endif
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h
index 9f2d3367420..7a1af43b625 100644
--- a/intern/cycles/kernel/svm/svm_tex_coord.h
+++ b/intern/cycles/kernel/svm/svm_tex_coord.h
@@ -248,8 +248,9 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac
}
/* first try to get tangent attribute */
- int attr_offset = find_attribute(kg, sd, node.z);
- int attr_sign_offset = find_attribute(kg, sd, node.w);
+ AttributeElement attr_elem, attr_sign_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);
if(attr_offset == ATTR_STD_NOT_FOUND || attr_sign_offset == ATTR_STD_NOT_FOUND) {
stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f));
@@ -257,8 +258,8 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac
}
/* ensure orthogonal and normalized (interpolation breaks it) */
- float3 tangent = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL);
- float sign = triangle_attribute_float(kg, sd, ATTR_ELEMENT_CORNER, attr_sign_offset, NULL, NULL);
+ 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);
object_normal_transform(kg, sd, &tangent);
tangent = cross(sd->N, normalize(cross(tangent, sd->N)));;
@@ -295,22 +296,24 @@ __device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack,
if(direction_type == NODE_TANGENT_UVMAP) {
/* UV map */
- int attr_offset = find_attribute(kg, sd, node.z);
+ AttributeElement attr_elem;
+ int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
if(attr_offset == ATTR_STD_NOT_FOUND)
tangent = make_float3(0.0f, 0.0f, 0.0f);
else
- tangent = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL);
+ tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
}
else {
/* radial */
- int attr_offset = find_attribute(kg, sd, node.z);
+ AttributeElement attr_elem;
+ int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
float3 generated;
if(attr_offset == ATTR_STD_NOT_FOUND)
generated = sd->P;
else
- generated = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL);
+ generated = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
if(axis == NODE_TANGENT_AXIS_X)
tangent = make_float3(0.0f, -(generated.z - 0.5f), (generated.y - 0.5f));
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index e1a583625fc..57177eec48f 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -97,7 +97,8 @@ typedef enum NodeType {
NODE_CLOSURE_SET_NORMAL,
NODE_CLOSURE_AMBIENT_OCCLUSION,
NODE_TANGENT,
- NODE_NORMAL_MAP
+ NODE_NORMAL_MAP,
+ NODE_HAIR_INFO
} NodeType;
typedef enum NodeAttributeType {
@@ -132,6 +133,13 @@ typedef enum NodeParticleInfo {
NODE_INFO_PAR_ANGULAR_VELOCITY
} NodeParticleInfo;
+typedef enum NodeHairInfo {
+ NODE_INFO_CURVE_IS_STRAND,
+ NODE_INFO_CURVE_INTERCEPT,
+ NODE_INFO_CURVE_THICKNESS,
+ NODE_INFO_CURVE_TANGENT_NORMAL
+} NodeHairInfo;
+
typedef enum NodeLightPath {
NODE_LP_camera = 0,
NODE_LP_shadow,
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index 7907061c19c..d67a686d1e8 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -31,6 +31,7 @@ set(SRC
object.cpp
osl.cpp
particles.cpp
+ curves.cpp
scene.cpp
session.cpp
shader.cpp
@@ -56,6 +57,7 @@ set(SRC_HEADERS
object.h
osl.h
particles.h
+ curves.h
scene.h
session.h
shader.h
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
index 95941c14b6c..b6f6ba47fe8 100644
--- a/intern/cycles/render/attribute.cpp
+++ b/intern/cycles/render/attribute.cpp
@@ -26,7 +26,7 @@ CCL_NAMESPACE_BEGIN
/* Attribute */
-void Attribute::set(ustring name_, TypeDesc type_, Element element_)
+void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_)
{
name = name_;
type = type_;
@@ -39,12 +39,30 @@ void Attribute::set(ustring name_, TypeDesc type_, Element element_)
type == TypeDesc::TypeNormal);
}
-void Attribute::reserve(int numverts, int numtris)
+void Attribute::reserve(int numverts, int numtris, int numcurves, int numkeys)
{
- buffer.resize(buffer_size(numverts, numtris), 0);
+ buffer.resize(buffer_size(numverts, numtris, numcurves, numkeys), 0);
}
-size_t Attribute::data_sizeof()
+void Attribute::add(const float& f)
+{
+ char *data = (char*)&f;
+ size_t size = sizeof(f);
+
+ for(size_t i = 0; i < size; i++)
+ buffer.push_back(data[i]);
+}
+
+void Attribute::add(const float3& f)
+{
+ char *data = (char*)&f;
+ size_t size = sizeof(f);
+
+ for(size_t i = 0; i < size; i++)
+ buffer.push_back(data[i]);
+}
+
+size_t Attribute::data_sizeof() const
{
if(type == TypeDesc::TypeFloat)
return sizeof(float);
@@ -52,19 +70,27 @@ size_t Attribute::data_sizeof()
return sizeof(float3);
}
-size_t Attribute::element_size(int numverts, int numtris)
+size_t Attribute::element_size(int numverts, int numtris, int numcurves, int numkeys) const
{
- if(element == VERTEX)
+ if(element == ATTR_ELEMENT_VALUE)
+ return 1;
+ if(element == ATTR_ELEMENT_VERTEX)
return numverts;
- else if(element == FACE)
+ else if(element == ATTR_ELEMENT_FACE)
return numtris;
- else
+ else if(element == ATTR_ELEMENT_CORNER)
return numtris*3;
+ else if(element == ATTR_ELEMENT_CURVE)
+ return numcurves;
+ else if(element == ATTR_ELEMENT_CURVE_KEY)
+ return numkeys;
+
+ return 0;
}
-size_t Attribute::buffer_size(int numverts, int numtris)
+size_t Attribute::buffer_size(int numverts, int numtris, int numcurves, int numkeys) const
{
- return element_size(numverts, numtris)*data_sizeof();
+ return element_size(numverts, numtris, numcurves, numkeys)*data_sizeof();
}
bool Attribute::same_storage(TypeDesc a, TypeDesc b)
@@ -84,18 +110,51 @@ bool Attribute::same_storage(TypeDesc a, TypeDesc b)
return false;
}
+const char *Attribute::standard_name(AttributeStandard std)
+{
+ if(std == ATTR_STD_VERTEX_NORMAL)
+ return "N";
+ else if(std == ATTR_STD_FACE_NORMAL)
+ return "Ng";
+ else if(std == ATTR_STD_UV)
+ return "uv";
+ else if(std == ATTR_STD_GENERATED)
+ return "generated";
+ else if(std == ATTR_STD_UV_TANGENT)
+ return "tangent";
+ else if(std == ATTR_STD_UV_TANGENT_SIGN)
+ return "tangent_sign";
+ else if(std == ATTR_STD_POSITION_UNDEFORMED)
+ return "undeformed";
+ else if(std == ATTR_STD_POSITION_UNDISPLACED)
+ return "undisplaced";
+ else if(std == ATTR_STD_MOTION_PRE)
+ return "motion_pre";
+ else if(std == ATTR_STD_MOTION_POST)
+ return "motion_post";
+ else if(std == ATTR_STD_PARTICLE)
+ return "particle";
+ else if(std == ATTR_STD_CURVE_TANGENT)
+ return "curve_tangent";
+ else if(std == ATTR_STD_CURVE_INTERCEPT)
+ return "curve_intercept";
+
+ return "";
+}
+
/* Attribute Set */
AttributeSet::AttributeSet()
{
- mesh = NULL;
+ triangle_mesh = NULL;
+ curve_mesh = NULL;
}
AttributeSet::~AttributeSet()
{
}
-Attribute *AttributeSet::add(ustring name, TypeDesc type, Attribute::Element element)
+Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element)
{
Attribute *attr = find(name);
@@ -111,24 +170,22 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, Attribute::Element ele
attributes.push_back(Attribute());
attr = &attributes.back();
- if(element == Attribute::VERTEX)
- attr->set(name, type, element);
- else if(element == Attribute::FACE)
- attr->set(name, type, element);
- else if(element == Attribute::CORNER)
- attr->set(name, type, element);
+ attr->set(name, type, element);
- if(mesh)
- attr->reserve(mesh->verts.size(), mesh->triangles.size());
+ /* this is weak .. */
+ if(triangle_mesh)
+ attr->reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), 0, 0);
+ if(curve_mesh)
+ attr->reserve(0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size());
return attr;
}
-Attribute *AttributeSet::find(ustring name)
+Attribute *AttributeSet::find(ustring name) const
{
- foreach(Attribute& attr, attributes)
+ foreach(const Attribute& attr, attributes)
if(attr.name == name)
- return &attr;
+ return (Attribute*)&attr;
return NULL;
}
@@ -154,41 +211,59 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
Attribute *attr = NULL;
if(name == ustring())
- name = attribute_standard_name(std);
-
- if(std == ATTR_STD_VERTEX_NORMAL)
- attr = add(name, TypeDesc::TypeNormal, Attribute::VERTEX);
- else if(std == ATTR_STD_FACE_NORMAL)
- attr = add(name, TypeDesc::TypeNormal, Attribute::FACE);
- else if(std == ATTR_STD_UV)
- attr = add(name, TypeDesc::TypePoint, Attribute::CORNER);
- else if(std == ATTR_STD_UV_TANGENT)
- attr = add(name, TypeDesc::TypeVector, Attribute::CORNER);
- else if(std == ATTR_STD_UV_TANGENT_SIGN)
- attr = add(name, TypeDesc::TypeFloat, Attribute::CORNER);
- else if(std == ATTR_STD_GENERATED)
- attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
- else if(std == ATTR_STD_POSITION_UNDEFORMED)
- attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
- else if(std == ATTR_STD_POSITION_UNDISPLACED)
- attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
- else if(std == ATTR_STD_MOTION_PRE)
- attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
- else if(std == ATTR_STD_MOTION_POST)
- attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
- else
- assert(0);
+ name = Attribute::standard_name(std);
+
+ if(triangle_mesh) {
+ if(std == ATTR_STD_VERTEX_NORMAL)
+ attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX);
+ else if(std == ATTR_STD_FACE_NORMAL)
+ attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_FACE);
+ else if(std == ATTR_STD_UV)
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
+ else if(std == ATTR_STD_UV_TANGENT)
+ attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER);
+ else if(std == ATTR_STD_UV_TANGENT_SIGN)
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER);
+ else if(std == ATTR_STD_GENERATED)
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
+ else if(std == ATTR_STD_POSITION_UNDEFORMED)
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
+ else if(std == ATTR_STD_POSITION_UNDISPLACED)
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
+ else if(std == ATTR_STD_MOTION_PRE)
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
+ else if(std == ATTR_STD_MOTION_POST)
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
+ else
+ assert(0);
+ }
+ else if(curve_mesh) {
+ if(std == ATTR_STD_UV)
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
+ else if(std == ATTR_STD_GENERATED)
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
+ else if(std == ATTR_STD_MOTION_PRE)
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY);
+ else if(std == ATTR_STD_MOTION_POST)
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY);
+ else if(std == ATTR_STD_CURVE_TANGENT)
+ attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CURVE_KEY);
+ else if(std == ATTR_STD_CURVE_INTERCEPT)
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY);
+ else
+ assert(0);
+ }
attr->std = std;
return attr;
}
-Attribute *AttributeSet::find(AttributeStandard std)
+Attribute *AttributeSet::find(AttributeStandard std) const
{
- foreach(Attribute& attr, attributes)
+ foreach(const Attribute& attr, attributes)
if(attr.std == std)
- return &attr;
+ return (Attribute*)&attr;
return NULL;
}
@@ -217,10 +292,14 @@ Attribute *AttributeSet::find(AttributeRequest& req)
return find(req.std);
}
-void AttributeSet::reserve(int numverts, int numtris)
+void AttributeSet::reserve()
{
- foreach(Attribute& attr, attributes)
- attr.reserve(numverts, numtris);
+ foreach(Attribute& attr, attributes) {
+ if(triangle_mesh)
+ attr.reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), 0, 0);
+ if(curve_mesh)
+ attr.reserve(0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size());
+ }
}
void AttributeSet::clear()
@@ -235,9 +314,13 @@ AttributeRequest::AttributeRequest(ustring name_)
name = name_;
std = ATTR_STD_NONE;
- type = TypeDesc::TypeFloat;
- element = ATTR_ELEMENT_NONE;
- offset = 0;
+ triangle_type = TypeDesc::TypeFloat;
+ triangle_element = ATTR_ELEMENT_NONE;
+ triangle_offset = 0;
+
+ curve_type = TypeDesc::TypeFloat;
+ curve_element = ATTR_ELEMENT_NONE;
+ curve_offset = 0;
}
AttributeRequest::AttributeRequest(AttributeStandard std_)
@@ -245,9 +328,13 @@ AttributeRequest::AttributeRequest(AttributeStandard std_)
name = ustring();
std = std_;
- type = TypeDesc::TypeFloat;
- element = ATTR_ELEMENT_NONE;
- offset = 0;
+ triangle_type = TypeDesc::TypeFloat;
+ triangle_element = ATTR_ELEMENT_NONE;
+ triangle_offset = 0;
+
+ curve_type = TypeDesc::TypeFloat;
+ curve_element = ATTR_ELEMENT_NONE;
+ curve_offset = 0;
}
/* AttributeRequestSet */
diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h
index d05952edfd7..6c0c06d0425 100644
--- a/intern/cycles/render/attribute.h
+++ b/intern/cycles/render/attribute.h
@@ -21,7 +21,6 @@
#include "kernel_types.h"
-#include "util_attribute.h"
#include "util_list.h"
#include "util_param.h"
#include "util_types.h"
@@ -42,36 +41,34 @@ class Mesh;
class Attribute {
public:
- enum Element {
- VERTEX,
- FACE,
- CORNER
- };
-
ustring name;
AttributeStandard std;
TypeDesc type;
vector<char> buffer;
- Element element;
+ AttributeElement element;
Attribute() {}
- void set(ustring name, TypeDesc type, Element element);
- void reserve(int numverts, int numfaces);
+ void set(ustring name, TypeDesc type, AttributeElement element);
+ void reserve(int numverts, int numfaces, int numcurves, int numkeys);
- size_t data_sizeof();
- size_t element_size(int numverts, int numfaces);
- size_t buffer_size(int numverts, int numfaces);
+ size_t data_sizeof() const;
+ size_t element_size(int numverts, int numfaces, int numcurves, int numkeys) const;
+ size_t buffer_size(int numverts, int numfaces, int numcurves, int numkeys) const;
char *data() { return (buffer.size())? &buffer[0]: NULL; };
float3 *data_float3() { return (float3*)data(); }
float *data_float() { return (float*)data(); }
const char *data() const { return (buffer.size())? &buffer[0]: NULL; }
- const float3 *data_float3() const { return (float3*)data(); }
- const float *data_float() const { return (float*)data(); }
+ const float3 *data_float3() const { return (const float3*)data(); }
+ const float *data_float() const { return (const float*)data(); }
+
+ void add(const float& f);
+ void add(const float3& f);
static bool same_storage(TypeDesc a, TypeDesc b);
+ static const char *standard_name(AttributeStandard std);
};
/* Attribute Set
@@ -80,23 +77,24 @@ public:
class AttributeSet {
public:
- Mesh *mesh;
+ Mesh *triangle_mesh;
+ Mesh *curve_mesh;
list<Attribute> attributes;
AttributeSet();
~AttributeSet();
- Attribute *add(ustring name, TypeDesc type, Attribute::Element element);
- Attribute *find(ustring name);
+ Attribute *add(ustring name, TypeDesc type, AttributeElement element);
+ Attribute *find(ustring name) const;
void remove(ustring name);
Attribute *add(AttributeStandard std, ustring name = ustring());
- Attribute *find(AttributeStandard std);
+ Attribute *find(AttributeStandard std) const;
void remove(AttributeStandard std);
Attribute *find(AttributeRequest& req);
- void reserve(int numverts, int numfaces);
+ void reserve();
void clear();
};
@@ -104,7 +102,7 @@ public:
*
* Request from a shader to use a certain attribute, so we can figure out
* which ones we need to export from the host app end store for the kernel.
- * The attribute is found either by name or by standard. */
+ * The attribute is found either by name or by standard attribute type. */
class AttributeRequest {
public:
@@ -112,9 +110,9 @@ public:
AttributeStandard std;
/* temporary variables used by MeshManager */
- TypeDesc type;
- AttributeElement element;
- int offset;
+ TypeDesc triangle_type, curve_type;
+ AttributeElement triangle_element, curve_element;
+ int triangle_offset, curve_offset;
AttributeRequest(ustring name_);
AttributeRequest(AttributeStandard std);
diff --git a/intern/cycles/render/curves.cpp b/intern/cycles/render/curves.cpp
new file mode 100644
index 00000000000..3299503b4ab
--- /dev/null
+++ b/intern/cycles/render/curves.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "device.h"
+#include "curves.h"
+#include "mesh.h"
+#include "object.h"
+#include "scene.h"
+
+#include "util_foreach.h"
+#include "util_map.h"
+#include "util_progress.h"
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Hair System Manager */
+
+CurveSystemManager::CurveSystemManager()
+{
+ primitive = CURVE_LINE_SEGMENTS;
+ line_method = CURVE_CORRECTED;
+ interpolation = CURVE_CARDINAL;
+ triangle_method = CURVE_CAMERA;
+ resolution = 3;
+ segments = 1;
+
+ 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;
+ use_joined = false;
+ use_tangent_normal = false;
+ use_tangent_normal_geometry = false;
+ use_tangent_normal_correction = false;
+
+ need_update = true;
+ need_mesh_update = false;
+}
+
+CurveSystemManager::~CurveSystemManager()
+{
+}
+
+void CurveSystemManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
+{
+ if(!need_update)
+ return;
+
+ device_free(device, dscene);
+
+ progress.set_status("Updating Hair settings", "Copying Hair settings to device");
+
+ KernelCurves *kcurve= &dscene->data.curve_kernel_data;
+
+ 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(progress.get_cancel()) return;
+
+ need_update = false;
+}
+
+void CurveSystemManager::device_free(Device *device, DeviceScene *dscene)
+{
+
+}
+
+bool CurveSystemManager::modified(const CurveSystemManager& CurveSystemManager)
+{
+ return !(line_method == CurveSystemManager.line_method &&
+ interpolation == CurveSystemManager.interpolation &&
+ primitive == CurveSystemManager.primitive &&
+ use_encasing == CurveSystemManager.use_encasing &&
+ use_tangent_normal == CurveSystemManager.use_tangent_normal &&
+ use_tangent_normal_correction == CurveSystemManager.use_tangent_normal_correction &&
+ use_tangent_normal_geometry == CurveSystemManager.use_tangent_normal_geometry &&
+ 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);
+}
+
+bool CurveSystemManager::modified_mesh(const CurveSystemManager& CurveSystemManager)
+{
+ return !(primitive == CurveSystemManager.primitive &&
+ interpolation == CurveSystemManager.interpolation &&
+ use_parents == CurveSystemManager.use_parents &&
+ 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_cache == CurveSystemManager.use_cache);
+}
+
+void CurveSystemManager::tag_update(Scene *scene)
+{
+ need_update = true;
+}
+
+void CurveSystemManager::tag_update_mesh()
+{
+ need_mesh_update = true;
+}
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/render/curves.h b/intern/cycles/render/curves.h
new file mode 100644
index 00000000000..bb9ef6d99cf
--- /dev/null
+++ b/intern/cycles/render/curves.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __CURVES_H__
+#define __CURVES_H__
+
+#include "util_types.h"
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceScene;
+class Progress;
+class Scene;
+
+typedef enum curve_presets {
+ CURVE_CUSTOM,
+ CURVE_TANGENT_SHADING,
+ CURVE_TRUE_NORMAL,
+ CURVE_ACCURATE_PRESET
+} curve_presets;
+
+typedef enum curve_primitives {
+ CURVE_TRIANGLES,
+ CURVE_LINE_SEGMENTS,
+ CURVE_SEGMENTS
+} curve_primitives;
+
+typedef enum curve_triangles {
+ CURVE_CAMERA,
+ CURVE_RIBBONS,
+ CURVE_TESSELATED
+} curve_triangles;
+
+typedef enum curve_lines {
+ CURVE_ACCURATE,
+ CURVE_CORRECTED,
+ CURVE_POSTCORRECTED,
+ CURVE_UNCORRECTED
+} curve_lines;
+
+typedef enum curve_interpolation {
+ CURVE_LINEAR,
+ CURVE_CARDINAL,
+ CURVE_BSPLINE
+} curve_interpolation;
+
+class ParticleCurveData {
+
+public:
+
+ ParticleCurveData();
+ ~ParticleCurveData();
+
+ vector<int> psys_firstcurve;
+ vector<int> psys_curvenum;
+ vector<int> psys_shader;
+
+ vector<float> psys_rootradius;
+ vector<float> psys_tipradius;
+ vector<float> psys_shape;
+ vector<bool> psys_closetip;
+
+ vector<int> curve_firstkey;
+ vector<int> curve_keynum;
+ vector<float> curve_length;
+ vector<float3> curve_uv;
+ vector<float3> curve_vcol;
+
+ vector<float3> curvekey_co;
+ vector<float> curvekey_time;
+};
+
+/* HairSystem Manager */
+
+class CurveSystemManager {
+public:
+
+ int primitive;
+ int line_method;
+ int interpolation;
+ int triangle_method;
+ int resolution;
+ int segments;
+
+ float normalmix;
+ float encasing_ratio;
+
+ bool use_curves;
+ bool use_smooth;
+ bool use_cache;
+ bool use_parents;
+ bool use_encasing;
+ bool use_backfacing;
+ bool use_tangent_normal;
+ bool use_tangent_normal_correction;
+ bool use_tangent_normal_geometry;
+ bool use_joined;
+
+ bool need_update;
+ bool need_mesh_update;
+
+ CurveSystemManager();
+ ~CurveSystemManager();
+
+ void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
+ void device_free(Device *device, DeviceScene *dscene);
+ bool modified(const CurveSystemManager& CurveSystemManager);
+ bool modified_mesh(const CurveSystemManager& CurveSystemManager);
+
+ void tag_update(Scene *scene);
+ void tag_update_mesh();
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __CURVES_H__ */
+
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index 4173da453fd..c8e3e94ec98 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -142,6 +142,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
/* count */
size_t num_lights = scene->lights.size();
size_t num_triangles = 0;
+ size_t num_curve_segments = 0;
foreach(Object *object, scene->objects) {
Mesh *mesh = object->mesh;
@@ -169,10 +170,19 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
if(shader->sample_as_light && shader->has_surface_emission)
num_triangles++;
}
+
+ /* disabled for curves */
+#if 0
+ foreach(Mesh::Curve& curve, mesh->curves) {
+ Shader *shader = scene->shaders[curve.shader];
+
+ if(shader->sample_as_light && shader->has_surface_emission)
+ num_curve_segments += curve.num_segments();
+#endif
}
}
- size_t num_distribution = num_triangles;
+ size_t num_distribution = num_triangles + num_curve_segments;
num_distribution += num_lights;
/* emission area */
@@ -216,7 +226,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
if(shader->sample_as_light && shader->has_surface_emission) {
distribution[offset].x = totarea;
distribution[offset].y = __int_as_float(i + mesh->tri_offset);
- distribution[offset].z = 1.0f;
+ distribution[offset].z = __int_as_float(~0);
distribution[offset].w = __int_as_float(object_id);
offset++;
@@ -234,6 +244,40 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
totarea += triangle_area(p1, p2, p3);
}
}
+
+ /*sample as light disabled for strands*/
+#if 0
+ size_t i = 0;
+
+ foreach(Mesh::Curve& curve, mesh->curves) {
+ Shader *shader = scene->shaders[curve.shader];
+ int first_key = curve.first_key;
+
+ if(shader->sample_as_light && shader->has_surface_emission) {
+ for(int j = 0; j < curve.num_segments(); j++) {
+ distribution[offset].x = totarea;
+ distribution[offset].y = __int_as_float(i + mesh->curve_offset); // XXX fix kernel code
+ distribution[offset].z = __int_as_float(j);
+ distribution[offset].w = __int_as_float(object_id);
+ offset++;
+
+ float3 p1 = mesh->curve_keys[first_key + j].loc;
+ float r1 = mesh->curve_keys[first_key + j].radius;
+ float3 p2 = mesh->curve_keys[first_key + j + 1].loc;
+ float r2 = mesh->curve_keys[first_key + j + 1].radius;
+
+ if(!transform_applied) {
+ p1 = transform_point(&tfm, p1);
+ p2 = transform_point(&tfm, p2);
+ }
+
+ totarea += M_PI_F * (r1 + r2) * len(p1 - p2);
+ }
+ }
+
+ i++;
+ }
+#endif
}
if(progress.get_cancel()) return;
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index bc782a78c60..d4619dcff55 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -51,7 +51,11 @@ Mesh::Mesh()
tri_offset = 0;
vert_offset = 0;
- attributes.mesh = this;
+ curve_offset = 0;
+ curvekey_offset = 0;
+
+ attributes.triangle_mesh = this;
+ curve_attributes.curve_mesh = this;
}
Mesh::~Mesh()
@@ -59,14 +63,18 @@ Mesh::~Mesh()
delete bvh;
}
-void Mesh::reserve(int numverts, int numtris)
+void Mesh::reserve(int numverts, int numtris, int numcurves, int numcurvekeys)
{
/* reserve space to add verts and triangles later */
verts.resize(numverts);
triangles.resize(numtris);
shader.resize(numtris);
smooth.resize(numtris);
- attributes.reserve(numverts, numtris);
+ curve_keys.resize(numcurvekeys);
+ curves.resize(numcurves);
+
+ attributes.reserve();
+ curve_attributes.reserve();
}
void Mesh::clear()
@@ -77,7 +85,11 @@ void Mesh::clear()
shader.clear();
smooth.clear();
+ curve_keys.clear();
+ curves.clear();
+
attributes.clear();
+ curve_attributes.clear();
used_shaders.clear();
transform_applied = false;
@@ -86,24 +98,47 @@ void Mesh::clear()
void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_)
{
- Triangle t;
- t.v[0] = v0;
- t.v[1] = v1;
- t.v[2] = v2;
+ Triangle tri;
+ tri.v[0] = v0;
+ tri.v[1] = v1;
+ tri.v[2] = v2;
- triangles.push_back(t);
+ triangles.push_back(tri);
shader.push_back(shader_);
smooth.push_back(smooth_);
}
+void Mesh::add_curve_key(float3 co, float radius)
+{
+ CurveKey key;
+ key.co = co;
+ key.radius = radius;
+
+ curve_keys.push_back(key);
+}
+
+void Mesh::add_curve(int first_key, int num_keys, int shader)
+{
+ Curve curve;
+ curve.first_key = first_key;
+ curve.num_keys = num_keys;
+ curve.shader = shader;
+
+ curves.push_back(curve);
+}
+
void Mesh::compute_bounds()
{
BoundBox bnds = BoundBox::empty;
size_t verts_size = verts.size();
+ size_t curve_keys_size = curve_keys.size();
for(size_t i = 0; i < verts_size; i++)
bnds.grow(verts[i]);
+ for(size_t i = 0; i < curve_keys_size; i++)
+ bnds.grow(curve_keys[i].co, curve_keys[i].radius);
+
/* happens mostly on empty meshes */
if(!bnds.valid())
bnds.grow(make_float3(0.0f, 0.0f, 0.0f));
@@ -135,7 +170,12 @@ void Mesh::add_face_normals()
float3 v1 = verts_ptr[t.v[1]];
float3 v2 = verts_ptr[t.v[2]];
- fN[i] = normalize(cross(v1 - v0, v2 - v0));
+ float3 norm = cross(v1 - v0, v2 - v0);
+ float normlen = len(norm);
+ if(normlen == 0.0f)
+ fN[i] = make_float3(0.0f, 0.0f, 0.0f);
+ else
+ fN[i] = norm / normlen;
if(flip)
fN[i] = -fN[i];
@@ -243,6 +283,43 @@ void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset)
}
}
+void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset)
+{
+ size_t curve_keys_size = curve_keys.size();
+ CurveKey *keys_ptr = NULL;
+
+ /* pack curve keys */
+ if(curve_keys_size) {
+ keys_ptr = &curve_keys[0];
+
+ for(size_t i = 0; i < curve_keys_size; i++) {
+ float3 p = keys_ptr[i].co;
+ float radius = keys_ptr[i].radius;
+
+ curve_key_co[i] = make_float4(p.x, p.y, p.z, radius);
+ }
+ }
+
+ /* pack curve segments */
+ size_t curve_num = curves.size();
+
+ if(curve_num) {
+ Curve *curve_ptr = &curves[0];
+ int shader_id = 0;
+
+ for(size_t i = 0; i < curve_num; i++) {
+ Curve curve = curve_ptr[i];
+ shader_id = scene->shader_manager->get_shader_id(curve.shader, this, false);
+
+ curve_data[i] = make_float4(
+ __int_as_float(curve.first_key + curvekey_offset),
+ __int_as_float(curve.num_keys),
+ __int_as_float(shader_id),
+ 0.0f);
+ }
+ }
+}
+
void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total)
{
if(progress->get_cancel())
@@ -327,7 +404,7 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
og->attribute_map.clear();
og->object_names.clear();
- og->attribute_map.resize(scene->objects.size());
+ og->attribute_map.resize(scene->objects.size()*ATTR_PRIM_TYPES);
for(size_t i = 0; i < scene->objects.size(); i++) {
/* set object name to object index map */
@@ -343,7 +420,8 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
osl_attr.elem = ATTR_ELEMENT_VALUE;
osl_attr.value = attr;
- og->attribute_map[i][attr.name()] = osl_attr;
+ og->attribute_map[i*ATTR_PRIM_TYPES][attr.name()] = osl_attr;
+ og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][attr.name()] = osl_attr;
}
/* find mesh attributes */
@@ -357,27 +435,46 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
/* set object attributes */
foreach(AttributeRequest& req, attributes.requests) {
- if(req.element == ATTR_ELEMENT_NONE)
- continue;
-
OSLGlobals::Attribute osl_attr;
- osl_attr.elem = req.element;
- osl_attr.offset = req.offset;
-
- if(req.type == TypeDesc::TypeFloat)
- osl_attr.type = TypeDesc::TypeFloat;
- else
- osl_attr.type = TypeDesc::TypeColor;
-
- if(req.std != ATTR_STD_NONE) {
- /* if standard attribute, add lookup by geom: name convention */
- ustring stdname(string("geom:") + string(attribute_standard_name(req.std)));
- og->attribute_map[i][stdname] = osl_attr;
+ if(req.triangle_element != ATTR_ELEMENT_NONE) {
+ osl_attr.elem = req.triangle_element;
+ osl_attr.offset = req.triangle_offset;
+
+ if(req.triangle_type == TypeDesc::TypeFloat)
+ osl_attr.type = TypeDesc::TypeFloat;
+ else
+ osl_attr.type = TypeDesc::TypeColor;
+
+ if(req.std != ATTR_STD_NONE) {
+ /* if standard attribute, add lookup by geom: name convention */
+ ustring stdname(string("geom:") + string(Attribute::standard_name(req.std)));
+ og->attribute_map[i*ATTR_PRIM_TYPES][stdname] = osl_attr;
+ }
+ else if(req.name != ustring()) {
+ /* add lookup by mesh attribute name */
+ og->attribute_map[i*ATTR_PRIM_TYPES][req.name] = osl_attr;
+ }
}
- else if(req.name != ustring()) {
- /* add lookup by mesh attribute name */
- og->attribute_map[i][req.name] = osl_attr;
+
+ if(req.curve_element != ATTR_ELEMENT_NONE) {
+ osl_attr.elem = req.curve_element;
+ osl_attr.offset = req.curve_offset;
+
+ if(req.curve_type == TypeDesc::TypeFloat)
+ osl_attr.type = TypeDesc::TypeFloat;
+ else
+ osl_attr.type = TypeDesc::TypeColor;
+
+ if(req.std != ATTR_STD_NONE) {
+ /* if standard attribute, add lookup by geom: name convention */
+ ustring stdname(string("geom:") + string(Attribute::standard_name(req.std)));
+ og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][stdname] = osl_attr;
+ }
+ else if(req.name != ustring()) {
+ /* add lookup by mesh attribute name */
+ og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][req.name] = osl_attr;
+ }
}
}
}
@@ -393,7 +490,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
int attr_map_stride = 0;
for(size_t i = 0; i < scene->meshes.size(); i++)
- attr_map_stride = max(attr_map_stride, mesh_attributes[i].size()+1);
+ attr_map_stride = max(attr_map_stride, (mesh_attributes[i].size() + 1)*ATTR_PRIM_TYPES);
if(attr_map_stride == 0)
return;
@@ -404,12 +501,13 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
for(size_t i = 0; i < scene->objects.size(); i++) {
Object *object = scene->objects[i];
+ Mesh *mesh = object->mesh;
/* find mesh attributes */
size_t j;
for(j = 0; j < scene->meshes.size(); j++)
- if(scene->meshes[j] == object->mesh)
+ if(scene->meshes[j] == mesh)
break;
AttributeRequestSet& attributes = mesh_attributes[j];
@@ -425,14 +523,29 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
else
id = scene->shader_manager->get_attribute_id(req.std);
- attr_map[index].x = id;
- attr_map[index].y = req.element;
- attr_map[index].z = as_uint(req.offset);
+ if(mesh->triangles.size()) {
+ attr_map[index].x = id;
+ attr_map[index].y = req.triangle_element;
+ attr_map[index].z = as_uint(req.triangle_offset);
- if(req.type == TypeDesc::TypeFloat)
- attr_map[index].w = NODE_ATTR_FLOAT;
- else
- attr_map[index].w = NODE_ATTR_FLOAT3;
+ if(req.triangle_type == TypeDesc::TypeFloat)
+ attr_map[index].w = NODE_ATTR_FLOAT;
+ else
+ attr_map[index].w = NODE_ATTR_FLOAT3;
+ }
+
+ index++;
+
+ if(mesh->curves.size()) {
+ attr_map[index].x = id;
+ attr_map[index].y = req.curve_element;
+ attr_map[index].z = as_uint(req.curve_offset);
+
+ if(req.curve_type == TypeDesc::TypeFloat)
+ attr_map[index].w = NODE_ATTR_FLOAT;
+ else
+ attr_map[index].w = NODE_ATTR_FLOAT3;
+ }
index++;
}
@@ -442,6 +555,15 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
attr_map[index].y = 0;
attr_map[index].z = 0;
attr_map[index].w = 0;
+
+ index++;
+
+ attr_map[index].x = ATTR_STD_NONE;
+ attr_map[index].y = 0;
+ attr_map[index].z = 0;
+ attr_map[index].w = 0;
+
+ index++;
}
/* copy to device */
@@ -449,6 +571,60 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
device->tex_alloc("__attributes_map", dscene->attributes_map);
}
+static void update_attribute_element_offset(Mesh *mesh, vector<float>& attr_float, vector<float4>& attr_float3,
+ Attribute *mattr, TypeDesc& type, int& offset, AttributeElement& element)
+{
+ if(mattr) {
+ /* store element and type */
+ element = mattr->element;
+ type = mattr->type;
+
+ /* store attribute data in arrays */
+ size_t size = mattr->element_size(
+ mesh->verts.size(),
+ mesh->triangles.size(),
+ mesh->curves.size(),
+ mesh->curve_keys.size());
+
+ if(mattr->type == TypeDesc::TypeFloat) {
+ float *data = mattr->data_float();
+ offset = attr_float.size();
+
+ attr_float.resize(attr_float.size() + size);
+
+ for(size_t k = 0; k < size; k++)
+ attr_float[offset+k] = data[k];
+ }
+ else {
+ float3 *data = mattr->data_float3();
+ offset = attr_float3.size();
+
+ attr_float3.resize(attr_float3.size() + size);
+
+ for(size_t k = 0; k < size; k++)
+ attr_float3[offset+k] = float3_to_float4(data[k]);
+ }
+
+ /* mesh vertex/curve index is global, not per object, so we sneak
+ * a correction for that in here */
+ if(element == ATTR_ELEMENT_VERTEX)
+ offset -= mesh->vert_offset;
+ else if(element == ATTR_ELEMENT_FACE)
+ offset -= mesh->tri_offset;
+ else if(element == ATTR_ELEMENT_CORNER)
+ offset -= 3*mesh->tri_offset;
+ else if(element == ATTR_ELEMENT_CURVE)
+ offset -= mesh->curve_offset;
+ else if(element == ATTR_ELEMENT_CURVE_KEY)
+ offset -= mesh->curvekey_offset;
+ }
+ else {
+ /* attribute not found */
+ element = ATTR_ELEMENT_NONE;
+ offset = 0;
+ }
+}
+
void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
progress.set_status("Updating Mesh", "Computing attributes");
@@ -482,66 +658,24 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
/* todo: we now store std and name attributes from requests even if
* they actually refer to the same mesh attributes, optimize */
foreach(AttributeRequest& req, attributes.requests) {
- Attribute *mattr = mesh->attributes.find(req);
-
- /* todo: get rid of this exception */
- if(!mattr && req.std == ATTR_STD_GENERATED) {
- mattr = mesh->attributes.add(ATTR_STD_GENERATED);
+ Attribute *triangle_mattr = mesh->attributes.find(req);
+ Attribute *curve_mattr = mesh->curve_attributes.find(req);
+
+ /* todo: get rid of this exception, it's only here for giving some
+ * working texture coordinate for subdivision as we can't preserve
+ * any attributes yet */
+ if(!triangle_mattr && req.std == ATTR_STD_GENERATED) {
+ triangle_mattr = mesh->attributes.add(ATTR_STD_GENERATED);
if(mesh->verts.size())
- memcpy(mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size());
+ memcpy(triangle_mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size());
}
- /* attribute not found */
- if(!mattr) {
- req.element = ATTR_ELEMENT_NONE;
- req.offset = 0;
- continue;
- }
-
- /* we abuse AttributeRequest to pass on info like element and
- * offset, it doesn't really make sense but is convenient */
-
- /* store element and type */
- if(mattr->element == Attribute::VERTEX)
- req.element = ATTR_ELEMENT_VERTEX;
- else if(mattr->element == Attribute::FACE)
- req.element = ATTR_ELEMENT_FACE;
- else if(mattr->element == Attribute::CORNER)
- req.element = ATTR_ELEMENT_CORNER;
-
- req.type = mattr->type;
-
- /* store attribute data in arrays */
- size_t size = mattr->element_size(mesh->verts.size(), mesh->triangles.size());
-
- if(mattr->type == TypeDesc::TypeFloat) {
- float *data = mattr->data_float();
- req.offset = attr_float.size();
-
- attr_float.resize(attr_float.size() + size);
-
- for(size_t k = 0; k < size; k++)
- attr_float[req.offset+k] = data[k];
- }
- else {
- float3 *data = mattr->data_float3();
- req.offset = attr_float3.size();
-
- attr_float3.resize(attr_float3.size() + size);
-
- for(size_t k = 0; k < size; k++)
- attr_float3[req.offset+k] = float3_to_float4(data[k]);
- }
-
- /* mesh vertex/triangle index is global, not per object, so we sneak
- * a correction for that in here */
- if(req.element == ATTR_ELEMENT_VERTEX)
- req.offset -= mesh->vert_offset;
- else if(mattr->element == Attribute::FACE)
- req.offset -= mesh->tri_offset;
- else if(mattr->element == Attribute::CORNER)
- req.offset -= 3*mesh->tri_offset;
+ update_attribute_element_offset(mesh, attr_float, attr_float3, triangle_mattr,
+ req.triangle_type, req.triangle_offset, req.triangle_element);
+ update_attribute_element_offset(mesh, attr_float, attr_float3, curve_mattr,
+ req.curve_type, req.curve_offset, req.curve_element);
+
if(progress.get_cancel()) return;
}
}
@@ -573,39 +707,62 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
size_t vert_size = 0;
size_t tri_size = 0;
+ size_t curve_key_size = 0;
+ size_t curve_size = 0;
+
foreach(Mesh *mesh, scene->meshes) {
mesh->vert_offset = vert_size;
mesh->tri_offset = tri_size;
+ mesh->curvekey_offset = curve_key_size;
+ mesh->curve_offset = curve_size;
+
vert_size += mesh->verts.size();
tri_size += mesh->triangles.size();
+
+ curve_key_size += mesh->curve_keys.size();
+ curve_size += mesh->curves.size();
}
- if(tri_size == 0)
- return;
+ if(tri_size != 0) {
+ /* normals */
+ progress.set_status("Updating Mesh", "Computing normals");
- /* normals */
- progress.set_status("Updating Mesh", "Computing normals");
+ float4 *normal = dscene->tri_normal.resize(tri_size);
+ float4 *vnormal = dscene->tri_vnormal.resize(vert_size);
+ float4 *tri_verts = dscene->tri_verts.resize(vert_size);
+ float4 *tri_vindex = dscene->tri_vindex.resize(tri_size);
- float4 *normal = dscene->tri_normal.resize(tri_size);
- float4 *vnormal = dscene->tri_vnormal.resize(vert_size);
- float4 *tri_verts = dscene->tri_verts.resize(vert_size);
- float4 *tri_vindex = dscene->tri_vindex.resize(tri_size);
+ foreach(Mesh *mesh, scene->meshes) {
+ mesh->pack_normals(scene, &normal[mesh->tri_offset], &vnormal[mesh->vert_offset]);
+ mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->tri_offset], mesh->vert_offset);
- foreach(Mesh *mesh, scene->meshes) {
- mesh->pack_normals(scene, &normal[mesh->tri_offset], &vnormal[mesh->vert_offset]);
- mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->tri_offset], mesh->vert_offset);
+ if(progress.get_cancel()) return;
+ }
- if(progress.get_cancel()) return;
+ /* vertex coordinates */
+ progress.set_status("Updating Mesh", "Copying Mesh to device");
+
+ device->tex_alloc("__tri_normal", dscene->tri_normal);
+ device->tex_alloc("__tri_vnormal", dscene->tri_vnormal);
+ device->tex_alloc("__tri_verts", dscene->tri_verts);
+ device->tex_alloc("__tri_vindex", dscene->tri_vindex);
}
- /* vertex coordinates */
- progress.set_status("Updating Mesh", "Copying Mesh to device");
+ if(curve_size != 0) {
+ progress.set_status("Updating Mesh", "Copying Strands to device");
+
+ float4 *curve_keys = dscene->curve_keys.resize(curve_key_size);
+ float4 *curves = dscene->curves.resize(curve_size);
- device->tex_alloc("__tri_normal", dscene->tri_normal);
- device->tex_alloc("__tri_vnormal", dscene->tri_vnormal);
- device->tex_alloc("__tri_verts", dscene->tri_verts);
- device->tex_alloc("__tri_vindex", dscene->tri_vindex);
+ foreach(Mesh *mesh, scene->meshes) {
+ mesh->pack_curves(scene, &curve_keys[mesh->curvekey_offset], &curves[mesh->curve_offset], mesh->curvekey_offset);
+ if(progress.get_cancel()) return;
+ }
+
+ device->tex_alloc("__curve_keys", dscene->curve_keys);
+ device->tex_alloc("__curves", dscene->curves);
+ }
}
void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
@@ -642,6 +799,10 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
dscene->tri_woop.reference(&pack.tri_woop[0], pack.tri_woop.size());
device->tex_alloc("__tri_woop", dscene->tri_woop);
}
+ if(pack.prim_segment.size()) {
+ dscene->prim_segment.reference((uint*)&pack.prim_segment[0], pack.prim_segment.size());
+ device->tex_alloc("__prim_segment", dscene->prim_segment);
+ }
if(pack.prim_visibility.size()) {
dscene->prim_visibility.reference((uint*)&pack.prim_visibility[0], pack.prim_visibility.size());
device->tex_alloc("__prim_visibility", dscene->prim_visibility);
@@ -751,6 +912,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
device->tex_free(dscene->bvh_nodes);
device->tex_free(dscene->object_node);
device->tex_free(dscene->tri_woop);
+ device->tex_free(dscene->prim_segment);
device->tex_free(dscene->prim_visibility);
device->tex_free(dscene->prim_index);
device->tex_free(dscene->prim_object);
@@ -758,6 +920,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
device->tex_free(dscene->tri_vnormal);
device->tex_free(dscene->tri_vindex);
device->tex_free(dscene->tri_verts);
+ device->tex_free(dscene->curves);
+ device->tex_free(dscene->curve_keys);
device->tex_free(dscene->attributes_map);
device->tex_free(dscene->attributes_float);
device->tex_free(dscene->attributes_float3);
@@ -765,6 +929,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
dscene->bvh_nodes.clear();
dscene->object_node.clear();
dscene->tri_woop.clear();
+ dscene->prim_segment.clear();
dscene->prim_visibility.clear();
dscene->prim_index.clear();
dscene->prim_object.clear();
@@ -772,6 +937,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
dscene->tri_vnormal.clear();
dscene->tri_vindex.clear();
dscene->tri_verts.clear();
+ dscene->curves.clear();
+ dscene->curve_keys.clear();
dscene->attributes_map.clear();
dscene->attributes_float.clear();
dscene->attributes_float3.clear();
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index 637143f5adf..b83752ad8df 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -50,6 +50,21 @@ public:
int v[3];
};
+ /* Mesh Curve */
+ struct Curve {
+ int first_key;
+ int num_keys;
+ uint shader;
+ uint pad;
+
+ int num_segments() { return num_keys - 1; }
+ };
+
+ struct CurveKey {
+ float3 co;
+ float radius;
+ };
+
/* Displacement */
enum DisplacementMethod {
DISPLACE_BUMP,
@@ -65,8 +80,12 @@ public:
vector<uint> shader;
vector<bool> smooth;
+ vector<CurveKey> curve_keys;
+ vector<Curve> curves;
+
vector<uint> used_shaders;
AttributeSet attributes;
+ AttributeSet curve_attributes;
BoundBox bounds;
bool transform_applied;
@@ -82,13 +101,18 @@ public:
size_t tri_offset;
size_t vert_offset;
+ size_t curve_offset;
+ size_t curvekey_offset;
+
/* Functions */
Mesh();
~Mesh();
- void reserve(int numverts, int numfaces);
+ void reserve(int numverts, int numfaces, int numcurves, int numcurvekeys);
void clear();
void add_triangle(int v0, int v1, int v2, int shader, bool smooth);
+ void add_curve_key(float3 loc, float radius);
+ void add_curve(int first_key, int num_keys, int shader);
void compute_bounds();
void add_face_normals();
@@ -96,6 +120,7 @@ public:
void pack_normals(Scene *scene, float4 *normal, float4 *vnormal);
void pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset);
+ void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset);
void compute_bvh(SceneParams *params, Progress *progress, int n, int total);
bool need_attribute(Scene *scene, AttributeStandard std);
diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp
index dea694a811e..04267697b29 100644
--- a/intern/cycles/render/mesh_displace.cpp
+++ b/intern/cycles/render/mesh_displace.cpp
@@ -19,6 +19,7 @@
#include "device.h"
#include "mesh.h"
+#include "object.h"
#include "scene.h"
#include "shader.h"
@@ -41,11 +42,24 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p
if(!has_displacement)
return false;
+ string msg = string_printf("Computing Displacement %s", mesh->name.c_str());
+ progress.set_status("Updating Mesh", msg);
+
+ /* find object index. todo: is arbitrary */
+ size_t object_index = ~0;
+
+ for(size_t i = 0; i < scene->objects.size(); i++) {
+ if(scene->objects[i]->mesh == mesh) {
+ object_index = i;
+ break;
+ }
+ }
+
/* setup input for device task */
vector<bool> done(mesh->verts.size(), false);
device_vector<uint4> d_input;
uint4 *d_input_data = d_input.resize(mesh->verts.size());
- size_t d_input_offset = 0;
+ size_t d_input_size = 0;
for(size_t i = 0; i < mesh->triangles.size(); i++) {
Mesh::Triangle t = mesh->triangles[i];
@@ -61,8 +75,8 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p
done[t.v[j]] = true;
/* set up object, primitive and barycentric coordinates */
- /* when used, non-instanced convention: object = -object-1; */
- int object = ~0; /* todo */
+ /* when used, non-instanced convention: object = ~object */
+ int object = ~object_index;
int prim = mesh->tri_offset + i;
float u, v;
@@ -81,16 +95,16 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p
/* back */
uint4 in = make_uint4(object, prim, __float_as_int(u), __float_as_int(v));
- d_input_data[d_input_offset++] = in;
+ d_input_data[d_input_size++] = in;
}
}
- if(d_input_offset == 0)
+ if(d_input_size == 0)
return false;
/* run device task */
device_vector<float4> d_output;
- d_output.resize(d_input.size());
+ d_output.resize(d_input_size);
device->mem_alloc(d_input, MEM_READ_ONLY);
device->mem_copy_to(d_input);
@@ -101,7 +115,7 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p
task.shader_output = d_output.device_pointer;
task.shader_eval_type = SHADER_EVAL_DISPLACE;
task.shader_x = 0;
- task.shader_w = d_input.size();
+ task.shader_w = d_output.size();
device->task_add(task);
device->task_wait();
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index aef28449e44..14ef3c68ad3 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -2240,6 +2240,63 @@ void ParticleInfoNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_particle_info");
}
+/* Hair Info */
+
+HairInfoNode::HairInfoNode()
+: ShaderNode("hair_info")
+{
+ add_output("Is Strand", SHADER_SOCKET_FLOAT);
+ add_output("Intercept", SHADER_SOCKET_FLOAT);
+ add_output("Thickness", SHADER_SOCKET_FLOAT);
+ add_output("Tangent Normal", SHADER_SOCKET_NORMAL);
+}
+
+void HairInfoNode::attributes(AttributeRequestSet *attributes)
+{
+ ShaderOutput *intercept_out = output("Intercept");
+
+ if(!intercept_out->links.empty())
+ attributes->add(ATTR_STD_CURVE_INTERCEPT);
+
+ ShaderNode::attributes(attributes);
+}
+
+void HairInfoNode::compile(SVMCompiler& compiler)
+{
+ ShaderOutput *out;
+
+ out = output("Is Strand");
+ if(!out->links.empty()) {
+ compiler.stack_assign(out);
+ compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_IS_STRAND, out->stack_offset);
+ }
+
+ out = output("Intercept");
+ if(!out->links.empty()) {
+ int attr = compiler.attribute(ATTR_STD_CURVE_INTERCEPT);
+ compiler.stack_assign(out);
+ compiler.add_node(NODE_ATTR, attr, out->stack_offset, NODE_ATTR_FLOAT);
+ }
+
+ out = output("Thickness");
+ if(!out->links.empty()) {
+ compiler.stack_assign(out);
+ compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_THICKNESS, out->stack_offset);
+ }
+
+ out = output("Tangent Normal");
+ if(!out->links.empty()) {
+ compiler.stack_assign(out);
+ compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, out->stack_offset);
+ }
+
+}
+
+void HairInfoNode::compile(OSLCompiler& compiler)
+{
+ compiler.add(this, "node_hair_info");
+}
+
/* Value */
ValueNode::ValueNode()
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 8012a99ff05..564ceee5a5b 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -331,6 +331,13 @@ public:
void attributes(AttributeRequestSet *attributes);
};
+class HairInfoNode : public ShaderNode {
+public:
+ SHADER_NODE_CLASS(HairInfoNode)
+
+ void attributes(AttributeRequestSet *attributes);
+};
+
class ValueNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ValueNode)
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index 5df8e8c1368..a89f8afd251 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -19,6 +19,7 @@
#include "device.h"
#include "light.h"
#include "mesh.h"
+#include "curves.h"
#include "object.h"
#include "scene.h"
@@ -45,6 +46,7 @@ Object::Object()
motion.post = transform_identity();
use_motion = false;
use_holdout = false;
+ curverender = false;
}
Object::~Object()
@@ -86,6 +88,10 @@ void Object::apply_transform()
for(size_t i = 0; i < mesh->verts.size(); i++)
mesh->verts[i] = transform_point(&tfm, mesh->verts[i]);
+ 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);
@@ -110,6 +116,13 @@ void Object::apply_transform()
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);
@@ -133,6 +146,7 @@ void Object::tag_update(Scene *scene)
}
}
+ scene->curve_system_manager->need_update = true;
scene->mesh_manager->need_update = true;
scene->object_manager->need_update = true;
}
@@ -189,6 +203,20 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene
surface_area += triangle_area(p1, p2, p3);
}
+ foreach(Mesh::Curve& curve, mesh->curves) {
+ int first_key = curve.first_key;
+
+ for(int i = 0; i < curve.num_segments(); i++) {
+ float3 p1 = mesh->curve_keys[first_key + i].co;
+ float r1 = mesh->curve_keys[first_key + i].radius;
+ float3 p2 = mesh->curve_keys[first_key + i + 1].co;
+ float r2 = mesh->curve_keys[first_key + i + 1].radius;
+
+ /* currently ignores segment overlaps*/
+ surface_area += M_PI_F *(r1 + r2) * len(p1 - p2);
+ }
+ }
+
surface_area_map[mesh] = surface_area;
}
else
@@ -204,6 +232,23 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene
surface_area += triangle_area(p1, p2, p3);
}
+
+ foreach(Mesh::Curve& curve, mesh->curves) {
+ int first_key = curve.first_key;
+
+ for(int i = 0; i < curve.num_segments(); i++) {
+ float3 p1 = mesh->curve_keys[first_key + i].co;
+ float r1 = mesh->curve_keys[first_key + i].radius;
+ float3 p2 = mesh->curve_keys[first_key + i + 1].co;
+ float r2 = mesh->curve_keys[first_key + i + 1].radius;
+
+ p1 = transform_point(&tfm, p1);
+ p2 = transform_point(&tfm, p2);
+
+ /* currently ignores segment overlaps*/
+ surface_area += M_PI_F *(r1 + r2) * len(p1 - p2);
+ }
+ }
}
/* pack in texture */
@@ -355,6 +400,7 @@ void ObjectManager::apply_static_transforms(Scene *scene, uint *object_flag, Pro
void ObjectManager::tag_update(Scene *scene)
{
need_update = true;
+ scene->curve_system_manager->need_update = true;
scene->mesh_manager->need_update = true;
scene->light_manager->need_update = true;
}
diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h
index 9c9b11bc29c..9ba500ca4d6 100644
--- a/intern/cycles/render/object.h
+++ b/intern/cycles/render/object.h
@@ -48,6 +48,7 @@ public:
MotionTransform motion;
bool use_motion;
bool use_holdout;
+ bool curverender;
float3 dupli_generated;
float2 dupli_uv;
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index 8085cfdd3e6..093bfecf88e 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -29,6 +29,7 @@
#include "mesh.h"
#include "object.h"
#include "particles.h"
+#include "curves.h"
#include "scene.h"
#include "svm.h"
#include "osl.h"
@@ -54,6 +55,7 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
integrator = new Integrator();
image_manager = new ImageManager();
particle_system_manager = new ParticleSystemManager();
+ curve_system_manager = new CurveSystemManager();
/* OSL only works on the CPU */
if(device_info_.type == DEVICE_CPU)
@@ -96,6 +98,7 @@ void Scene::free_memory(bool final)
light_manager->device_free(device, &dscene);
particle_system_manager->device_free(device, &dscene);
+ curve_system_manager->device_free(device, &dscene);
if(!params.persistent_images || final)
image_manager->device_free(device, &dscene);
@@ -112,6 +115,7 @@ void Scene::free_memory(bool final)
delete shader_manager;
delete light_manager;
delete particle_system_manager;
+ delete curve_system_manager;
delete image_manager;
}
else {
@@ -165,6 +169,11 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel()) return;
+ progress.set_status("Updating Hair Systems");
+ curve_system_manager->device_update(device, &dscene, this, progress);
+
+ if(progress.get_cancel()) return;
+
progress.set_status("Updating Meshes");
mesh_manager->device_update(device, &dscene, this, progress);
@@ -242,7 +251,8 @@ bool Scene::need_reset()
|| filter->need_update
|| integrator->need_update
|| shader_manager->need_update
- || particle_system_manager->need_update);
+ || particle_system_manager->need_update
+ || curve_system_manager->need_update);
}
void Scene::reset()
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index ebe932e40e7..f6e1daea80d 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -25,7 +25,6 @@
#include "kernel_types.h"
-#include "util_attribute.h"
#include "util_param.h"
#include "util_string.h"
#include "util_thread.h"
@@ -50,6 +49,7 @@ class Object;
class ObjectManager;
class ParticleSystemManager;
class ParticleSystem;
+class CurveSystemManager;
class Shader;
class ShaderManager;
class Progress;
@@ -62,6 +62,7 @@ public:
device_vector<float4> bvh_nodes;
device_vector<uint> object_node;
device_vector<float4> tri_woop;
+ device_vector<uint> prim_segment;
device_vector<uint> prim_visibility;
device_vector<uint> prim_index;
device_vector<uint> prim_object;
@@ -72,6 +73,9 @@ public:
device_vector<float4> tri_vindex;
device_vector<float4> tri_verts;
+ device_vector<float4> curves;
+ device_vector<float4> curve_keys;
+
/* objects */
device_vector<float4> objects;
device_vector<float4> objects_vector;
@@ -170,6 +174,7 @@ public:
MeshManager *mesh_manager;
ObjectManager *object_manager;
ParticleSystemManager *particle_system_manager;
+ CurveSystemManager *curve_system_manager;
/* default shaders */
int default_surface;
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 1d1a3d54893..36948adce17 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -357,7 +357,7 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile)
tile_lock.unlock();
- /* in case of a permant buffer, return it, otherwise we will allocate
+ /* in case of a permanent buffer, return it, otherwise we will allocate
* a new temporary buffer */
if(!params.background) {
tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride);
@@ -411,6 +411,12 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile)
rtile.rgba = 0;
rtile.buffers = tilebuffers;
+ /* this will tag tile as IN PROGRESS in blender-side render pipeline,
+ * which is needed to highlight currently rendering tile before first
+ * sample was processed for it
+ */
+ update_tile_sample(rtile);
+
return true;
}
diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp
index 6920df9954c..48e6808bc38 100644
--- a/intern/cycles/subd/subd_dice.cpp
+++ b/intern/cycles/subd/subd_dice.cpp
@@ -47,7 +47,7 @@ void EdgeDice::reserve(int num_verts, int num_tris)
vert_offset = mesh->verts.size();
tri_offset = mesh->triangles.size();
- mesh->reserve(vert_offset + num_verts, tri_offset + num_tris);
+ mesh->reserve(vert_offset + num_verts, tri_offset + num_tris, 0, 0);
Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt
index dce417704cc..bcaaa9a71b9 100644
--- a/intern/cycles/util/CMakeLists.txt
+++ b/intern/cycles/util/CMakeLists.txt
@@ -9,7 +9,6 @@ set(INC_SYS
)
set(SRC
- util_attribute.cpp
util_cache.cpp
util_cuda.cpp
util_dynlib.cpp
@@ -33,7 +32,6 @@ endif()
set(SRC_HEADERS
util_algorithm.h
util_args.h
- util_attribute.h
util_boundbox.h
util_cache.h
util_cuda.h
diff --git a/intern/cycles/util/util_attribute.cpp b/intern/cycles/util/util_attribute.cpp
deleted file mode 100644
index 057fb6213e9..00000000000
--- a/intern/cycles/util/util_attribute.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2011, Blender Foundation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "util_attribute.h"
-
-CCL_NAMESPACE_BEGIN
-
-const char *attribute_standard_name(AttributeStandard std)
-{
- if(std == ATTR_STD_VERTEX_NORMAL)
- return "N";
- else if(std == ATTR_STD_FACE_NORMAL)
- return "Ng";
- else if(std == ATTR_STD_UV)
- return "uv";
- else if(std == ATTR_STD_GENERATED)
- return "generated";
- else if(std == ATTR_STD_UV_TANGENT)
- return "tangent";
- else if(std == ATTR_STD_UV_TANGENT_SIGN)
- return "tangent_sign";
- else if(std == ATTR_STD_POSITION_UNDEFORMED)
- return "undeformed";
- else if(std == ATTR_STD_POSITION_UNDISPLACED)
- return "undisplaced";
- else if(std == ATTR_STD_MOTION_PRE)
- return "motion_pre";
- else if(std == ATTR_STD_MOTION_POST)
- return "motion_post";
- else if(std == ATTR_STD_PARTICLE)
- return "particle";
-
- return "";
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_boundbox.h b/intern/cycles/util/util_boundbox.h
index 6dd1c6c71e8..0c857f906ee 100644
--- a/intern/cycles/util/util_boundbox.h
+++ b/intern/cycles/util/util_boundbox.h
@@ -65,6 +65,13 @@ public:
max = ccl::max(max, pt);
}
+ __forceinline void grow(const float3& pt, float border)
+ {
+ float3 shift = {border, border, border, 0.0f};
+ min = ccl::min(min, pt - shift);
+ max = ccl::max(max, pt + shift);
+ }
+
__forceinline void grow(const BoundBox& bbox)
{
grow(bbox.min);
diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h
index 00b6cf5c56e..bb6de1197e7 100644
--- a/intern/cycles/util/util_types.h
+++ b/intern/cycles/util/util_types.h
@@ -448,24 +448,6 @@ __device_inline int4 make_int4(const float3& f)
#endif
-typedef enum AttributeStandard {
- ATTR_STD_NONE = 0,
- ATTR_STD_VERTEX_NORMAL,
- ATTR_STD_FACE_NORMAL,
- ATTR_STD_UV,
- ATTR_STD_UV_TANGENT,
- ATTR_STD_UV_TANGENT_SIGN,
- ATTR_STD_GENERATED,
- ATTR_STD_POSITION_UNDEFORMED,
- ATTR_STD_POSITION_UNDISPLACED,
- ATTR_STD_MOTION_PRE,
- ATTR_STD_MOTION_POST,
- ATTR_STD_PARTICLE,
- ATTR_STD_NUM,
-
- ATTR_STD_NOT_FOUND = ~0
-} AttributeStandard;
-
CCL_NAMESPACE_END
#endif /* __UTIL_TYPES_H__ */
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index 39fd038d568..2d9d89d9ad0 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -1579,7 +1579,13 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
case NSScrollWheel:
{
- if (!m_hasMultiTouchTrackpad) {
+ int momentum = 0;
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+ m_hasMultiTouchTrackpad = 0;
+ momentum = [event momentumPhase] || [event phase];
+#endif
+ /* standard scrollwheel case */
+ if (!m_hasMultiTouchTrackpad && momentum == 0) {
GHOST_TInt32 delta;
double deltaF = [event deltaY];
@@ -1593,9 +1599,18 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
else {
NSPoint mousePos = [cocoawindow mouseLocationOutsideOfEventStream];
GHOST_TInt32 x, y;
- double dx = [event deltaX];
- double dy = -[event deltaY];
+ double dx;
+ double dy;
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+ /* with 10.7 nice scrolling deltas are supported */
+ dx = [event scrollingDeltaX];
+ dy = [event scrollingDeltaY];
+
+#else
+ /* trying to pretend you have nice scrolls... */
+ dx = [event deltaX];
+ dy = -[event deltaY];
const double deltaMax = 50.0;
if ((dx == 0) && (dy == 0)) break;
@@ -1612,9 +1627,10 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
else dy += 0.5;
if (dy < -deltaMax) dy= -deltaMax;
else if (dy > deltaMax) dy= deltaMax;
-
- window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
+
dy = -dy;
+#endif
+ window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000, window, GHOST_kTrackpadEventScroll, x, y, dx, dy));
}
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 471505538ba..2d58f0612ce 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -595,6 +595,11 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
[m_window setAcceptsMouseMovedEvents:YES];
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
+ NSView *view = [m_window contentView];
+ [view setAcceptsTouchEvents:YES];
+#endif
+
[m_window registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
NSStringPboardType, NSTIFFPboardType, nil]];
diff --git a/intern/locale/boost_locale_wrapper.cpp b/intern/locale/boost_locale_wrapper.cpp
index 939c66bad13..80e75298d70 100644
--- a/intern/locale/boost_locale_wrapper.cpp
+++ b/intern/locale/boost_locale_wrapper.cpp
@@ -55,44 +55,49 @@ void bl_locale_set(const char *locale)
// Specify location of dictionaries.
gen.add_messages_path(messages_path);
gen.add_messages_domain(default_domain);
- //gen.set_default_messages_domain(default_domain);
+ //gen.set_default_messages_domain(default_domain);
- if (locale && locale[0]) {
- std::locale::global(gen(locale));
- }
- else {
-#if defined (__APPLE__)
- // workaround to get osx system locale from user defaults
- FILE* fp;
- std::string locale_osx = "";
- char result[16];
- int result_len = 0;
+ try {
+ if (locale && locale[0]) {
+ std::locale::global(gen(locale));
+ }
+ else {
+#ifdef __APPLE__
+ // workaround to get osx system locale from user defaults
+ FILE *fp;
+ std::string locale_osx = "";
+ char result[16];
+ int result_len = 0;
- fp = popen("defaults read .GlobalPreferences AppleLocale", "r");
+ fp = popen("defaults read .GlobalPreferences AppleLocale", "r");
- if(fp) {
- result_len = fread(result, 1, sizeof(result) - 1, fp);
+ if (fp) {
+ result_len = fread(result, 1, sizeof(result) - 1, fp);
- if(result_len > 0) {
- result[result_len-1] = '\0'; // \0 terminate and remove \n
- locale_osx = std::string(result) + std::string(".UTF-8");
- }
+ if (result_len > 0) {
+ result[result_len - 1] = '\0'; // \0 terminate and remove \n
+ locale_osx = std::string(result) + std::string(".UTF-8");
+ }
- pclose(fp);
- }
+ pclose(fp);
+ }
- if(locale_osx == "")
- fprintf(stderr, "Locale set: failed to read AppleLocale read from defaults\n");
+ if (locale_osx == "")
+ fprintf(stderr, "Locale set: failed to read AppleLocale read from defaults\n");
- std::locale::global(gen(locale_osx.c_str()));
+ std::locale::global(gen(locale_osx.c_str()));
#else
- std::locale::global(gen(""));
+ std::locale::global(gen(""));
#endif
+ }
+ // Note: boost always uses "C" LC_NUMERIC by default!
+ }
+ catch(std::exception const &e) {
+ std::cout << "bl_locale_set(" << locale << "): " << e.what() << " \n";
}
- // Note: boost always uses "C" LC_NUMERIC by default!
}
-const char* bl_locale_pgettext(const char *msgctxt, const char *msgid)
+const char *bl_locale_pgettext(const char *msgctxt, const char *msgid)
{
// Note: We cannot use short stuff like boost::locale::gettext, because those return
// std::basic_string objects, which c_ptr()-returned char* is no more valid
@@ -107,7 +112,7 @@ const char* bl_locale_pgettext(const char *msgctxt, const char *msgid)
return msgid;
}
catch(std::exception const &e) {
-// std::cout << "boost_locale_pgettext: " << e.what() << " \n";
+// std::cout << "bl_locale_pgettext(" << msgctxt << ", " << msgid << "): " << e.what() << " \n";
return msgid;
}
}
diff --git a/intern/smoke/CMakeLists.txt b/intern/smoke/CMakeLists.txt
index 3b8a4c06e69..b6338f90ebc 100644
--- a/intern/smoke/CMakeLists.txt
+++ b/intern/smoke/CMakeLists.txt
@@ -29,7 +29,7 @@ set(INC
)
set(INC_SYS
- ../../extern/bullet2/src
+ ${BULLET_INCLUDE_DIRS}
${PNG_INCLUDE_DIR}
${ZLIB_INCLUDE_DIRS}
)