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
diff options
context:
space:
mode:
-rw-r--r--intern/cycles/blender/blender_mesh.cpp4
-rw-r--r--intern/cycles/blender/blender_shader.cpp9
-rw-r--r--intern/cycles/graph/node_type.cpp1
-rw-r--r--intern/cycles/kernel/CMakeLists.txt2
-rw-r--r--intern/cycles/kernel/closure/bsdf.h29
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi.h476
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h220
-rw-r--r--intern/cycles/kernel/closure/bsdf_util.h4
-rw-r--r--intern/cycles/kernel/kernel_bake.h15
-rw-r--r--intern/cycles/kernel/kernel_emission.h2
-rw-r--r--intern/cycles/kernel/kernel_path.h4
-rw-r--r--intern/cycles/kernel/kernel_path_branched.h2
-rw-r--r--intern/cycles/kernel/kernel_random.h6
-rw-r--r--intern/cycles/kernel/kernel_shader.h17
-rw-r--r--intern/cycles/kernel/kernel_shadow.h4
-rw-r--r--intern/cycles/kernel/kernel_subsurface.h2
-rw-r--r--intern/cycles/kernel/kernel_types.h62
-rw-r--r--intern/cycles/kernel/osl/osl_closures.cpp130
-rw-r--r--intern/cycles/kernel/osl/osl_closures.h6
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp8
-rw-r--r--intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_glass_bsdf.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_glossy_bsdf.osl2
-rw-r--r--intern/cycles/kernel/shaders/stdosl.h3
-rw-r--r--intern/cycles/kernel/split/kernel_shader_eval.h2
-rw-r--r--intern/cycles/kernel/svm/svm_closure.h47
-rw-r--r--intern/cycles/kernel/svm/svm_types.h3
-rw-r--r--intern/cycles/render/nodes.cpp12
-rw-r--r--intern/cycles/util/util_math.h14
-rw-r--r--intern/cycles/util/util_string.cpp6
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py38
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py49
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py2
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py2
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py2
-rw-r--r--release/scripts/templates_py/external_script_stub.py (renamed from release/scripts/templates_py/script_stub.py)0
-rw-r--r--source/blender/blenkernel/BKE_blender.h5
-rw-r--r--source/blender/blenkernel/BKE_blender_undo.h2
-rw-r--r--source/blender/blenkernel/BKE_displist.h14
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h1
-rw-r--r--source/blender/blenkernel/BKE_text.h1
-rw-r--r--source/blender/blenkernel/CMakeLists.txt3
-rw-r--r--source/blender/blenkernel/intern/blender.c53
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c14
-rw-r--r--source/blender/blenkernel/intern/brush.c15
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c4
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c6
-rw-r--r--source/blender/blenkernel/intern/displist.c14
-rw-r--r--source/blender/blenkernel/intern/idcode.c10
-rw-r--r--source/blender/blenkernel/intern/image.c2
-rw-r--r--source/blender/blenkernel/intern/library_remap.c7
-rw-r--r--source/blender/blenkernel/intern/mesh.c6
-rw-r--r--source/blender/blenkernel/intern/movieclip.c67
-rw-r--r--source/blender/blenkernel/intern/text.c185
-rw-r--r--source/blender/blenlib/BLI_array_utils.h4
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h2
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c4
-rw-r--r--source/blender/blenlib/intern/array_utils.c18
-rw-r--r--source/blender/blenlib/intern/math_geom.c2
-rw-r--r--source/blender/blenlib/intern/path_util.c2
-rw-r--r--source/blender/blenloader/intern/readfile.c1
-rw-r--r--source/blender/blenloader/intern/writefile.c40
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.c128
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c3
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c80
-rw-r--r--source/blender/editors/animation/drivers.c8
-rw-r--r--source/blender/editors/animation/keyframes_edit.c74
-rw-r--r--source/blender/editors/animation/keyframing.c3
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c30
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c60
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h1
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c5
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c46
-rw-r--r--source/blender/editors/include/ED_fileselect.h2
-rw-r--r--source/blender/editors/include/ED_gpencil.h2
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h34
-rw-r--r--source/blender/editors/include/ED_mask.h2
-rw-r--r--source/blender/editors/include/UI_interface.h12
-rw-r--r--source/blender/editors/interface/interface.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c28
-rw-r--r--source/blender/editors/interface/interface_templates.c12
-rw-r--r--source/blender/editors/mask/mask_editaction.c30
-rw-r--r--source/blender/editors/mesh/editface.c3
-rw-r--r--source/blender/editors/object/object_constraint.c76
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/space_action/action_intern.h2
-rw-r--r--source/blender/editors/space_action/action_ops.c10
-rw-r--r--source/blender/editors/space_action/action_select.c259
-rw-r--r--source/blender/editors/space_file/file_intern.h1
-rw-r--r--source/blender/editors/space_file/file_ops.c105
-rw-r--r--source/blender/editors/space_file/file_utils.c17
-rw-r--r--source/blender/editors/space_file/filelist.c9
-rw-r--r--source/blender/editors/space_file/filesel.c4
-rw-r--r--source/blender/editors/space_graph/graph_ops.c7
-rw-r--r--source/blender/editors/space_graph/graph_select.c83
-rw-r--r--source/blender/editors/space_graph/space_graph.c45
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c11
-rw-r--r--source/blender/editors/space_text/text_ops.c3
-rw-r--r--source/blender/editors/space_view3d/drawobject.c18
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c4
-rw-r--r--source/blender/editors/transform/transform.c15
-rw-r--r--source/blender/editors/transform/transform.h4
-rw-r--r--source/blender/editors/transform/transform_ops.c3
-rw-r--r--source/blender/editors/transform/transform_snap_object.c2
-rw-r--r--source/blender/freestyle/intern/system/PythonInterpreter.h3
-rw-r--r--source/blender/gpu/GPU_draw.h6
-rw-r--r--source/blender/gpu/intern/gpu_draw.c149
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex_world.glsl68
-rw-r--r--source/blender/imbuf/intern/thumbs.c4
-rw-r--r--source/blender/makesdna/DNA_anim_types.h5
-rw-r--r--source/blender/makesdna/DNA_node_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_ID.c9
-rw-r--r--source/blender/makesrna/intern/rna_camera.c6
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c2
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c426
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c6
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c21
-rw-r--r--source/blender/makesrna/intern/rna_space.c8
-rw-r--r--source/blender/nodes/NOD_static_types.h2
-rw-r--r--source/blender/python/intern/bpy_operator.c5
-rw-r--r--source/blender/render/intern/source/convertblender.c15
-rw-r--r--source/blender/windowmanager/WM_api.h6
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c9
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c3
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c144
-rw-r--r--source/blender/windowmanager/wm_subwindow.h2
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c4
-rw-r--r--source/creator/CMakeLists.txt4
-rw-r--r--source/creator/creator.c56
-rw-r--r--tests/gtests/blenlib/BLI_array_utils_test.cc82
132 files changed, 2734 insertions, 1240 deletions
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index 80db51148e6..4bd385c4200 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -801,7 +801,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
}
/* free derived mesh */
- b_data.meshes.remove(b_mesh);
+ b_data.meshes.remove(b_mesh, false);
}
}
mesh->geometry_flags = requested_geometry_flags;
@@ -1013,7 +1013,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
sync_curves(mesh, b_mesh, b_ob, true, time_index);
/* free derived mesh */
- b_data.meshes.remove(b_mesh);
+ b_data.meshes.remove(b_mesh, false);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 78a28b7feed..7ca23f23cb4 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -393,6 +393,9 @@ static ShaderNode *add_node(Scene *scene,
case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
break;
+ case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX:
+ aniso->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID;
+ break;
case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
break;
@@ -439,6 +442,9 @@ static ShaderNode *add_node(Scene *scene,
case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY:
glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
break;
+ case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX:
+ glossy->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
+ break;
}
node = glossy;
}
@@ -455,6 +461,9 @@ static ShaderNode *add_node(Scene *scene,
case BL::ShaderNodeBsdfGlass::distribution_GGX:
glass->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
break;
+ case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX:
+ glass->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
+ break;
}
node = glass;
}
diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp
index 6c6035fdb22..5b98de778ad 100644
--- a/intern/cycles/graph/node_type.cpp
+++ b/intern/cycles/graph/node_type.cpp
@@ -89,6 +89,7 @@ ustring SocketType::type_name(Type type)
ustring("boolean"),
ustring("float"),
ustring("int"),
+ ustring("uint"),
ustring("color"),
ustring("vector"),
ustring("point"),
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index ddf12435336..f0adbc03e22 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -76,6 +76,8 @@ set(SRC_CLOSURE_HEADERS
closure/bsdf_diffuse.h
closure/bsdf_diffuse_ramp.h
closure/bsdf_microfacet.h
+ closure/bsdf_microfacet_multi.h
+ closure/bsdf_microfacet_multi_impl.h
closure/bsdf_oren_nayar.h
closure/bsdf_phong_ramp.h
closure/bsdf_reflection.h
diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h
index f0add804c32..f318a61f3a3 100644
--- a/intern/cycles/kernel/closure/bsdf.h
+++ b/intern/cycles/kernel/closure/bsdf.h
@@ -20,6 +20,7 @@
#include "../closure/bsdf_phong_ramp.h"
#include "../closure/bsdf_diffuse_ramp.h"
#include "../closure/bsdf_microfacet.h"
+#include "../closure/bsdf_microfacet_multi.h"
#include "../closure/bsdf_reflection.h"
#include "../closure/bsdf_refraction.h"
#include "../closure/bsdf_transparent.h"
@@ -35,7 +36,7 @@
CCL_NAMESPACE_BEGIN
-ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf)
+ccl_device int bsdf_sample(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf)
{
int label;
@@ -85,6 +86,14 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader
label = bsdf_microfacet_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+ label = bsdf_microfacet_multi_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
+ eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state));
+ break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+ label = bsdf_microfacet_multi_ggx_glass_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
+ eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state));
+ break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
@@ -130,7 +139,7 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader
return label;
}
-ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf)
+ccl_device float3 bsdf_eval(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf)
{
float3 eval;
@@ -172,6 +181,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
eval = bsdf_microfacet_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+ eval = bsdf_microfacet_multi_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
+ break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+ eval = bsdf_microfacet_multi_ggx_glass_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
+ break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
@@ -234,6 +249,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
eval = bsdf_microfacet_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+ eval = bsdf_microfacet_multi_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
+ break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+ eval = bsdf_microfacet_multi_ggx_glass_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
+ break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
@@ -286,6 +307,10 @@ ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness)
#ifdef __SVM__
switch(sc->type) {
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+ bsdf_microfacet_multi_ggx_blur(sc, roughness);
+ break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
new file mode 100644
index 00000000000..6060d7d8ccb
--- /dev/null
+++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
@@ -0,0 +1,476 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Most of the code is based on the supplemental implementations from https://eheitzresearch.wordpress.com/240-2/. */
+
+/* === GGX Microfacet distribution functions === */
+
+/* Isotropic GGX microfacet distribution */
+ccl_device_inline float D_ggx(float3 wm, float alpha)
+{
+ wm.z *= wm.z;
+ alpha *= alpha;
+ float tmp = (1.0f - wm.z) + alpha * wm.z;
+ return alpha / max(M_PI_F * tmp*tmp, 1e-7f);
+}
+
+/* Anisotropic GGX microfacet distribution */
+ccl_device_inline float D_ggx_aniso(const float3 wm, const float2 alpha)
+{
+ float slope_x = -wm.x/alpha.x;
+ float slope_y = -wm.y/alpha.y;
+ float tmp = wm.z*wm.z + slope_x*slope_x + slope_y*slope_y;
+
+ return 1.0f / max(M_PI_F * tmp*tmp * alpha.x*alpha.y, 1e-7f);
+}
+
+/* Sample slope distribution (based on page 14 of the supplemental implementation). */
+ccl_device_inline float2 mf_sampleP22_11(const float cosI, const float2 randU)
+{
+ if(cosI > 0.9999f) {
+ const float r = sqrtf(randU.x / (1.0f - randU.x));
+ const float phi = M_2PI_F * randU.y;
+ return make_float2(r*cosf(phi), r*sinf(phi));
+ }
+
+ const float sinI = sqrtf(1.0f - cosI*cosI);
+ const float tanI = sinI/cosI;
+ const float projA = 0.5f * (cosI + 1.0f);
+ if(projA < 0.0001f)
+ return make_float2(0.0f, 0.0f);
+ const float A = 2.0f*randU.x*projA / cosI - 1.0f;
+ float tmp = A*A-1.0f;
+ if(fabsf(tmp) < 1e-7f)
+ return make_float2(0.0f, 0.0f);
+ tmp = 1.0f / tmp;
+ const float D = safe_sqrtf(tanI*tanI*tmp*tmp - (A*A-tanI*tanI)*tmp);
+
+ const float slopeX2 = tanI*tmp + D;
+ const float slopeX = (A < 0.0f || slopeX2 > 1.0f/tanI)? (tanI*tmp - D) : slopeX2;
+
+ float U2;
+ if(randU.y >= 0.5f)
+ U2 = 2.0f*(randU.y - 0.5f);
+ else
+ U2 = 2.0f*(0.5f - randU.y);
+ const float z = (U2*(U2*(U2*0.27385f-0.73369f)+0.46341f)) / (U2*(U2*(U2*0.093073f+0.309420f)-1.0f)+0.597999f);
+ const float slopeY = z * sqrtf(1.0f + slopeX*slopeX);
+
+ if(randU.y >= 0.5f)
+ return make_float2(slopeX, slopeY);
+ else
+ return make_float2(slopeX, -slopeY);
+}
+
+/* Visible normal sampling for the GGX distribution (based on page 7 of the supplemental implementation). */
+ccl_device_inline float3 mf_sample_vndf(const float3 wi, const float2 alpha, const float2 randU)
+{
+ const float3 wi_11 = normalize(make_float3(alpha.x*wi.x, alpha.y*wi.y, wi.z));
+ const float2 slope_11 = mf_sampleP22_11(wi_11.z, randU);
+
+ const float2 cossin_phi = normalize(make_float2(wi_11.x, wi_11.y));
+ const float slope_x = alpha.x*(cossin_phi.x * slope_11.x - cossin_phi.y * slope_11.y);
+ const float slope_y = alpha.y*(cossin_phi.y * slope_11.x + cossin_phi.x * slope_11.y);
+
+ kernel_assert(isfinite(slope_x));
+ return normalize(make_float3(-slope_x, -slope_y, 1.0f));
+}
+
+/* === Phase functions: Glossy, Diffuse and Glass === */
+
+/* Phase function for reflective materials, either without a fresnel term (for compatibility) or with the conductive fresnel term. */
+ccl_device_inline float3 mf_sample_phase_glossy(const float3 wi, float3 *n, float3 *k, float3 *weight, const float3 wm)
+{
+ if(n && k)
+ *weight *= fresnel_conductor(dot(wi, wm), *n, *k);
+
+ return -wi + 2.0f * wm * dot(wi, wm);
+}
+
+ccl_device_inline float3 mf_eval_phase_glossy(const float3 w, const float lambda, const float3 wo, const float2 alpha, float3 *n, float3 *k)
+{
+ if(w.z > 0.9999f)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ const float3 wh = normalize(wo - w);
+ if(wh.z < 0.0f)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z;
+
+ const float dotW_WH = dot(-w, wh);
+ if(dotW_WH < 0.0f)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ float phase = max(0.0f, dotW_WH) * 0.25f / (pArea * dotW_WH);
+ if(alpha.x == alpha.y)
+ phase *= D_ggx(wh, alpha.x);
+ else
+ phase *= D_ggx_aniso(wh, alpha);
+
+ if(n && k) {
+ /* Apply conductive fresnel term. */
+ return phase * fresnel_conductor(dotW_WH, *n, *k);
+ }
+
+ return make_float3(phase, phase, phase);
+}
+
+/* Phase function for rough lambertian diffuse surfaces. */
+ccl_device_inline float3 mf_sample_phase_diffuse(const float3 wm, const float randu, const float randv)
+{
+ float3 tm, bm;
+ make_orthonormals(wm, &tm, &bm);
+
+ float2 disk = concentric_sample_disk(randu, randv);
+ return disk.x*tm + disk.y*bm + safe_sqrtf(1.0f - disk.x*disk.x - disk.y*disk.y)*wm;
+}
+
+ccl_device_inline float3 mf_eval_phase_diffuse(const float3 w, const float3 wm)
+{
+ const float v = max(0.0f, dot(w, wm)) * M_1_PI_F;
+ return make_float3(v, v, v);
+}
+
+/* Phase function for dielectric transmissive materials, including both reflection and refraction according to the dielectric fresnel term. */
+ccl_device_inline float3 mf_sample_phase_glass(const float3 wi, const float eta, const float3 wm, const float randV, bool *outside)
+{
+ float cosI = dot(wi, wm);
+ float f = fresnel_dielectric_cos(cosI, eta);
+ if(randV < f) {
+ *outside = true;
+ return -wi + 2.0f * wm * cosI;
+ }
+ *outside = false;
+ float inv_eta = 1.0f/eta;
+ float cosT = -safe_sqrtf(1.0f - (1.0f - cosI*cosI) * inv_eta*inv_eta);
+ return normalize(wm*(cosI*inv_eta + cosT) - wi*inv_eta);
+}
+
+ccl_device_inline float3 mf_eval_phase_glass(const float3 w, const float lambda, const float3 wo, const bool wo_outside, const float2 alpha, const float eta)
+{
+ if(w.z > 0.9999f)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z;
+ float v;
+ if(wo_outside) {
+ const float3 wh = normalize(wo - w);
+ if(wh.z < 0.0f)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ const float dotW_WH = dot(-w, wh);
+ v = fresnel_dielectric_cos(dotW_WH, eta) * max(0.0f, dotW_WH) * D_ggx(wh, alpha.x) * 0.25f / (pArea * dotW_WH);
+ }
+ else {
+ float3 wh = normalize(wo*eta - w);
+ if(wh.z < 0.0f)
+ wh = -wh;
+ const float dotW_WH = dot(-w, wh), dotWO_WH = dot(wo, wh);
+ if(dotW_WH < 0.0f)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ float temp = dotW_WH + eta*dotWO_WH;
+ v = (1.0f - fresnel_dielectric_cos(dotW_WH, eta)) * max(0.0f, dotW_WH) * max(0.0f, -dotWO_WH) * D_ggx(wh, alpha.x) / (pArea * temp * temp);
+ }
+
+ return make_float3(v, v, v);
+}
+
+/* === Utility functions for the random walks === */
+
+/* Smith Lambda function for GGX (based on page 12 of the supplemental implementation). */
+ccl_device_inline float mf_lambda(const float3 w, const float2 alpha)
+{
+ if(w.z > 0.9999f)
+ return 0.0f;
+ else if(w.z < -0.9999f)
+ return -1.0f;
+
+ const float inv_wz2 = 1.0f / (w.z*w.z);
+ const float2 wa = make_float2(w.x, w.y)*alpha;
+ float v = sqrtf(1.0f + dot(wa, wa) * inv_wz2);
+ if(w.z <= 0.0f)
+ v = -v;
+
+ return 0.5f*(v - 1.0f);
+}
+
+/* Height distribution CDF (based on page 4 of the supplemental implementation). */
+ccl_device_inline float mf_invC1(const float h)
+{
+ return 2.0f * saturate(h) - 1.0f;
+}
+
+ccl_device_inline float mf_C1(const float h)
+{
+ return saturate(0.5f * (h + 1.0f));
+}
+
+/* Masking function (based on page 16 of the supplemental implementation). */
+ccl_device_inline float mf_G1(const float3 w, const float C1, const float lambda)
+{
+ if(w.z > 0.9999f)
+ return 1.0f;
+ if(w.z < 1e-5f)
+ return 0.0f;
+ return powf(C1, lambda);
+}
+
+/* Sampling from the visible height distribution (based on page 17 of the supplemental implementation). */
+ccl_device_inline bool mf_sample_height(const float3 w, float *h, float *C1, float *G1, float *lambda, const float U)
+{
+ if(w.z > 0.9999f)
+ return false;
+ if(w.z < -0.9999f) {
+ *C1 *= U;
+ *h = mf_invC1(*C1);
+ *G1 = mf_G1(w, *C1, *lambda);
+ }
+ else if(fabsf(w.z) >= 0.0001f) {
+ if(U > 1.0f - *G1)
+ return false;
+ if(*lambda >= 0.0f) {
+ *C1 = 1.0f;
+ }
+ else {
+ *C1 *= powf(1.0f-U, -1.0f / *lambda);
+ }
+ *h = mf_invC1(*C1);
+ *G1 = mf_G1(w, *C1, *lambda);
+ }
+ return true;
+}
+
+/* === PDF approximations for the different phase functions. ===
+ * As explained in bsdf_microfacet_multi_impl.h, using approximations with MIS still produces an unbiased result. */
+
+/* Approximation for the albedo of the single-scattering GGX distribution,
+ * the missing energy is then approximated as a diffuse reflection for the PDF. */
+ccl_device_inline float mf_ggx_albedo(float r)
+{
+ float albedo = 0.806495f*expf(-1.98712f*r*r) + 0.199531f;
+ albedo -= ((((((1.76741f*r - 8.43891f)*r + 15.784f)*r - 14.398f)*r + 6.45221f)*r - 1.19722f)*r + 0.027803f)*r + 0.00568739f;
+ return saturate(albedo);
+}
+
+ccl_device_inline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha)
+{
+ return 0.25f * D_ggx(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, make_float2(alpha, alpha))) * wi.z) + (1.0f - mf_ggx_albedo(alpha)) * wo.z;
+}
+
+ccl_device_inline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo, const float2 alpha)
+{
+ return 0.25f * D_ggx_aniso(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, alpha)) * wi.z) + (1.0f - mf_ggx_albedo(sqrtf(alpha.x*alpha.y))) * wo.z;
+}
+
+ccl_device_inline float mf_diffuse_pdf(const float3 wo)
+{
+ return M_1_PI_F * wo.z;
+}
+
+ccl_device_inline float mf_glass_pdf(const float3 wi, const float3 wo, const float alpha, const float eta)
+{
+ float3 wh;
+ float fresnel;
+ if(wi.z*wo.z > 0.0f) {
+ wh = normalize(wi + wo);
+ fresnel = fresnel_dielectric_cos(dot(wi, wh), eta);
+ }
+ else {
+ wh = normalize(wi + wo*eta);
+ fresnel = 1.0f - fresnel_dielectric_cos(dot(wi, wh), eta);
+ }
+ if(wh.z < 0.0f)
+ wh = -wh;
+ float3 r_wi = (wi.z < 0.0f)? -wi: wi;
+ return fresnel * max(0.0f, dot(r_wi, wh)) * D_ggx(wh, alpha) / ((1.0f + mf_lambda(r_wi, make_float2(alpha, alpha))) * r_wi.z) + fabsf(wo.z);
+}
+
+/* === Actual random walk implementations, one version of mf_eval and mf_sample per phase function. === */
+
+#define MF_NAME_JOIN(x,y) x ## _ ## y
+#define MF_NAME_EVAL(x,y) MF_NAME_JOIN(x,y)
+#define MF_FUNCTION_FULL_NAME(prefix) MF_NAME_EVAL(prefix, MF_PHASE_FUNCTION)
+
+#define MF_PHASE_FUNCTION glass
+#define MF_MULTI_GLASS
+#include "bsdf_microfacet_multi_impl.h"
+
+/* The diffuse phase function is not implemented as a node yet. */
+#if 0
+#define MF_PHASE_FUNCTION diffuse
+#define MF_MULTI_DIFFUSE
+#include "bsdf_microfacet_multi_impl.h"
+#endif
+
+#define MF_PHASE_FUNCTION glossy
+#define MF_MULTI_GLOSSY
+#include "bsdf_microfacet_multi_impl.h"
+
+ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughness)
+{
+ sc->data0 = fmaxf(roughness, sc->data0); /* alpha_x */
+ sc->data1 = fmaxf(roughness, sc->data1); /* alpha_y */
+}
+
+/* === Closure implementations === */
+
+/* Multiscattering GGX Glossy closure */
+
+ccl_device int bsdf_microfacet_multi_ggx_common_setup(ShaderClosure *sc)
+{
+ sc->data0 = clamp(sc->data0, 1e-4f, 1.0f); /* alpha */
+ sc->data1 = clamp(sc->data1, 1e-4f, 1.0f);
+ sc->custom1 = saturate(sc->custom1); /* color */
+ sc->custom2 = saturate(sc->custom2);
+ sc->custom3 = saturate(sc->custom3);
+
+ sc->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
+
+ return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM;
+}
+
+ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(ShaderClosure *sc)
+{
+#ifdef __KERNEL_OPENCL__
+ if(all(sc->T == 0.0f))
+#else
+ if(sc->T == make_float3(0.0f, 0.0f, 0.0f))
+#endif
+ sc->T = make_float3(1.0f, 0.0f, 0.0f);
+
+ return bsdf_microfacet_multi_ggx_common_setup(sc);
+}
+
+ccl_device int bsdf_microfacet_multi_ggx_setup(ShaderClosure *sc)
+{
+ sc->data1 = sc->data0;
+
+ return bsdf_microfacet_multi_ggx_common_setup(sc);
+}
+
+ccl_device float3 bsdf_microfacet_multi_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) {
+ *pdf = 0.0f;
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) {
+ bool is_aniso = (sc->data0 != sc->data1);
+ float3 X, Y, Z;
+ Z = sc->N;
+ if(is_aniso)
+ make_orthonormals_tangent(Z, sc->T, &X, &Y);
+ else
+ make_orthonormals(Z, &X, &Y);
+
+ float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
+ float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z));
+
+ if(is_aniso)
+ *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(sc->data0, sc->data1));
+ else
+ *pdf = mf_ggx_pdf(localI, localO, sc->data0);
+ return mf_eval_glossy(localI, localO, true, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, NULL, NULL);
+}
+
+ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state)
+{
+ bool is_aniso = (sc->data0 != sc->data1);
+ float3 X, Y, Z;
+ Z = sc->N;
+ if(is_aniso)
+ make_orthonormals_tangent(Z, sc->T, &X, &Y);
+ else
+ make_orthonormals(Z, &X, &Y);
+
+ float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
+ float3 localO;
+
+ *eval = mf_sample_glossy(localI, &localO, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, NULL, NULL);
+ if(is_aniso)
+ *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(sc->data0, sc->data1));
+ else
+ *pdf = mf_ggx_pdf(localI, localO, sc->data0);
+ *eval *= *pdf;
+
+ *omega_in = X*localO.x + Y*localO.y + Z*localO.z;
+ return LABEL_REFLECT|LABEL_GLOSSY;
+}
+
+/* Multiscattering GGX Glass closure */
+
+ccl_device int bsdf_microfacet_multi_ggx_glass_setup(ShaderClosure *sc)
+{
+ sc->data0 = clamp(sc->data0, 1e-4f, 1.0f); /* alpha */
+ sc->data1 = sc->data0;
+ sc->data2 = max(0.0f, sc->data2); /* ior */
+ sc->custom1 = saturate(sc->custom1); /* color */
+ sc->custom2 = saturate(sc->custom2);
+ sc->custom3 = saturate(sc->custom3);
+
+ sc->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
+
+ return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM;
+}
+
+ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) {
+ float3 X, Y, Z;
+ Z = sc->N;
+ make_orthonormals(Z, &X, &Y);
+
+ float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
+ float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z));
+
+ *pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2);
+ return mf_eval_glass(localI, localO, false, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2);
+}
+
+ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) {
+ float3 X, Y, Z;
+ Z = sc->N;
+ make_orthonormals(Z, &X, &Y);
+
+ float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
+ float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z));
+
+ *pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2);
+ return mf_eval_glass(localI, localO, true, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2);
+}
+
+ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state)
+{
+ float3 X, Y, Z;
+ Z = sc->N;
+ make_orthonormals(Z, &X, &Y);
+
+ float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
+ float3 localO;
+
+ *eval = mf_sample_glass(localI, &localO, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2);
+ *pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2);
+ *eval *= *pdf;
+
+ *omega_in = X*localO.x + Y*localO.y + Z*localO.z;
+ if(localO.z*localI.z > 0.0f)
+ return LABEL_REFLECT|LABEL_GLOSSY;
+ else
+ return LABEL_TRANSMIT|LABEL_GLOSSY;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h
new file mode 100644
index 00000000000..8f8e19dd059
--- /dev/null
+++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Evaluate the BSDF from wi to wo.
+ * Evaluation is split into the analytical single-scattering BSDF and the multi-scattering BSDF,
+ * which is evaluated stochastically through a random walk. At each bounce (except for the first one),
+ * the amount of reflection from here towards wo is evaluated before bouncing again.
+ *
+ * Because of the random walk, the evaluation is not deterministic, but its expected value is equal to
+ * the correct BSDF, which is enough for Monte-Carlo rendering. The PDF also can't be determined
+ * analytically, so the single-scattering PDF plus a diffuse term to account for the multi-scattered
+ * energy is used. In combination with MIS, that is enough to produce an unbiased result, although
+ * the balance heuristic isn't necessarily optimal anymore.
+ */
+ccl_device float3 MF_FUNCTION_FULL_NAME(mf_eval)(float3 wi, float3 wo, const bool wo_outside, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint* lcg_state
+#ifdef MF_MULTI_GLASS
+ , const float eta
+#elif defined(MF_MULTI_GLOSSY)
+ , float3 *n, float3 *k
+#endif
+)
+{
+ /* Evaluating for a shallower incoming direction produces less noise, and the properties of the BSDF guarantee reciprocity. */
+ bool swapped = false;
+#ifdef MF_MULTI_GLASS
+ if(wi.z*wo.z < 0.0f) {
+ /* Glass transmission is a special case and requires the directions to change hemisphere. */
+ if(-wo.z < wi.z) {
+ swapped = true;
+ float3 tmp = -wo;
+ wo = -wi;
+ wi = tmp;
+ }
+ }
+ else
+#endif
+ if(wo.z < wi.z) {
+ swapped = true;
+ float3 tmp = wo;
+ wo = wi;
+ wi = tmp;
+ }
+
+ if(wi.z < 1e-5f || (wo.z < 1e-5f && wo_outside) || (wo.z > -1e-5f && !wo_outside))
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ const float2 alpha = make_float2(alpha_x, alpha_y);
+
+ float lambda_r = mf_lambda(-wi, alpha);
+ float shadowing_lambda = mf_lambda(wo_outside? wo: -wo, alpha);
+
+ /* Analytically compute single scattering for lower noise. */
+ float3 eval;
+#ifdef MF_MULTI_GLASS
+ eval = mf_eval_phase_glass(-wi, lambda_r, wo, wo_outside, alpha, eta);
+ if(wo_outside)
+ eval *= -lambda_r / (shadowing_lambda - lambda_r);
+ else
+ eval *= -lambda_r * beta(-lambda_r, shadowing_lambda+1.0f);
+#elif defined(MF_MULTI_DIFFUSE)
+ /* Diffuse has no special closed form for the single scattering bounce */
+ eval = make_float3(0.0f, 0.0f, 0.0f);
+#else /* MF_MULTI_GLOSSY */
+ const float3 wh = normalize(wi+wo);
+ const float G2 = 1.0f / (1.0f - (lambda_r + 1.0f) + shadowing_lambda);
+ float val = G2 * 0.25f / wi.z;
+ if(alpha.x == alpha.y)
+ val *= D_ggx(wh, alpha.x);
+ else
+ val *= D_ggx_aniso(wh, alpha);
+ if(n && k) {
+ eval = fresnel_conductor(dot(wh, wi), *n, *k) * val;
+ }
+ else {
+ eval = make_float3(val, val, val);
+ }
+#endif
+
+ float3 wr = -wi;
+ float hr = 1.0f;
+ float C1_r = 1.0f;
+ float G1_r = 0.0f;
+ bool outside = true;
+ float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
+
+ for(int order = 0; order < 10; order++) {
+ /* Sample microfacet height and normal */
+ if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float(lcg_state)))
+ break;
+ float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float(lcg_state), lcg_step_float(lcg_state)));
+
+#ifdef MF_MULTI_DIFFUSE
+ if(order == 0) {
+ /* Compute single-scattering for diffuse. */
+ const float G2_G1 = -lambda_r / (shadowing_lambda - lambda_r);
+ eval += throughput * G2_G1 * mf_eval_phase_diffuse(wo, wm);
+ }
+#endif
+ if(order > 0) {
+ /* Evaluate amount of scattering towards wo on this microfacet. */
+ float3 phase;
+#ifdef MF_MULTI_GLASS
+ if(outside)
+ phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta);
+ else
+ phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f/eta);
+#elif defined(MF_MULTI_DIFFUSE)
+ phase = mf_eval_phase_diffuse(wo, wm);
+#else /* MF_MULTI_GLOSSY */
+ phase = mf_eval_phase_glossy(wr, lambda_r, wo, alpha, n, k) * throughput;
+#endif
+ eval += throughput * phase * mf_G1(wo_outside? wo: -wo, mf_C1((outside == wo_outside)? hr: -hr), shadowing_lambda);
+ }
+ if(order+1 < 10) {
+ /* Bounce from the microfacet. */
+#ifdef MF_MULTI_GLASS
+ bool next_outside;
+ wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float(lcg_state), &next_outside);
+ if(!next_outside) {
+ outside = !outside;
+ wr = -wr;
+ hr = -hr;
+ }
+#elif defined(MF_MULTI_DIFFUSE)
+ wr = mf_sample_phase_diffuse(wm, lcg_step_float(lcg_state), lcg_step_float(lcg_state));
+#else /* MF_MULTI_GLOSSY */
+ wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm);
+#endif
+
+ lambda_r = mf_lambda(wr, alpha);
+
+ throughput *= color;
+
+ C1_r = mf_C1(hr);
+ G1_r = mf_G1(wr, C1_r, lambda_r);
+ }
+ }
+
+ if(swapped)
+ eval *= fabsf(wi.z / wo.z);
+ return eval;
+}
+
+/* Perform a random walk on the microsurface starting from wi, returning the direction in which the walk
+ * escaped the surface in wo. The function returns the throughput between wi and wo.
+ * Without reflection losses due to coloring or fresnel absorption in conductors, the sampling is optimal.
+ */
+ccl_device float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3 *wo, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint *lcg_state
+#ifdef MF_MULTI_GLASS
+ , const float eta
+#elif defined(MF_MULTI_GLOSSY)
+ , float3 *n, float3 *k
+#endif
+)
+{
+ const float2 alpha = make_float2(alpha_x, alpha_y);
+
+ float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
+ float3 wr = -wi;
+ float lambda_r = mf_lambda(wr, alpha);
+ float hr = 1.0f;
+ float C1_r = 1.0f;
+ float G1_r = 0.0f;
+ bool outside = true;
+
+ int order;
+ for(order = 0; order < 10; order++) {
+ /* Sample microfacet height. */
+ if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float(lcg_state))) {
+ /* The random walk has left the surface. */
+ *wo = outside? wr: -wr;
+ return throughput;
+ }
+ /* Sample microfacet normal. */
+ float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float(lcg_state), lcg_step_float(lcg_state)));
+
+ /* First-bounce color is already accounted for in mix weight. */
+ if(order > 0)
+ throughput *= color;
+
+ /* Bounce from the microfacet. */
+#ifdef MF_MULTI_GLASS
+ bool next_outside;
+ wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float(lcg_state), &next_outside);
+ if(!next_outside) {
+ hr = -hr;
+ wr = -wr;
+ outside = !outside;
+ }
+#elif defined(MF_MULTI_DIFFUSE)
+ wr = mf_sample_phase_diffuse(wm, lcg_step_float(lcg_state), lcg_step_float(lcg_state));
+#else /* MF_MULTI_GLOSSY */
+ wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm);
+#endif
+
+ /* Update random walk parameters. */
+ lambda_r = mf_lambda(wr, alpha);
+ G1_r = mf_G1(wr, C1_r, lambda_r);
+ }
+ *wo = make_float3(0.0f, 0.0f, 1.0f);
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+#undef MF_MULTI_GLASS
+#undef MF_MULTI_DIFFUSE
+#undef MF_MULTI_GLOSSY
+#undef MF_PHASE_FUNCTION
diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h
index 05816bac2c1..89b1998d1ce 100644
--- a/intern/cycles/kernel/closure/bsdf_util.h
+++ b/intern/cycles/kernel/closure/bsdf_util.h
@@ -111,10 +111,9 @@ ccl_device float fresnel_dielectric_cos(float cosi, float eta)
return 1.0f; // TIR(no refracted component)
}
-#if 0
ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k)
{
- float3 cosi2 = make_float3(cosi*cosi);
+ float3 cosi2 = make_float3(cosi*cosi, cosi*cosi, cosi*cosi);
float3 one = make_float3(1.0f, 1.0f, 1.0f);
float3 tmp_f = eta * eta + k * k;
float3 tmp = tmp_f * cosi2;
@@ -124,7 +123,6 @@ ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k
(tmp_f + (2.0f * eta * cosi) + cosi2);
return(Rparl2 + Rperp2) * 0.5f;
}
-#endif
ccl_device float smooth_step(float edge0, float edge1, float x)
{
diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h
index 8d05befe1d4..9ee0b09529e 100644
--- a/intern/cycles/kernel/kernel_bake.h
+++ b/intern/cycles/kernel/kernel_bake.h
@@ -48,7 +48,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
/* evaluate surface shader */
float rbsdf = path_state_rng_1D(kg, &rng, &state, PRNG_BSDF);
- shader_eval_surface(kg, sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, sd, &rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
/* TODO, disable the closures we won't need */
@@ -220,6 +220,7 @@ ccl_device_inline float3 kernel_bake_shader_bsdf(KernelGlobals *kg,
ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg,
ShaderData *sd,
+ RNG *rng,
PathState *state,
float3 direct,
float3 indirect,
@@ -239,12 +240,12 @@ ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg,
}
else {
/* surface color of the pass only */
- shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN);
return kernel_bake_shader_bsdf(kg, sd, type);
}
}
else {
- shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN);
color = kernel_bake_shader_bsdf(kg, sd, type);
}
@@ -336,7 +337,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
case SHADER_EVAL_NORMAL:
{
if((sd.flag & SD_HAS_BUMP)) {
- shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_MAIN);
}
/* compression: normal = (2 * color) - 1 */
@@ -350,7 +351,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
}
case SHADER_EVAL_EMISSION:
{
- shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_EMISSION);
+ shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_EMISSION);
out = shader_emissive_eval(kg, &sd);
break;
}
@@ -403,6 +404,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
{
out = kernel_bake_evaluate_direct_indirect(kg,
&sd,
+ &rng,
&state,
L.direct_diffuse,
L.indirect_diffuse,
@@ -414,6 +416,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
{
out = kernel_bake_evaluate_direct_indirect(kg,
&sd,
+ &rng,
&state,
L.direct_glossy,
L.indirect_glossy,
@@ -425,6 +428,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
{
out = kernel_bake_evaluate_direct_indirect(kg,
&sd,
+ &rng,
&state,
L.direct_transmission,
L.indirect_transmission,
@@ -437,6 +441,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
#ifdef __SUBSURFACE__
out = kernel_bake_evaluate_direct_indirect(kg,
&sd,
+ &rng,
&state,
L.direct_subsurface,
L.indirect_subsurface,
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index e22bcead404..149ac3ed4f9 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -57,7 +57,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
/* no path flag, we're evaluating this for all closures. that's weak but
* we'd have to do multiple evaluations otherwise */
path_state_modify_bounce(state, true);
- shader_eval_surface(kg, emission_sd, state, 0.0f, 0, SHADER_CONTEXT_EMISSION);
+ shader_eval_surface(kg, emission_sd, NULL, state, 0.0f, 0, SHADER_CONTEXT_EMISSION);
path_state_modify_bounce(state, false);
/* evaluate emissive closure */
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 0dded397ffa..3c3503eab8b 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -253,7 +253,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
&isect,
ray);
float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF);
- shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT);
+ shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT);
#ifdef __BRANCHED_PATH__
shader_merge_closures(sd);
#endif
@@ -791,7 +791,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
/* setup shading */
shader_setup_from_ray(kg, &sd, &isect, &ray);
float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF);
- shader_eval_surface(kg, &sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, &sd, rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
/* holdout */
#ifdef __HOLDOUT__
diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h
index fdba1a7b025..56516967d8f 100644
--- a/intern/cycles/kernel/kernel_path_branched.h
+++ b/intern/cycles/kernel/kernel_path_branched.h
@@ -463,7 +463,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
/* setup shading */
shader_setup_from_ray(kg, &sd, &isect, &ray);
- shader_eval_surface(kg, &sd, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, &sd, rng, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
shader_merge_closures(&sd);
/* holdout */
diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h
index 631a2cb75de..bf3c25d2cb2 100644
--- a/intern/cycles/kernel/kernel_random.h
+++ b/intern/cycles/kernel/kernel_random.h
@@ -232,14 +232,14 @@ ccl_device void path_rng_end(KernelGlobals *kg, ccl_global uint *rng_state, RNG
/* Linear Congruential Generator */
-ccl_device uint lcg_step_uint(uint *rng)
+ccl_device uint lcg_step_uint(ccl_addr_space uint *rng)
{
/* implicit mod 2^32 */
*rng = (1103515245*(*rng) + 12345);
return *rng;
}
-ccl_device float lcg_step_float(uint *rng)
+ccl_device float lcg_step_float(ccl_addr_space uint *rng)
{
/* implicit mod 2^32 */
*rng = (1103515245*(*rng) + 12345);
@@ -309,7 +309,7 @@ ccl_device_inline void path_state_branch(PathState *state, int branch, int num_b
state->num_samples = state->num_samples*num_branches;
}
-ccl_device_inline uint lcg_state_init(RNG *rng, const PathState *state, uint scramble)
+ccl_device_inline uint lcg_state_init(RNG *rng, const ccl_addr_space PathState *state, uint scramble)
{
return lcg_init(*rng + state->rng_offset + state->sample*scramble);
}
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index a0b56118ab7..3a4770f82f1 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -468,6 +468,9 @@ ccl_device void shader_merge_closures(ShaderData *sd)
continue;
}
+ if((sd->flag & SD_BSDF_HAS_CUSTOM) && !(sci->custom1 == scj->custom1 && sci->custom2 == scj->custom2 && sci->custom3 == scj->custom3))
+ continue;
+
sci->weight += scj->weight;
sci->sample_weight += scj->sample_weight;
@@ -488,7 +491,7 @@ ccl_device void shader_merge_closures(ShaderData *sd)
/* BSDF */
-ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderData *sd, const float3 omega_in, float *pdf,
+ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, ShaderData *sd, const float3 omega_in, float *pdf,
int skip_bsdf, BsdfEval *result_eval, float sum_pdf, float sum_sample_weight)
{
/* this is the veach one-sample model with balance heuristic, some pdf
@@ -517,7 +520,7 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderDa
#ifdef __BRANCHED_PATH__
ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg,
- const ShaderData *sd,
+ ShaderData *sd,
const float3 omega_in,
BsdfEval *result_eval,
float light_pdf,
@@ -563,7 +566,7 @@ ccl_device void shader_bsdf_eval(KernelGlobals *kg,
}
}
-ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
+ccl_device int shader_bsdf_sample(KernelGlobals *kg, ShaderData *sd,
float randu, float randv, BsdfEval *bsdf_eval,
float3 *omega_in, differential3 *domega_in, float *pdf)
{
@@ -620,7 +623,7 @@ ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
return label;
}
-ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, const ShaderData *sd,
+ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, ShaderData *sd,
const ShaderClosure *sc, float randu, float randv, BsdfEval *bsdf_eval,
float3 *omega_in, differential3 *domega_in, float *pdf)
{
@@ -824,7 +827,7 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)
/* Surface Evaluation */
-ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
+ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, RNG *rng,
ccl_addr_space PathState *state, float randb, int path_flag, ShaderContext ctx)
{
ccl_fetch(sd, num_closure) = 0;
@@ -846,6 +849,10 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
ccl_fetch(sd, flag) |= bsdf_diffuse_setup(ccl_fetch_array(sd, closure, 0));
#endif
}
+
+ if(rng && (ccl_fetch(sd, flag) & SD_BSDF_NEEDS_LCG)) {
+ ccl_fetch(sd, lcg_state) = lcg_state_init(rng, state, 0xb4bc3953);
+ }
}
/* Background Evaluation */
diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h
index 1abbbb2ddad..db2fc84834a 100644
--- a/intern/cycles/kernel/kernel_shadow.h
+++ b/intern/cycles/kernel/kernel_shadow.h
@@ -117,7 +117,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd,
/* attenuation from transparent surface */
if(!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) {
path_state_modify_bounce(state, true);
- shader_eval_surface(kg, shadow_sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
+ shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
path_state_modify_bounce(state, false);
throughput *= shader_bsdf_transparency(kg, shadow_sd);
@@ -252,7 +252,7 @@ ccl_device_noinline bool shadow_blocked(KernelGlobals *kg,
/* attenuation from transparent surface */
if(!(ccl_fetch(shadow_sd, flag) & SD_HAS_ONLY_VOLUME)) {
path_state_modify_bounce(state, true);
- shader_eval_surface(kg, shadow_sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
+ shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
path_state_modify_bounce(state, false);
throughput *= shader_bsdf_transparency(kg, shadow_sd);
diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h
index 705b57ba6ff..b048bd38fc9 100644
--- a/intern/cycles/kernel/kernel_subsurface.h
+++ b/intern/cycles/kernel/kernel_subsurface.h
@@ -198,7 +198,7 @@ ccl_device void subsurface_color_bump_blur(KernelGlobals *kg,
if(bump || texture_blur > 0.0f) {
/* average color and normal at incoming point */
- shader_eval_surface(kg, sd, state, 0.0f, state_flag, SHADER_CONTEXT_SSS);
+ shader_eval_surface(kg, sd, NULL, state, 0.0f, state_flag, SHADER_CONTEXT_SSS);
float3 in_color = shader_bssrdf_sum(sd, (bump)? N: NULL, NULL);
/* we simply divide out the average color and multiply with the average
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index aa5eeebda7b..76d2a6b98e6 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -679,31 +679,34 @@ typedef enum ShaderContext {
enum ShaderDataFlag {
/* runtime flags */
- SD_BACKFACING = (1 << 0), /* backside of surface? */
- SD_EMISSION = (1 << 1), /* have emissive closure? */
- SD_BSDF = (1 << 2), /* have bsdf closure? */
- SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */
- SD_BSSRDF = (1 << 4), /* have bssrdf */
- SD_HOLDOUT = (1 << 5), /* have holdout closure? */
- SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */
- SD_SCATTER = (1 << 7), /* have volume phase closure? */
- SD_AO = (1 << 8), /* have ao closure? */
- SD_TRANSPARENT = (1 << 9), /* have transparent closure? */
+ SD_BACKFACING = (1 << 0), /* backside of surface? */
+ SD_EMISSION = (1 << 1), /* have emissive closure? */
+ SD_BSDF = (1 << 2), /* have bsdf closure? */
+ SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */
+ SD_BSSRDF = (1 << 4), /* have bssrdf */
+ SD_HOLDOUT = (1 << 5), /* have holdout closure? */
+ SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */
+ SD_SCATTER = (1 << 7), /* have volume phase closure? */
+ SD_AO = (1 << 8), /* have ao closure? */
+ SD_TRANSPARENT = (1 << 9), /* have transparent closure? */
+ SD_BSDF_NEEDS_LCG = (1 << 10),
+ SD_BSDF_HAS_CUSTOM = (1 << 11), /* are the custom variables relevant? */
SD_CLOSURE_FLAGS = (SD_EMISSION|SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF|
- SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO),
+ SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO|
+ SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM),
/* shader flags */
- SD_USE_MIS = (1 << 10), /* direct light sample */
- SD_HAS_TRANSPARENT_SHADOW = (1 << 11), /* has transparent shadow */
- SD_HAS_VOLUME = (1 << 12), /* has volume shader */
- SD_HAS_ONLY_VOLUME = (1 << 13), /* has only volume shader, no surface */
- SD_HETEROGENEOUS_VOLUME = (1 << 14), /* has heterogeneous volume */
- SD_HAS_BSSRDF_BUMP = (1 << 15), /* bssrdf normal uses bump */
- SD_VOLUME_EQUIANGULAR = (1 << 16), /* use equiangular sampling */
- SD_VOLUME_MIS = (1 << 17), /* use multiple importance sampling */
- SD_VOLUME_CUBIC = (1 << 18), /* use cubic interpolation for voxels */
- SD_HAS_BUMP = (1 << 19), /* has data connected to the displacement input */
+ SD_USE_MIS = (1 << 12), /* direct light sample */
+ SD_HAS_TRANSPARENT_SHADOW = (1 << 13), /* has transparent shadow */
+ SD_HAS_VOLUME = (1 << 14), /* has volume shader */
+ SD_HAS_ONLY_VOLUME = (1 << 15), /* has only volume shader, no surface */
+ SD_HETEROGENEOUS_VOLUME = (1 << 16), /* has heterogeneous volume */
+ SD_HAS_BSSRDF_BUMP = (1 << 17), /* bssrdf normal uses bump */
+ SD_VOLUME_EQUIANGULAR = (1 << 18), /* use equiangular sampling */
+ SD_VOLUME_MIS = (1 << 19), /* use multiple importance sampling */
+ SD_VOLUME_CUBIC = (1 << 20), /* use cubic interpolation for voxels */
+ SD_HAS_BUMP = (1 << 21), /* has data connected to the displacement input */
SD_SHADER_FLAGS = (SD_USE_MIS|SD_HAS_TRANSPARENT_SHADOW|SD_HAS_VOLUME|
SD_HAS_ONLY_VOLUME|SD_HETEROGENEOUS_VOLUME|
@@ -711,13 +714,13 @@ enum ShaderDataFlag {
SD_VOLUME_CUBIC|SD_HAS_BUMP),
/* object flags */
- SD_HOLDOUT_MASK = (1 << 20), /* holdout for camera rays */
- SD_OBJECT_MOTION = (1 << 21), /* has object motion blur */
- SD_TRANSFORM_APPLIED = (1 << 22), /* vertices have transform applied */
- SD_NEGATIVE_SCALE_APPLIED = (1 << 23), /* vertices have negative scale applied */
- SD_OBJECT_HAS_VOLUME = (1 << 24), /* object has a volume shader */
- SD_OBJECT_INTERSECTS_VOLUME = (1 << 25), /* object intersects AABB of an object with volume shader */
- SD_OBJECT_HAS_VERTEX_MOTION = (1 << 26), /* has position for motion vertices */
+ SD_HOLDOUT_MASK = (1 << 22), /* holdout for camera rays */
+ SD_OBJECT_MOTION = (1 << 23), /* has object motion blur */
+ SD_TRANSFORM_APPLIED = (1 << 24), /* vertices have transform applied */
+ SD_NEGATIVE_SCALE_APPLIED = (1 << 25), /* vertices have negative scale applied */
+ SD_OBJECT_HAS_VOLUME = (1 << 26), /* object has a volume shader */
+ SD_OBJECT_INTERSECTS_VOLUME = (1 << 27), /* object intersects AABB of an object with volume shader */
+ SD_OBJECT_HAS_VERTEX_MOTION = (1 << 28), /* has position for motion vertices */
SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED|
SD_NEGATIVE_SCALE_APPLIED|SD_OBJECT_HAS_VOLUME|
@@ -806,6 +809,9 @@ typedef ccl_addr_space struct ShaderData {
int num_closure;
float randb_closure;
+ /* LCG state for closures that require additional random numbers. */
+ uint lcg_state;
+
/* ray start position, only set for backgrounds */
float3 ray_P;
differential3 ray_dP;
diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp
index 95b8cea0922..02b1491489c 100644
--- a/intern/cycles/kernel/osl/osl_closures.cpp
+++ b/intern/cycles/kernel/osl/osl_closures.cpp
@@ -44,11 +44,13 @@
#include "kernel_compat_cpu.h"
#include "kernel_globals.h"
#include "kernel_montecarlo.h"
+#include "kernel_random.h"
#include "closure/bsdf_util.h"
#include "closure/bsdf_ashikhmin_velvet.h"
#include "closure/bsdf_diffuse.h"
#include "closure/bsdf_microfacet.h"
+#include "closure/bsdf_microfacet_multi.h"
#include "closure/bsdf_oren_nayar.h"
#include "closure/bsdf_reflection.h"
#include "closure/bsdf_refraction.h"
@@ -205,6 +207,12 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
bsdf_microfacet_ggx_aniso_params(), bsdf_microfacet_ggx_aniso_prepare);
register_closure(ss, "microfacet_ggx_refraction", id++,
bsdf_microfacet_ggx_refraction_params(), bsdf_microfacet_ggx_refraction_prepare);
+ register_closure(ss, "microfacet_multi_ggx", id++,
+ closure_bsdf_microfacet_multi_ggx_params(), closure_bsdf_microfacet_multi_ggx_prepare);
+ register_closure(ss, "microfacet_multi_ggx_glass", id++,
+ closure_bsdf_microfacet_multi_ggx_glass_params(), closure_bsdf_microfacet_multi_ggx_glass_prepare);
+ register_closure(ss, "microfacet_multi_ggx_aniso", id++,
+ closure_bsdf_microfacet_multi_ggx_aniso_params(), closure_bsdf_microfacet_multi_ggx_aniso_prepare);
register_closure(ss, "microfacet_beckmann", id++,
bsdf_microfacet_beckmann_params(), bsdf_microfacet_beckmann_prepare);
register_closure(ss, "microfacet_beckmann_aniso", id++,
@@ -250,5 +258,127 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
volume_absorption_params(), volume_absorption_prepare);
}
+/* Multiscattering GGX closures */
+
+class MicrofacetMultiClosure : public CBSDFClosure {
+public:
+ float3 color;
+
+ /* Technically, the MultiGGX Glass closure may also transmit.
+ * However, since this is set statically and only used for caustic flags, this is probably as good as it gets. */
+ MicrofacetMultiClosure() : CBSDFClosure(LABEL_GLOSSY|LABEL_REFLECT)
+ {
+ }
+
+ void setup()
+ {
+ sc.prim = NULL;
+ sc.custom1 = color.x;
+ sc.custom2 = color.y;
+ sc.custom3 = color.z;
+ }
+
+ void blur(float roughness)
+ {
+ }
+
+ float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const
+ {
+ pdf = 0.0f;
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+
+ float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float& pdf) const
+ {
+ pdf = 0.0f;
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+
+ int sample(const float3 &Ng,
+ const float3 &omega_out, const float3 &domega_out_dx, const float3 &domega_out_dy,
+ float randu, float randv,
+ float3 &omega_in, float3 &domega_in_dx, float3 &domega_in_dy,
+ float &pdf, float3 &eval) const
+ {
+ pdf = 0;
+ return LABEL_NONE;
+ }
+};
+
+class MicrofacetMultiGGXClosure : public MicrofacetMultiClosure {
+public:
+ MicrofacetMultiGGXClosure() : MicrofacetMultiClosure() {}
+
+ void setup()
+ {
+ MicrofacetMultiClosure::setup();
+ m_shaderdata_flag = bsdf_microfacet_multi_ggx_setup(&sc);
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_multi_ggx_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
+ CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)
+ };
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_prepare, MicrofacetMultiGGXClosure);
+
+class MicrofacetMultiGGXAnisoClosure : public MicrofacetMultiClosure {
+public:
+ MicrofacetMultiGGXAnisoClosure() : MicrofacetMultiClosure() {}
+
+ void setup()
+ {
+ MicrofacetMultiClosure::setup();
+ m_shaderdata_flag = bsdf_microfacet_multi_ggx_aniso_setup(&sc);
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.T),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data1),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
+ CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)
+ };
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_aniso_prepare, MicrofacetMultiGGXAnisoClosure);
+
+class MicrofacetMultiGGXGlassClosure : public MicrofacetMultiClosure {
+public:
+ MicrofacetMultiGGXGlassClosure() : MicrofacetMultiClosure() {}
+
+ void setup()
+ {
+ MicrofacetMultiClosure::setup();
+ m_shaderdata_flag = bsdf_microfacet_multi_ggx_glass_setup(&sc);
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data2),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
+ CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)
+ };
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_prepare, MicrofacetMultiGGXGlassClosure);
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h
index 1578d06cd56..c5a1a29b6af 100644
--- a/intern/cycles/kernel/osl/osl_closures.h
+++ b/intern/cycles/kernel/osl/osl_closures.h
@@ -52,6 +52,9 @@ OSL::ClosureParam *closure_bssrdf_cubic_params();
OSL::ClosureParam *closure_bssrdf_gaussian_params();
OSL::ClosureParam *closure_bssrdf_burley_params();
OSL::ClosureParam *closure_henyey_greenstein_volume_params();
+OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_params();
+OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params();
+OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params();
void closure_emission_prepare(OSL::RendererServices *, int id, void *data);
void closure_background_prepare(OSL::RendererServices *, int id, void *data);
@@ -63,6 +66,9 @@ void closure_bssrdf_cubic_prepare(OSL::RendererServices *, int id, void *data);
void closure_bssrdf_gaussian_prepare(OSL::RendererServices *, int id, void *data);
void closure_bssrdf_burley_prepare(OSL::RendererServices *, int id, void *data);
void closure_henyey_greenstein_volume_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_microfacet_multi_ggx_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_microfacet_multi_ggx_glass_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_microfacet_multi_ggx_aniso_prepare(OSL::RendererServices *, int id, void *data);
#define CCLOSURE_PREPARE(name, classname) \
void name(RendererServices *, int id, void *data) \
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
index f58368e6789..6cde7419e10 100644
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ b/intern/cycles/kernel/osl/osl_shader.cpp
@@ -177,6 +177,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
case CClosurePrimitive::BSDF: {
CBSDFClosure *bsdf = (CBSDFClosure *)prim;
int scattering = bsdf->scattering();
+ int shaderdata_flag = bsdf->shaderdata_flag();
/* caustic options */
if((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) {
@@ -201,11 +202,16 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
sc.data1 = bsdf->sc.data1;
sc.data2 = bsdf->sc.data2;
sc.prim = bsdf->sc.prim;
+ if(shaderdata_flag & SD_BSDF_HAS_CUSTOM) {
+ sc.custom1 = bsdf->sc.custom1;
+ sc.custom2 = bsdf->sc.custom2;
+ sc.custom3 = bsdf->sc.custom3;
+ }
/* add */
if(sc.sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure < MAX_CLOSURE) {
sd->closure[sd->num_closure++] = sc;
- sd->flag |= bsdf->shaderdata_flag();
+ sd->flag |= shaderdata_flag;
}
break;
}
diff --git a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl
index f7f89543aa9..bef6d7e8809 100644
--- a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl
@@ -51,6 +51,8 @@ shader node_anisotropic_bsdf(
BSDF = Color * microfacet_beckmann_aniso(Normal, T, RoughnessU, RoughnessV);
else if (distribution == "GGX")
BSDF = Color * microfacet_ggx_aniso(Normal, T, RoughnessU, RoughnessV);
+ else if (distribution == "Multiscatter GGX")
+ BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, RoughnessU, RoughnessV, Color);
else
BSDF = Color * ashikhmin_shirley(Normal, T, RoughnessU, RoughnessV);
}
diff --git a/intern/cycles/kernel/shaders/node_glass_bsdf.osl b/intern/cycles/kernel/shaders/node_glass_bsdf.osl
index 8fd0a2fd714..a9723a8300a 100644
--- a/intern/cycles/kernel/shaders/node_glass_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_glass_bsdf.osl
@@ -35,6 +35,8 @@ shader node_glass_bsdf(
else if (distribution == "beckmann")
BSDF = Color * (Fr * microfacet_beckmann(Normal, Roughness) +
(1.0 - Fr) * microfacet_beckmann_refraction(Normal, Roughness, eta));
+ else if (distribution == "Multiscatter GGX")
+ BSDF = Color * microfacet_multi_ggx_glass(Normal, Roughness, eta, Color);
else if (distribution == "GGX")
BSDF = Color * (Fr * microfacet_ggx(Normal, Roughness) +
(1.0 - Fr) * microfacet_ggx_refraction(Normal, Roughness, eta));
diff --git a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl
index cc2a66fd46a..f4ea7e7dc6a 100644
--- a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl
@@ -30,6 +30,8 @@ shader node_glossy_bsdf(
BSDF = Color * microfacet_beckmann(Normal, Roughness);
else if (distribution == "GGX")
BSDF = Color * microfacet_ggx(Normal, Roughness);
+ else if (distribution == "Multiscatter GGX")
+ BSDF = Color * microfacet_multi_ggx(Normal, Roughness, Color);
else
BSDF = Color * ashikhmin_shirley(Normal, vector(0, 0, 0), Roughness, Roughness);
diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h
index 8d5d3746caf..a8dda8a12c9 100644
--- a/intern/cycles/kernel/shaders/stdosl.h
+++ b/intern/cycles/kernel/shaders/stdosl.h
@@ -527,6 +527,9 @@ closure color transparent() BUILTIN;
closure color microfacet_ggx(normal N, float ag) BUILTIN;
closure color microfacet_ggx_aniso(normal N, vector T, float ax, float ay) BUILTIN;
closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN;
+closure color microfacet_multi_ggx(normal N, float ag, color C) BUILTIN;
+closure color microfacet_multi_ggx_aniso(normal N, vector T, float ax, float ay, color C) BUILTIN;
+closure color microfacet_multi_ggx_glass(normal N, float ag, float eta, color C) BUILTIN;
closure color microfacet_beckmann(normal N, float ab) BUILTIN;
closure color microfacet_beckmann_aniso(normal N, vector T, float ax, float ay) BUILTIN;
closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN;
diff --git a/intern/cycles/kernel/split/kernel_shader_eval.h b/intern/cycles/kernel/split/kernel_shader_eval.h
index e816a818915..cef64bf5f36 100644
--- a/intern/cycles/kernel/split/kernel_shader_eval.h
+++ b/intern/cycles/kernel/split/kernel_shader_eval.h
@@ -65,6 +65,6 @@ ccl_device void kernel_shader_eval(
isect,
&ray);
float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF);
- shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN);
}
}
diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h
index 65512a0105c..fae89aade60 100644
--- a/intern/cycles/kernel/svm/svm_closure.h
+++ b/intern/cycles/kernel/svm/svm_closure.h
@@ -186,7 +186,8 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
case CLOSURE_BSDF_REFLECTION_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
- case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: {
+ case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: {
#ifdef __CAUSTICS_TRICKS__
if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE))
break;
@@ -206,6 +207,14 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(sc);
else if(type == CLOSURE_BSDF_MICROFACET_GGX_ID)
ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(sc);
+ else if(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) {
+ kernel_assert(stack_valid(data_node.z));
+ float3 color = stack_load_float3(stack, data_node.z);
+ sc->custom1 = color.x;
+ sc->custom2 = color.y;
+ sc->custom3 = color.z;
+ ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_setup(sc);
+ }
else
ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_setup(sc);
}
@@ -307,8 +316,36 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
break;
}
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: {
+#ifdef __CAUSTICS_TRICKS__
+ if(!kernel_data.integrator.caustics_reflective && !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE))
+ break;
+#endif
+ ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
+
+ if(sc) {
+ sc->N = N;
+
+ sc->data0 = param1;
+ sc->data1 = param1;
+ float eta = fmaxf(param2, 1e-5f);
+ sc->data2 = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f/eta: eta;
+
+ kernel_assert(stack_valid(data_node.z));
+ float3 color = stack_load_float3(stack, data_node.z);
+ sc->custom1 = color.x;
+ sc->custom2 = color.y;
+ sc->custom3 = color.z;
+
+ /* setup bsdf */
+ ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_glass_setup(sc);
+ }
+
+ break;
+ }
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID:
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID: {
#ifdef __CAUSTICS_TRICKS__
if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE))
@@ -346,6 +383,14 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_aniso_setup(sc);
else if(type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID)
ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_aniso_setup(sc);
+ else if(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID) {
+ kernel_assert(stack_valid(data_node.w));
+ float3 color = stack_load_float3(stack, data_node.w);
+ sc->custom1 = color.x;
+ sc->custom2 = color.y;
+ sc->custom3 = color.z;
+ ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_aniso_setup(sc);
+ }
else
ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_aniso_setup(sc);
}
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index e57d22b1b13..e1a8ced6a34 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -396,8 +396,10 @@ typedef enum ClosureType {
CLOSURE_BSDF_REFLECTION_ID,
CLOSURE_BSDF_MICROFACET_GGX_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_ID,
+ CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID,
CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID,
CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID,
+ CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID,
CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID,
CLOSURE_BSDF_ASHIKHMIN_VELVET_ID,
@@ -413,6 +415,7 @@ typedef enum ClosureType {
CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID,
CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
+ CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID,
CLOSURE_BSDF_SHARP_GLASS_ID,
CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 5e53b66f710..87020823df9 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -1828,6 +1828,7 @@ NODE_DEFINE(AnisotropicBsdfNode)
static NodeEnum distribution_enum;
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID);
distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID);
+ distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID);
distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID);
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID);
@@ -1864,7 +1865,10 @@ void AnisotropicBsdfNode::compile(SVMCompiler& compiler)
{
closure = distribution;
- BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
+ if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID)
+ BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color"));
+ else
+ BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
}
void AnisotropicBsdfNode::compile(OSLCompiler& compiler)
@@ -1888,6 +1892,7 @@ NODE_DEFINE(GlossyBsdfNode)
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
+ distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f);
@@ -1937,6 +1942,8 @@ void GlossyBsdfNode::compile(SVMCompiler& compiler)
if(closure == CLOSURE_BSDF_REFLECTION_ID)
BsdfNode::compile(compiler, NULL, NULL);
+ else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID)
+ BsdfNode::compile(compiler, input("Roughness"), NULL, input("Color"));
else
BsdfNode::compile(compiler, input("Roughness"), NULL);
}
@@ -1961,6 +1968,7 @@ NODE_DEFINE(GlassBsdfNode)
distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
+ distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
@@ -2011,6 +2019,8 @@ void GlassBsdfNode::compile(SVMCompiler& compiler)
if(closure == CLOSURE_BSDF_SHARP_GLASS_ID)
BsdfNode::compile(compiler, NULL, input("IOR"));
+ else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
+ BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color"));
else
BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
}
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
index 53944ec1cc4..cfe6fa65143 100644
--- a/intern/cycles/util/util_math.h
+++ b/intern/cycles/util/util_math.h
@@ -545,6 +545,11 @@ ccl_device_inline float3 normalize(const float3 a)
#endif
+ccl_device_inline float3 saturate3(float3 a)
+{
+ return make_float3(saturate(a.x), saturate(a.y), saturate(a.z));
+}
+
ccl_device_inline float3 normalize_len(const float3 a, float *t)
{
*t = len(a);
@@ -1329,6 +1334,15 @@ ccl_device float safe_modulo(float a, float b)
return (b != 0.0f)? fmodf(a, b): 0.0f;
}
+ccl_device_inline float beta(float x, float y)
+{
+#ifndef __KERNEL_OPENCL__
+ return expf(lgammaf(x) + lgammaf(y) - lgammaf(x+y));
+#else
+ return expf(lgamma(x) + lgamma(y) - lgamma(x+y));
+#endif
+}
+
/* Ray Intersection */
ccl_device bool ray_sphere_intersect(
diff --git a/intern/cycles/util/util_string.cpp b/intern/cycles/util/util_string.cpp
index e16a83d56d0..c1c5a6b084b 100644
--- a/intern/cycles/util/util_string.cpp
+++ b/intern/cycles/util/util_string.cpp
@@ -260,7 +260,11 @@ string string_human_readable_size(size_t size)
string string_human_readable_number(size_t num)
{
- /* add thousands separators */
+ if(num == 0) {
+ return "0";
+ }
+
+ /* Add thousands separators. */
char buf[32];
char* p = buf+31;
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index 4ca2f773dcc..2a98303d00e 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -96,25 +96,25 @@ class ConstraintButtonsPanel:
def CHILD_OF(self, context, layout, con):
self.target_template(layout, con)
- split = layout.split()
-
- col = split.column()
- col.label(text="Location:")
- col.prop(con, "use_location_x", text="X")
- col.prop(con, "use_location_y", text="Y")
- col.prop(con, "use_location_z", text="Z")
-
- col = split.column()
- col.label(text="Rotation:")
- col.prop(con, "use_rotation_x", text="X")
- col.prop(con, "use_rotation_y", text="Y")
- col.prop(con, "use_rotation_z", text="Z")
-
- col = split.column()
- col.label(text="Scale:")
- col.prop(con, "use_scale_x", text="X")
- col.prop(con, "use_scale_y", text="Y")
- col.prop(con, "use_scale_z", text="Z")
+ #split = layout.split()
+
+ #col = split.column()
+ #col.label(text="Location:")
+ #col.prop(con, "use_location_x", text="X")
+ #col.prop(con, "use_location_y", text="Y")
+ #col.prop(con, "use_location_z", text="Z")
+
+ #col = split.column()
+ #col.label(text="Rotation:")
+ #col.prop(con, "use_rotation_x", text="X")
+ #col.prop(con, "use_rotation_y", text="Y")
+ #col.prop(con, "use_rotation_z", text="Z")
+
+ #col = split.column()
+ #col.label(text="Scale:")
+ #col.prop(con, "use_scale_x", text="X")
+ #col.prop(con, "use_scale_y", text="Y")
+ #col.prop(con, "use_scale_z", text="Z")
row = layout.row()
row.operator("constraint.childof_set_inverse")
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index a823789f2c3..ac412688fa1 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -63,6 +63,9 @@ class GreasePencilDrawingToolsPanel:
def draw(self, context):
layout = self.layout
+ is_3d_view = context.space_data.type == 'VIEW_3D'
+ is_clip_editor = context.space_data.type == 'CLIP_EDITOR'
+
col = layout.column(align=True)
col.label(text="Draw:")
@@ -85,9 +88,9 @@ class GreasePencilDrawingToolsPanel:
col.separator()
col.label("Data Source:")
row = col.row(align=True)
- if context.space_data.type == 'VIEW_3D':
+ if is_3d_view:
row.prop(context.tool_settings, "grease_pencil_source", expand=True)
- elif context.space_data.type == 'CLIP_EDITOR':
+ elif is_clip_editor:
row.prop(context.space_data, "grease_pencil_source", expand=True)
col.separator()
@@ -97,19 +100,19 @@ class GreasePencilDrawingToolsPanel:
gpd = context.gpencil_data
- if gpd:
+ if gpd and not is_3d_view:
layout.separator()
layout.separator()
col = layout.column(align=True)
col.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True)
- if context.space_data.type == 'VIEW_3D':
+ if is_3d_view:
col.separator()
col.separator()
col.label(text="Tools:")
- col.operator("gpencil.convert", text="Convert...")
+ col.operator_menu_enum("gpencil.convert", text="Convert to Geometry...", property="type")
col.operator("view3d.ruler")
@@ -133,20 +136,23 @@ class GreasePencilStrokeEditPanel:
def draw(self, context):
layout = self.layout
- layout.label(text="Select:")
- col = layout.column(align=True)
- col.operator("gpencil.select_all", text="Select All")
- col.operator("gpencil.select_border")
- col.operator("gpencil.select_circle")
+ is_3d_view = context.space_data.type == 'VIEW_3D'
- layout.separator()
+ if not is_3d_view:
+ layout.label(text="Select:")
+ col = layout.column(align=True)
+ col.operator("gpencil.select_all", text="Select All")
+ col.operator("gpencil.select_border")
+ col.operator("gpencil.select_circle")
- col = layout.column(align=True)
- col.operator("gpencil.select_linked")
- col.operator("gpencil.select_more")
- col.operator("gpencil.select_less")
+ layout.separator()
- layout.separator()
+ col = layout.column(align=True)
+ col.operator("gpencil.select_linked")
+ col.operator("gpencil.select_more")
+ col.operator("gpencil.select_less")
+
+ layout.separator()
layout.label(text="Edit:")
row = layout.row(align=True)
@@ -160,12 +166,13 @@ class GreasePencilStrokeEditPanel:
layout.separator()
- col = layout.column(align=True)
- col.operator("transform.translate") # icon='MAN_TRANS'
- col.operator("transform.rotate") # icon='MAN_ROT'
- col.operator("transform.resize", text="Scale") # icon='MAN_SCALE'
+ if not is_3d_view:
+ col = layout.column(align=True)
+ col.operator("transform.translate") # icon='MAN_TRANS'
+ col.operator("transform.rotate") # icon='MAN_ROT'
+ col.operator("transform.resize", text="Scale") # icon='MAN_SCALE'
- layout.separator()
+ layout.separator()
col = layout.column(align=True)
col.operator("transform.bend", text="Bend")
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 4b068265b80..e6f81656e45 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -248,6 +248,8 @@ class DOPESHEET_MT_select(Menu):
layout.operator("action.select_border").axis_range = False
layout.operator("action.select_border", text="Border Axis Range").axis_range = True
+ layout.operator("action.select_circle")
+
layout.separator()
layout.operator("action.select_column", text="Columns on Selected Keys").mode = 'KEYS'
layout.operator("action.select_column", text="Column on Current Frame").mode = 'CFRA'
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index e135b14e13d..446df9e6e79 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -154,6 +154,8 @@ class GRAPH_MT_select(Menu):
props.axis_range = False
props.include_handles = True
+ layout.operator("graph.select_circle")
+
layout.separator()
layout.operator("graph.select_column", text="Columns on Selected Keys").mode = 'KEYS'
layout.operator("graph.select_column", text="Column on Current Frame").mode = 'CFRA'
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index da7bd9c1994..247c3e099a0 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2526,7 +2526,7 @@ class VIEW3D_MT_edit_gpencil_delete(Menu):
layout.separator()
- layout.operator("gpencil.active_frame_delete")
+ layout.operator("gpencil.active_frames_delete_all")
# Edit Curve
diff --git a/release/scripts/templates_py/script_stub.py b/release/scripts/templates_py/external_script_stub.py
index 5505ca64078..5505ca64078 100644
--- a/release/scripts/templates_py/script_stub.py
+++ b/release/scripts/templates_py/external_script_stub.py
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 8ce85c8e615..d2d9c763031 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -50,6 +50,11 @@ void BKE_blender_userdef_refresh(void);
void BKE_blender_callback_test_break_set(void (*func)(void));
int BKE_blender_test_break(void);
+/* Blenders' own atexit (avoids leaking) */
+void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data);
+void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data);
+void BKE_blender_atexit(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h
index cd18bd8db40..9547eeb9838 100644
--- a/source/blender/blenkernel/BKE_blender_undo.h
+++ b/source/blender/blenkernel/BKE_blender_undo.h
@@ -45,6 +45,8 @@ extern const char *BKE_undo_get_name(int nr, bool *r_active);
extern bool BKE_undo_save_file(const char *filename);
extern struct Main *BKE_undo_get_main(struct Scene **r_scene);
+extern void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C));
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h
index 3b096773d96..9625f05192a 100644
--- a/source/blender/blenkernel/BKE_displist.h
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -45,10 +45,14 @@
#define DL_VERTS 7
/* dl->flag */
-#define DL_CYCL_U 1
-#define DL_CYCL_V 2
-#define DL_FRONT_CURVE 4
-#define DL_BACK_CURVE 8
+enum {
+ /** U/V swapped here compared with #Nurb.flagu, #Nurb.flagv and #CU_NURB_CYCLIC */
+ DL_CYCL_U = (1 << 0),
+ DL_CYCL_V = (1 << 1),
+
+ DL_FRONT_CURVE = (1 << 2),
+ DL_BACK_CURVE = (1 << 3),
+};
/* prototypes */
@@ -70,7 +74,7 @@ typedef struct DispList {
int charidx;
int totindex; /* indexed array drawing surfaces */
- unsigned int *bevelSplitFlag;
+ unsigned int *bevel_split; /* BLI_bitmap */
} DispList;
void BKE_displist_copy(struct ListBase *lbn, struct ListBase *lb);
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index afca326c727..3d963ac109c 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -40,7 +40,6 @@ struct MovieClipUser;
struct MovieDistortion;
void BKE_movieclip_free(struct MovieClip *clip);
-void BKE_movieclip_unlink(struct Main *bmain, struct MovieClip *clip);
struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain, const char *name, bool *r_exists);
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index b14593f5a56..858feeeab10 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -53,7 +53,6 @@ struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const cha
const bool is_internal);
struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath);
struct Text *BKE_text_copy (struct Main *bmain, struct Text *ta);
-void BKE_text_unlink (struct Main *bmain, struct Text *text);
void BKE_text_clear (struct Text *text);
void BKE_text_write (struct Text *text, const char *str);
int BKE_text_file_modified_check(struct Text *text);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index df715531cb7..74930dbea4a 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -49,9 +49,6 @@ set(INC
../../../intern/smoke/extern
../../../intern/atomic
../../../intern/libmv
-
- # XXX - BAD LEVEL CALL WM_api.h
- ../windowmanager
)
set(INC_SYS
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 15492fbd20d..0805335da66 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -226,3 +226,56 @@ int BKE_blender_test_break(void)
return (G.is_break == true);
}
+
+/** \name Blender's AtExit
+ *
+ * \note Don't use MEM_mallocN so functions can be registered at any time.
+ * \{ */
+
+struct AtExitData {
+ struct AtExitData *next;
+
+ void (*func)(void *user_data);
+ void *user_data;
+} *g_atexit = NULL;
+
+void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data)
+{
+ struct AtExitData *ae = malloc(sizeof(*ae));
+ ae->next = g_atexit;
+ ae->func = func;
+ ae->user_data = user_data;
+ g_atexit = ae;
+}
+
+void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data)
+{
+ struct AtExitData *ae = g_atexit;
+ struct AtExitData **ae_p = &g_atexit;
+
+ while (ae) {
+ if ((ae->func == func) && (ae->user_data == user_data)) {
+ *ae_p = ae->next;
+ free(ae);
+ return;
+ }
+ ae_p = &ae;
+ ae = ae->next;
+ }
+}
+
+void BKE_blender_atexit(void)
+{
+ struct AtExitData *ae = g_atexit, *ae_next;
+ while (ae) {
+ ae_next = ae->next;
+
+ ae->func(ae->user_data);
+
+ free(ae);
+ ae = ae_next;
+ }
+ g_atexit = NULL;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index ca0a1b91cea..d64bf7ecf43 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -66,9 +66,6 @@
#include "BLO_readfile.h"
#include "BLO_writefile.h"
-#include "WM_api.h" // XXXXX BAD, very BAD dependency (bad level call) - remove asap, elubie
-
-
/* -------------------------------------------------------------------- */
/** \name Global Undo
@@ -87,6 +84,15 @@ typedef struct UndoElem {
static ListBase undobase = {NULL, NULL};
static UndoElem *curundo = NULL;
+/**
+ * Avoid bad-level call to #WM_jobs_kill_all_except()
+ */
+static void (*undo_wm_job_kill_callback)(struct bContext *C) = NULL;
+
+void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C))
+{
+ undo_wm_job_kill_callback = callback;
+}
static int read_undosave(bContext *C, UndoElem *uel)
{
@@ -94,7 +100,7 @@ static int read_undosave(bContext *C, UndoElem *uel)
int success = 0, fileflags;
/* This is needed so undoing/redoing doesn't crash with threaded previews going */
- WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C));
+ undo_wm_job_kill_callback(C);
BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index a3e006a162f..44cacffb71f 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -216,21 +216,6 @@ void BKE_brush_free(Brush *brush)
BKE_previewimg_free(&(brush->preview));
}
-/**
- * \note Currently users don't remove brushes from the UI (as is done for scene, text... etc)
- * This is only used by RNA, which can remove brushes.
- */
-void BKE_brush_unlink(Main *bmain, Brush *brush)
-{
- Brush *brush_iter;
-
- for (brush_iter = bmain->brush.first; brush_iter; brush_iter = brush_iter->id.next) {
- if (brush_iter->toggle_brush == brush) {
- brush_iter->toggle_brush = NULL;
- }
- }
-}
-
static void extern_local_brush(Brush *brush)
{
id_lib_extern((ID *)brush->mtex.tex);
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 7821946eb6e..e0277c38e61 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -565,7 +565,7 @@ BVHTree *bvhtree_from_mesh_verts(
/**
* Builds a bvh tree where nodes are the given vertices (note: does not copy given mverts!).
* \param vert_allocated if true, vert freeing will be done when freeing data.
- * \param mask if not null, true elements give which vert to add to BVH tree.
+ * \param verts_mask if not null, true elements give which vert to add to BVH tree.
* \param verts_num_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask).
*/
BVHTree *bvhtree_from_mesh_verts_ex(
@@ -804,7 +804,7 @@ BVHTree *bvhtree_from_mesh_faces(
* Builds a bvh tree where nodes are the given tessellated faces (note: does not copy given mfaces!).
* \param vert_allocated if true, vert freeing will be done when freeing data.
* \param face_allocated if true, face freeing will be done when freeing data.
- * \param mask if not null, true elements give which faces to add to BVH tree.
+ * \param faces_mask: if not null, true elements give which faces to add to BVH tree.
* \param numFaces_active if >= 0, number of active faces to add to BVH tree (else will be computed from mask).
*/
BVHTree *bvhtree_from_mesh_faces_ex(
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 267f7a65e00..159d5b82a6c 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -61,8 +61,6 @@
#include "GPU_shader.h"
#include "GPU_basic_shader.h"
-#include "WM_api.h"
-
#include <string.h>
#include <limits.h>
#include <math.h>
@@ -699,10 +697,10 @@ static void cdDM_drawMappedFaces(
}
if ((orig != ORIGINDEX_NONE) && !is_hidden)
- WM_framebuffer_index_get(orig + 1, &selcol);
+ GPU_select_index_get(orig + 1, &selcol);
}
else if (orig != ORIGINDEX_NONE)
- WM_framebuffer_index_get(orig + 1, &selcol);
+ GPU_select_index_get(orig + 1, &selcol);
for (j = 0; j < mpoly->totloop; j++)
fi_map[start_element++] = selcol;
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index 98cbe47c7f9..49db75a0474 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -71,7 +71,7 @@ void BKE_displist_elem_free(DispList *dl)
if (dl->verts) MEM_freeN(dl->verts);
if (dl->nors) MEM_freeN(dl->nors);
if (dl->index) MEM_freeN(dl->index);
- if (dl->bevelSplitFlag) MEM_freeN(dl->bevelSplitFlag);
+ if (dl->bevel_split) MEM_freeN(dl->bevel_split);
MEM_freeN(dl);
}
}
@@ -144,8 +144,9 @@ void BKE_displist_copy(ListBase *lbn, ListBase *lb)
dln->nors = MEM_dupallocN(dl->nors);
dln->index = MEM_dupallocN(dl->index);
- if (dl->bevelSplitFlag)
- dln->bevelSplitFlag = MEM_dupallocN(dl->bevelSplitFlag);
+ if (dl->bevel_split) {
+ dln->bevel_split = MEM_dupallocN(dl->bevel_split);
+ }
dl = dl->next;
}
@@ -1629,7 +1630,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
if (dlb->type == DL_POLY) {
dl->flag |= DL_CYCL_U;
}
- if ((bl->poly >= 0) && (steps != 2)) {
+ if ((bl->poly >= 0) && (steps > 2)) {
dl->flag |= DL_CYCL_V;
}
@@ -1642,8 +1643,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
/* CU_2D conflicts with R_NOPUNOFLIP */
dl->rt = nu->flag & ~CU_2D;
- dl->bevelSplitFlag = MEM_callocN(sizeof(*dl->bevelSplitFlag) * ((steps + 0x1F) >> 5),
- "bevelSplitFlag");
+ dl->bevel_split = BLI_BITMAP_NEW(steps, "bevel_split");
/* for each point of poly make a bevel piece */
bevp_first = bl->bevpoints;
@@ -1683,7 +1683,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
}
if (bevp->split_tag) {
- dl->bevelSplitFlag[a >> 5] |= 1 << (a & 0x1F);
+ BLI_BITMAP_ENABLE(dl->bevel_split, a);
}
/* rotate bevel piece and write in data */
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index ea99fa8f55a..c7a346d49ec 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -123,7 +123,7 @@ static IDType *idtype_from_code(short idcode)
/**
* Return if the ID code is a valid ID code.
*
- * \param code The code to check.
+ * \param idcode: The code to check.
* \return Boolean, 0 when invalid.
*/
bool BKE_idcode_is_valid(short idcode)
@@ -134,7 +134,7 @@ bool BKE_idcode_is_valid(short idcode)
/**
* Return non-zero when an ID type is linkable.
*
- * \param code The code to check.
+ * \param idcode: The code to check.
* \return Boolean, 0 when non linkable.
*/
bool BKE_idcode_is_linkable(short idcode)
@@ -147,7 +147,7 @@ bool BKE_idcode_is_linkable(short idcode)
/**
* Convert an idcode into a name.
*
- * \param code The code to convert.
+ * \param idcode: The code to convert.
* \return A static string representing the name of
* the code.
*/
@@ -258,7 +258,7 @@ short BKE_idcode_from_idfilter(const int idfilter)
/**
* Convert an idcode into a name (plural).
*
- * \param code The code to convert.
+ * \param idcode: The code to convert.
* \return A static string representing the name of
* the code.
*/
@@ -272,7 +272,7 @@ const char *BKE_idcode_to_name_plural(short idcode)
/**
* Convert an idcode into its translations' context.
*
- * \param code The code to convert.
+ * \param idcode: The code to convert.
* \return A static string representing the i18n context of the code.
*/
const char *BKE_idcode_to_translation_context(short idcode)
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 14a445649ad..69384a70969 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -95,8 +95,6 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
-#include "WM_api.h"
-
static SpinLock image_spin;
/* prototypes */
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 9335d41f399..3747b09fd99 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -162,15 +162,14 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self),
}
if (*id_p && (*id_p == old_id)) {
+ const bool is_indirect = (id->lib != NULL);
+ const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
/* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
* on the other hand since they get reset to lib data on file open/reload it is indirect too...
* Edit Mode is also a 'skip direct' case. */
const bool is_obj = (GS(id->name) == ID_OB);
const bool is_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group));
const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
- /* Note that indirect data from same file as processed ID is **not** considered indirect! */
- const bool is_indirect = ((id->lib != NULL) && (id->lib != old_id->lib));
- const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) &&
(id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
@@ -184,7 +183,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self),
(is_obj_editmode && (((Object *)id)->data == *id_p)) ||
(skip_indirect && (is_proxy || is_indirect)))
{
- if (is_never_null || is_proxy || is_obj_editmode) {
+ if (!is_indirect && (is_never_null || is_proxy || is_obj_editmode)) {
id_remap_data->skipped_direct++;
}
else {
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 4e47dfcce74..f82e5cf61b3 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -427,12 +427,6 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me)
}
}
-/* Note: unlinking is called when me->id.us is 0, question remains how
- * much unlinking of Library data in Mesh should be done... probably
- * we need a more generic method, like the expand() functions in
- * readfile.c */
-
-
/** Free (or release) any data used by this mesh (does not free the mesh itself). */
void BKE_mesh_free(Mesh *me)
{
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 5f667732b04..f99457a4c26 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -1491,73 +1491,6 @@ void BKE_movieclip_free(MovieClip *clip)
BKE_tracking_free(&clip->tracking);
}
-void BKE_movieclip_unlink(Main *bmain, MovieClip *clip)
-{
- bScreen *scr;
- ScrArea *area;
- SpaceLink *sl;
- Scene *sce;
- Object *ob;
-
- for (scr = bmain->screen.first; scr; scr = scr->id.next) {
- for (area = scr->areabase.first; area; area = area->next) {
- for (sl = area->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_CLIP) {
- SpaceClip *sc = (SpaceClip *) sl;
-
- if (sc->clip == clip)
- sc->clip = NULL;
- }
- else if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *) sl;
- BGpic *bgpic;
-
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- if (bgpic->clip == clip)
- bgpic->clip = NULL;
- }
- }
- }
- }
- }
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- if (sce->clip == clip)
- sce->clip = NULL;
- }
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- bConstraint *con;
-
- for (con = ob->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
- bFollowTrackConstraint *data = (bFollowTrackConstraint *) con->data;
-
- if (data->clip == clip)
- data->clip = NULL;
- }
- else if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) {
- bCameraSolverConstraint *data = (bCameraSolverConstraint *) con->data;
-
- if (data->clip == clip)
- data->clip = NULL;
- }
- else if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
- bObjectSolverConstraint *data = (bObjectSolverConstraint *) con->data;
-
- if (data->clip == clip)
- data->clip = NULL;
- }
- }
- }
-
- FOREACH_NODETREE(bmain, ntree, id) {
- BKE_node_tree_unlink_id((ID *)clip, ntree);
- } FOREACH_NODETREE_END
-
- clip->id.us = 0;
-}
-
float BKE_movieclip_remap_scene_to_clip_frame(MovieClip *clip, float framenr)
{
return framenr - (float) clip->start_frame + 1.0f;
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 594f9dffbee..fdc2edba57f 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -498,191 +498,6 @@ Text *BKE_text_copy(Main *bmain, Text *ta)
return tan;
}
-void BKE_text_unlink(Main *bmain, Text *text)
-{
- bScreen *scr;
- ScrArea *area;
- SpaceLink *sl;
- Object *ob;
- bController *cont;
- bActuator *act;
- bConstraint *con;
- bNodeTree *ntree;
- bNode *node;
- Material *mat;
- Lamp *la;
- Tex *te;
- World *wo;
- FreestyleLineStyle *linestyle;
- Scene *sce;
- SceneRenderLayer *srl;
- FreestyleModuleConfig *module;
- bool update;
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- /* game controllers */
- for (cont = ob->controllers.first; cont; cont = cont->next) {
- if (cont->type == CONT_PYTHON) {
- bPythonCont *pc;
-
- pc = cont->data;
- if (pc->text == text) pc->text = NULL;
- }
- }
- /* game actuators */
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_2DFILTER) {
- bTwoDFilterActuator *tfa;
-
- tfa = act->data;
- if (tfa->text == text) tfa->text = NULL;
- }
- }
-
- /* pyconstraints */
- update = 0;
-
- if (ob->type == OB_ARMATURE && ob->pose) {
- bPoseChannel *pchan;
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (con = pchan->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_PYTHON) {
- bPythonConstraint *data = con->data;
- if (data->text == text) data->text = NULL;
- update = 1;
-
- }
- }
- }
- }
-
- for (con = ob->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_PYTHON) {
- bPythonConstraint *data = con->data;
- if (data->text == text) data->text = NULL;
- update = 1;
- }
- }
-
- if (update)
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- /* nodes */
- for (la = bmain->lamp.first; la; la = la->id.next) {
- ntree = la->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
- ntree = linestyle->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (mat = bmain->mat.first; mat; mat = mat->id.next) {
- ntree = mat->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (te = bmain->tex.first; te; te = te->id.next) {
- ntree = te->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (wo = bmain->world.first; wo; wo = wo->id.next) {
- ntree = wo->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- ntree = sce->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- Text *ntext = (Text *)node->id;
- if (ntext == text) node->id = NULL;
- }
- }
-
- /* Freestyle (while looping over the scene) */
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- for (module = srl->freestyleConfig.modules.first; module; module = module->next) {
- if (module->script == text)
- module->script = NULL;
- }
- }
- }
-
- for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) {
- for (node = ntree->nodes.first; node; node = node->next) {
- if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- /* text space */
- for (scr = bmain->screen.first; scr; scr = scr->id.next) {
- for (area = scr->areabase.first; area; area = area->next) {
- for (sl = area->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_TEXT) {
- SpaceText *st = (SpaceText *) sl;
-
- if (st->text == text) {
- st->text = NULL;
- st->top = 0;
- }
- }
- }
- }
- }
-
- text->id.us = 0;
-}
-
void BKE_text_clear(Text *text) /* called directly from rna */
{
int oldstate;
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index 5ef8421c003..a46c87cec40 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -48,6 +48,10 @@ int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_strid
#define BLI_array_findindex(arr, arr_len, p) \
_bli_array_findindex(arr, arr_len, sizeof(*(arr)), p)
+int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p);
+#define BLI_array_rfindindex(arr, arr_len, p) \
+ _bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p)
+
void _bli_array_binary_and(
void *arr, const void *arr_a, const void *arr_b,
unsigned int arr_len, size_t arr_stride);
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 9120d9f53f7..8124e07dd47 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -273,7 +273,7 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float
/*********************************** Other ***********************************/
void print_m3(const char *str, float M[3][3]);
-void print_m4(const char *str, float M[3][4]);
+void print_m4(const char *str, float M[4][4]);
#define print_m3_id(M) print_m3(STRINGIFY(M), M)
#define print_m4_id(M) print_m4(STRINGIFY(M), M)
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
index 527d9934797..76de52bda66 100644
--- a/source/blender/blenlib/intern/BLI_filelist.c
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -352,8 +352,6 @@ void BLI_filelist_entry_datetime_to_string(
/**
* Deep-duplicate of a single direntry.
- *
- * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over.
*/
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src)
{
@@ -368,8 +366,6 @@ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *s
/**
* Deep-duplicate of an array of direntries, including the array itself.
- *
- * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over.
*/
void BLI_filelist_duplicate(
struct direntry **dest_filelist, struct direntry * const src_filelist, const unsigned int nrentries)
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index 9c91da4abee..32f0111babd 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -134,8 +134,22 @@ void _bli_array_permute(
int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p)
{
const char *arr_step = (const char *)arr;
- unsigned int i;
- for (i = 0; i < arr_len; i++, arr_step += arr_stride) {
+ for (unsigned int i = 0; i < arr_len; i++, arr_step += arr_stride) {
+ if (memcmp(arr_step, p, arr_stride) == 0) {
+ return (int)i;
+ }
+ }
+ return -1;
+}
+
+/**
+ * A version of #BLI_array_findindex that searches from the end of the list.
+ */
+int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p)
+{
+ const char *arr_step = (const char *)arr + (arr_stride * arr_len);
+ for (unsigned int i = arr_len; i-- != 0; ) {
+ arr_step -= arr_stride;
if (memcmp(arr_step, p, arr_stride) == 0) {
return (int)i;
}
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 370e8bb0035..124f0c7abb8 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -2692,7 +2692,7 @@ bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v
}
/**
- * \param r_vi The point \a p projected onto the triangle.
+ * \param r_isect_co: The point \a p projected onto the triangle.
* \return True when \a p is inside the triangle.
* \note Its up to the caller to check the distance between \a p and \a r_vi against an error margin.
*/
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 2b793841c38..ded10ad7713 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -310,7 +310,7 @@ static int BLI_path_unc_prefix_len(const char *path); /* defined below in same f
/**
* Remove redundant characters from \a path and optionally make absolute.
*
- * \param relbase: The path this is relative to, or ignored when NULL.
+ * \param relabase: The path this is relative to, or ignored when NULL.
* \param path: Can be any input, and this function converts it to a regular full path.
* Also removes garbage from directory paths, like `/../` or double slashes etc.
*
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 3262f740b09..2e01456dbd5 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -1324,6 +1324,7 @@ bool BLO_has_bfile_extension(const char *str)
*
* \param path the full path to explode.
* \param r_dir the string that'll contain path up to blend file itself ('library' path).
+ * WARNING! Must be FILE_MAX_LIBEXTRA long (it also stores group and name strings)!
* \param r_group the string that'll contain 'group' part of the path, if any. May be NULL.
* \param r_name the string that'll contain data's name part of the path, if any. May be NULL.
* \return true if path contains a blend file.
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 3393be059bd..194ad72100c 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -29,15 +29,22 @@
*/
-/*
- * FILEFORMAT: IFF-style structure (but not IFF compatible!)
+/**
+ *
+ * FILE FORMAT
+ * ===========
+ *
+ * IFF-style structure (but not IFF compatible!)
*
* start file:
+ * <pre>
* BLENDER_V100 12 bytes (versie 1.00)
* V = big endian, v = little endian
* _ = 4 byte pointer, - = 8 byte pointer
+ * </pre>
*
- * datablocks: also see struct BHead
+ * datablocks: (also see struct #BHead).
+ * <pre>
* <bh.code> 4 chars
* <bh.len> int, len data after BHead
* <bh.old> void, old pointer
@@ -46,29 +53,32 @@
* data
* ...
* ...
+ * </pre>
*
* Almost all data in Blender are structures. Each struct saved
* gets a BHead header. With BHead the struct can be linked again
* and compared with StructDNA .
*
+ *
* WRITE
+ * =====
*
* Preferred writing order: (not really a must, but why would you do it random?)
* Any case: direct data is ALWAYS after the lib block
*
* (Local file data)
* - for each LibBlock
- * - write LibBlock
- * - write associated direct data
+ * - write LibBlock
+ * - write associated direct data
* (External file data)
* - per library
- * - write library block
- * - per LibBlock
- * - write the ID of LibBlock
- * - write TEST (128x128, blend file preview, optional)
- * - write FileGlobal (some global vars)
- * - write SDNA
- * - write USER if filename is ~/X.XX/config/startup.blend
+ * - write library block
+ * - per LibBlock
+ * - write the ID of LibBlock
+ * - write #TEST (#RenderInfo struct. 128x128 blend file preview is optional).
+ * - write #GLOB (#FileGlobal struct) (some global vars).
+ * - write #DNA1 (#SDNA struct)
+ * - write #USER (#UserDef struct) if filename is ``~/X.XX/config/startup.blend``.
*/
@@ -309,12 +319,6 @@ static WriteData *writedata_new(WriteWrap *ww)
{
WriteData *wd= MEM_callocN(sizeof(*wd), "writedata");
- /* XXX, see note about this in readfile.c, remove
- * once we have an xp lock - zr
- */
-
- if (wd == NULL) return NULL;
-
wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
wd->ww = ww;
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
index c142dcae514..5ee0e904a33 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
@@ -97,12 +97,22 @@ static BMLoop *bm_edge_flagged_radial_first(BMEdge *e)
return NULL;
}
+static void normalize_v2_m3_v3v3(float out[2], float axis_mat[3][3], const float v1[3], const float v2[3])
+{
+ float dir[3];
+ sub_v3_v3v3(dir, v1, v2);
+ mul_v2_m3v3(out, axis_mat, dir);
+ normalize_v2(out);
+}
+
+
/**
* \note Be sure to update #bm_face_split_edgenet_find_loop_pair_exists
* when making changed to edge picking logic.
*/
static bool bm_face_split_edgenet_find_loop_pair(
- BMVert *v_init, const float face_normal[3],
+ BMVert *v_init,
+ const float face_normal[3], float face_normal_matrix[3][3],
BMEdge *e_pair[2])
{
/* Always find one boundary edge (to determine winding)
@@ -142,10 +152,17 @@ static bool bm_face_split_edgenet_find_loop_pair(
}
e_pair[0] = BLI_SMALLSTACK_POP(edges_boundary);
+ /* use to hold boundary OR wire edges */
+ BLI_SMALLSTACK_DECLARE(edges_search, BMEdge *);
+
/* attempt one boundary and one wire, or 2 boundary */
if (edges_wire_len == 0) {
- if (edges_boundary_len >= 2) {
+ if (edges_boundary_len > 1) {
e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary);
+
+ if (edges_boundary_len > 2) {
+ BLI_SMALLSTACK_SWAP(edges_search, edges_wire);
+ }
}
else {
/* one boundary and no wire */
@@ -154,28 +171,37 @@ static bool bm_face_split_edgenet_find_loop_pair(
}
else {
e_pair[1] = BLI_SMALLSTACK_POP(edges_wire);
-
if (edges_wire_len > 1) {
- BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init);
- BMVert *v_next;
- float angle_best;
-
- v_next = BM_edge_other_vert(e_pair[1], v_init);
- angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal);
-
- BMEdge *e;
- while ((e = BLI_SMALLSTACK_POP(edges_wire))) {
- float angle_test;
- v_next = BM_edge_other_vert(e, v_init);
- angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal);
- if (angle_test < angle_best) {
- angle_best = angle_test;
- e_pair[1] = e;
- }
- }
+ BLI_SMALLSTACK_SWAP(edges_search, edges_wire);
}
}
+ /* if we swapped above, search this list for the best edge */
+ if (!BLI_SMALLSTACK_IS_EMPTY(edges_search)) {
+ /* find the best edge in 'edge_list' to use for 'e_pair[1]' */
+ const BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init);
+ const BMVert *v_next = BM_edge_other_vert(e_pair[1], v_init);
+
+ float dir_prev[2], dir_next[2];
+
+ normalize_v2_m3_v3v3(dir_prev, face_normal_matrix, v_prev->co, v_init->co);
+ normalize_v2_m3_v3v3(dir_next, face_normal_matrix, v_next->co, v_init->co);
+ float angle_best_cos = dot_v2v2(dir_next, dir_prev);
+
+ BMEdge *e;
+ while ((e = BLI_SMALLSTACK_POP(edges_search))) {
+ v_next = BM_edge_other_vert(e, v_init);
+ float dir_test[2];
+
+ normalize_v2_m3_v3v3(dir_test, face_normal_matrix, v_next->co, v_init->co);
+ const float angle_test_cos = dot_v2v2(dir_prev, dir_test);
+
+ if (angle_test_cos > angle_best_cos) {
+ angle_best_cos = angle_test_cos;
+ e_pair[1] = e;
+ }
+ }
+ }
/* flip based on winding */
l_walk = bm_edge_flagged_radial_first(e_pair[0]);
@@ -309,36 +335,40 @@ walk_nofork:
BMEdge *e_next, *e_first;
e_first = v->e;
e_next = BM_DISK_EDGE_NEXT(e_first, v); /* always skip this verts edge */
- do {
- BLI_assert(v->e != e_next);
- if ((BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) &&
- (bm_edge_flagged_radial_count(e_next) < 2))
- {
- BMVert *v_next;
- v_next = BM_edge_other_vert(e_next, v);
+ /* in rare cases there may be edges with a single connecting vertex */
+ if (e_next != e_first) {
+ do {
+ if ((BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) &&
+ (bm_edge_flagged_radial_count(e_next) < 2))
+ {
+ BMVert *v_next;
+
+ v_next = BM_edge_other_vert(e_next, v);
+ BLI_assert(v->e != e_next);
#ifdef DEBUG_PRINT
- /* indent and print */
- {
- BMVert *_v = v;
- do {
- printf(" ");
- } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init);
- printf("vert %d -> %d (add=%d)\n",
- BM_elem_index_get(v), BM_elem_index_get(v_next),
- BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0);
- }
+ /* indent and print */
+ {
+ BMVert *_v = v;
+ do {
+ printf(" ");
+ } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init);
+ printf("vert %d -> %d (add=%d)\n",
+ BM_elem_index_get(v), BM_elem_index_get(v_next),
+ BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0);
+ }
#endif
- if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) {
- eo = STACK_PUSH_RET_PTR(edge_order);
- eo->v = v_next;
+ if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) {
+ eo = STACK_PUSH_RET_PTR(edge_order);
+ eo->v = v_next;
- v_next->e = e_next;
+ v_next->e = e_next;
+ }
}
- }
- } while ((e_next = BM_DISK_EDGE_NEXT(e_next, v)) != e_first);
+ } while ((e_next = BM_DISK_EDGE_NEXT(e_next, v)) != e_first);
+ }
#ifdef USE_FASTPATH_NOFORK
if (STACK_SIZE(edge_order) == 1) {
@@ -388,7 +418,7 @@ finally:
}
static bool bm_face_split_edgenet_find_loop(
- BMVert *v_init, const float face_normal[3],
+ BMVert *v_init, const float face_normal[3], float face_normal_matrix[3][3],
/* cache to avoid realloc every time */
struct VertOrder *edge_order, const unsigned int edge_order_len,
BMVert **r_face_verts, int *r_face_verts_len)
@@ -396,7 +426,7 @@ static bool bm_face_split_edgenet_find_loop(
BMEdge *e_pair[2];
BMVert *v;
- if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, e_pair)) {
+ if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, face_normal_matrix, e_pair)) {
return false;
}
@@ -491,12 +521,18 @@ bool BM_face_split_edgenet(
BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET);
} while ((l_iter = l_iter->next) != l_first);
+ float face_normal_matrix[3][3];
+ axis_dominant_v3_to_m3(face_normal_matrix, f->no);
+
/* any vert can be used to begin with */
STACK_PUSH(vert_queue, l_first->v);
while ((v = STACK_POP(vert_queue))) {
- if (bm_face_split_edgenet_find_loop(v, f->no, edge_order, edge_order_len, face_verts, &face_verts_len)) {
+ if (bm_face_split_edgenet_find_loop(
+ v, f->no, face_normal_matrix,
+ edge_order, edge_order_len, face_verts, &face_verts_len))
+ {
BMFace *f_new;
f_new = BM_face_create_verts(bm, face_verts, face_verts_len, f, BM_CREATE_NOP, false);
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index b4e8bb06afe..52a0df5b9d1 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -1292,7 +1292,8 @@ static bool bm_decim_edge_collapse(
* \param factor face count multiplier [0 - 1]
* \param vweights Optional array of vertex aligned weights [0 - 1],
* a vertex group is the usual source for this.
- * \param axis: Axis of symmetry, -1 to disable mirror decimate.
+ * \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate.
+ * \param symmetry_eps: Threshold when matching mirror verts.
*/
void BM_mesh_decimate_collapse(
BMesh *bm,
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 9d1f7fa45d2..bd6a68faabb 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -87,6 +87,18 @@
// #define USE_DUMP
+/* use only for small arrays */
+BLI_INLINE bool array_contains_pointer(const void **arr, unsigned int arr_len, const void *item)
+{
+ BLI_assert(arr_len < 3);
+ for (unsigned int i = 0; i < arr_len; i++) {
+ if (arr[i] == item) {
+ return true;
+ }
+ }
+ return false;
+}
+
static void tri_v3_scale(
float v1[3], float v2[3], float v3[3],
const float t)
@@ -535,6 +547,7 @@ static void bm_isect_tri_tri(
const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)};
float f_a_nor[3];
float f_b_nor[3];
+ /* track vertices which have been added to 'iv_ls_a' & 'iv_ls_b' */
int a_mask = 0;
int b_mask = 0;
unsigned int i;
@@ -556,6 +569,24 @@ static void bm_isect_tri_tri(
STACK_INIT(iv_ls_a, ARRAY_SIZE(iv_ls_a));
STACK_INIT(iv_ls_b, ARRAY_SIZE(iv_ls_b));
+ /* don't test, but we must be sure not to add doubles (assert instead). */
+#ifndef NDEBUG
+# define STACK_PUSH_NOTEST(arr, ele) \
+ { \
+ BLI_assert(BLI_array_findindex(arr, STACK_SIZE(arr), &(ele)) == -1); \
+ STACK_PUSH(arr, ele); \
+ } ((void)0)
+#else
+# define STACK_PUSH_NOTEST STACK_PUSH
+#endif
+
+ /* warning, this seems like it might be inefficent,
+ * however there will be <3 items in this case. */
+# define STACK_PUSH_TEST(arr, ele, arr_offset) \
+ if (!array_contains_pointer((const void **)(&(arr)[arr_offset]), STACK_SIZE(arr) - (arr_offset), (void *)ele)) { \
+ STACK_PUSH(arr, ele); \
+ } ((void)0)
+
/* vert-vert
* --------- */
{
@@ -568,7 +599,7 @@ static void bm_isect_tri_tri(
for (i_b = 0; i_b < 3; i_b++) {
if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
if (!((1 << i_a) & a_mask)) {
- STACK_PUSH(iv_ls_a, fv_a[i_a]);
+ STACK_PUSH_NOTEST(iv_ls_a, fv_a[i_a]);
a_mask |= (1 << i_a);
#ifdef USE_DUMP
printf(" ('VERT-VERT-A') %d, %d),\n",
@@ -576,7 +607,7 @@ static void bm_isect_tri_tri(
#endif
}
if (!((1 << i_b) & b_mask)) {
- STACK_PUSH(iv_ls_b, fv_b[i_b]);
+ STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]);
b_mask |= (1 << i_b);
#ifdef USE_DUMP
printf(" ('VERT-VERT-B') %d, %d),\n",
@@ -606,8 +637,8 @@ static void bm_isect_tri_tri(
interp_v3_v3v3(ix, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co, fac);
if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
BMEdge *e;
- STACK_PUSH(iv_ls_b, fv_a[i_a]);
- // STACK_PUSH(iv_ls_a, fv_a[i_a]);
+ STACK_PUSH_NOTEST(iv_ls_b, fv_a[i_a]);
+ // STACK_PUSH_NOTEST(iv_ls_a, fv_a[i_a]);
a_mask |= (1 << i_a);
e = BM_edge_exists(fv_b[i_b_e0], fv_b[i_b_e1]);
#ifdef USE_DUMP
@@ -644,8 +675,8 @@ static void bm_isect_tri_tri(
interp_v3_v3v3(ix, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co, fac);
if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
BMEdge *e;
- STACK_PUSH(iv_ls_a, fv_b[i_b]);
- // STACK_PUSH(iv_ls_b, fv_b[i_b]);
+ STACK_PUSH_NOTEST(iv_ls_a, fv_b[i_b]);
+ // STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]);
b_mask |= (1 << i_b);
e = BM_edge_exists(fv_a[i_a_e0], fv_a[i_a_e1]);
#ifdef USE_DUMP
@@ -685,11 +716,8 @@ static void bm_isect_tri_tri(
continue;
if (isect_point_tri_v3(fv_a[i_a]->co, UNPACK3(t_scale), ix)) {
if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
- BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), fv_a[i_a]) == -1);
- BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), fv_a[i_a]) == -1);
-
- STACK_PUSH(iv_ls_a, fv_a[i_a]);
- STACK_PUSH(iv_ls_b, fv_a[i_a]);
+ STACK_PUSH_NOTEST(iv_ls_a, fv_a[i_a]);
+ STACK_PUSH_NOTEST(iv_ls_b, fv_a[i_a]);
a_mask |= (1 << i_a);
#ifdef USE_DUMP
printf(" 'VERT TRI-A',\n");
@@ -715,11 +743,8 @@ static void bm_isect_tri_tri(
if (isect_point_tri_v3(fv_b[i_b]->co, UNPACK3(t_scale), ix)) {
if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
- BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), fv_b[i_b]) == -1);
- BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), fv_b[i_b]) == -1);
-
- STACK_PUSH(iv_ls_a, fv_b[i_b]);
- STACK_PUSH(iv_ls_b, fv_b[i_b]);
+ STACK_PUSH_NOTEST(iv_ls_a, fv_b[i_b]);
+ STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]);
b_mask |= (1 << i_b);
#ifdef USE_DUMP
printf(" 'VERT TRI-B',\n");
@@ -744,6 +769,17 @@ static void bm_isect_tri_tri(
/* edge-tri & edge-edge
* -------------------- */
{
+ /**
+ * Note that its possible to add the same vertex multiple times
+ * with near degenerate faces (or a large epsilon).
+ *
+ * For this reason we have #STACK_PUSH_TEST macro which only adds vertices that aren't already added.
+ * Since we know none of the vertices from #bm_isect_edge_tri, the check can be offset.
+ */
+
+ const unsigned int iv_ls_a_offset = STACK_SIZE(iv_ls_a);
+ const unsigned int iv_ls_b_offset = STACK_SIZE(iv_ls_b);
+
unsigned int i_e0;
for (i_e0 = 0; i_e0 < 3; i_e0++) {
unsigned int i_e1 = (i_e0 + 1) % 3;
@@ -753,10 +789,8 @@ static void bm_isect_tri_tri(
continue;
iv = bm_isect_edge_tri(s, fv_a[i_e0], fv_a[i_e1], fv_b, b_index, f_b_cos, f_b_nor, &side);
if (iv) {
- BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1);
- BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1);
- STACK_PUSH(iv_ls_a, iv);
- STACK_PUSH(iv_ls_b, iv);
+ STACK_PUSH_TEST(iv_ls_a, iv, iv_ls_a_offset);
+ STACK_PUSH_TEST(iv_ls_b, iv, iv_ls_b_offset);
#ifdef USE_DUMP
printf(" ('EDGE-TRI-A', %d),\n", side);
#endif
@@ -771,10 +805,8 @@ static void bm_isect_tri_tri(
continue;
iv = bm_isect_edge_tri(s, fv_b[i_e0], fv_b[i_e1], fv_a, a_index, f_a_cos, f_a_nor, &side);
if (iv) {
- BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1);
- BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1);
- STACK_PUSH(iv_ls_a, iv);
- STACK_PUSH(iv_ls_b, iv);
+ STACK_PUSH_TEST(iv_ls_a, iv, iv_ls_a_offset);
+ STACK_PUSH_TEST(iv_ls_b, iv, iv_ls_b_offset);
#ifdef USE_DUMP
printf(" ('EDGE-TRI-B', %d),\n", side);
#endif
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index a82cca9e52a..c24ca1e7027 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -158,7 +158,7 @@ static int add_driver_with_target(
ReportList *UNUSED(reports),
ID *dst_id, const char dst_path[], int dst_index,
ID *src_id, const char src_path[], int src_index,
- PointerRNA *UNUSED(dst_ptr), PropertyRNA *dst_prop,
+ PointerRNA *dst_ptr, PropertyRNA *dst_prop,
PointerRNA *src_ptr, PropertyRNA *src_prop,
short flag, int driver_type)
{
@@ -207,11 +207,15 @@ static int add_driver_with_target(
/* Create a driver variable for the target
* - For transform properties, we want to automatically use "transform channel" instead
* (The only issue is with quat rotations vs euler channels...)
+ * - To avoid problems with transform properties depending on the final transform that they
+ * control (thus creating pseudo-cycles - see T48734), we don't use transform channels
+ * when both the source and destinaions are in same places.
*/
dvar = driver_add_new_variable(driver);
if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) &&
- (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")))
+ (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")) &&
+ (src_ptr->data != dst_ptr->data))
{
/* Transform Channel */
DriverTarget *dtar;
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 08a7355694b..7b35a154fc8 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -539,10 +539,10 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
}
/**
- * only called from #ok_bezier_region_lasso
+ * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso
*/
-static bool bezier_region_lasso_test(
- const struct KeyframeEdit_LassoData *data_lasso,
+bool keyframe_region_lasso_test(
+ const KeyframeEdit_LassoData *data_lasso,
const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) {
@@ -564,7 +564,7 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
if (ked->data) {
short ok = 0;
-#define KEY_CHECK_OK(_index) bezier_region_lasso_test(ked->data, bezt->vec[_index])
+#define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index])
KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
#undef KEY_CHECK_OK
@@ -575,11 +575,38 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
+static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt)
+{
+ /* check for lasso customdata (KeyframeEdit_LassoData) */
+ if (ked->data) {
+ KeyframeEdit_LassoData *data = ked->data;
+ float pt[2];
+
+ /* late-binding remap of the x values (for summary channels) */
+ /* XXX: Ideally we reset, but it should be fine just leaving it as-is
+ * as the next channel will reset it properly, while the next summary-channel
+ * curve will also reset by itself...
+ */
+ if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
+ data->rectf_scaled->xmin = ked->f1;
+ data->rectf_scaled->xmax = ked->f2;
+ }
+
+ /* only use the x-coordinate of the point; the y is the channel range... */
+ pt[0] = bezt->vec[1][0];
+ pt[1] = ked->channel_y;
+
+ if (keyframe_region_lasso_test(data, pt))
+ return KEYFRAME_OK_KEY;
+ }
+ return 0;
+}
+
/**
- * only called from #ok_bezier_region_circle
+ * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle
*/
-static bool bezier_region_circle_test(
- const struct KeyframeEdit_CircleData *data_circle,
+bool keyframe_region_circle_test(
+ const KeyframeEdit_CircleData *data_circle,
const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
@@ -602,7 +629,7 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
if (ked->data) {
short ok = 0;
-#define KEY_CHECK_OK(_index) bezier_region_circle_test(ked->data, bezt->vec[_index])
+#define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index])
KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
#undef KEY_CHECK_OK
@@ -613,6 +640,33 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
+static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt)
+{
+ /* check for circle select customdata (KeyframeEdit_CircleData) */
+ if (ked->data) {
+ KeyframeEdit_CircleData *data = ked->data;
+ float pt[2];
+
+ /* late-binding remap of the x values (for summary channels) */
+ /* XXX: Ideally we reset, but it should be fine just leaving it as-is
+ * as the next channel will reset it properly, while the next summary-channel
+ * curve will also reset by itself...
+ */
+ if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
+ data->rectf_scaled->xmin = ked->f1;
+ data->rectf_scaled->xmax = ked->f2;
+ }
+
+ /* only use the x-coordinate of the point; the y is the channel range... */
+ pt[0] = bezt->vec[1][0];
+ pt[1] = ked->channel_y;
+
+ if (keyframe_region_circle_test(data, pt))
+ return KEYFRAME_OK_KEY;
+ }
+ return 0;
+}
+
KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
{
@@ -634,6 +688,10 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
return ok_bezier_region_lasso;
case BEZT_OK_REGION_CIRCLE: /* only if the point falls within KeyframeEdit_CircleData defined data */
return ok_bezier_region_circle;
+ case BEZT_OK_CHANNEL_LASSO: /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */
+ return ok_bezier_channel_lasso;
+ case BEZT_OK_CHANNEL_CIRCLE: /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */
+ return ok_bezier_channel_circle;
default: /* nothing was ok */
return NULL;
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 66b3a63c669..0c0f54f0179 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -1069,6 +1069,9 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou
if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) {
fcu->color_mode = FCURVE_COLOR_AUTO_RGB;
}
+ else if (RNA_property_subtype(prop), PROP_QUATERNION) {
+ fcu->color_mode = FCURVE_COLOR_AUTO_YRGB;
+ }
}
/* insert keyframe */
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index a49b3362155..738496a67c6 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -205,6 +205,36 @@ void ED_gplayer_frames_select_border(bGPDlayer *gpl, float min, float max, short
}
}
+/* select the frames in this layer that occur within the lasso/circle region specified */
+void ED_gplayer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, short tool, short select_mode)
+{
+ bGPDframe *gpf;
+
+ if (gpl == NULL)
+ return;
+
+ /* only select frames which are within the region */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* construct a dummy point coordinate to do this testing with */
+ float pt[2] = {0};
+
+ pt[0] = gpf->framenum;
+ pt[1] = ked->channel_y;
+
+ /* check the necessary regions */
+ if (tool == BEZT_OK_CHANNEL_LASSO) {
+ /* Lasso */
+ if (keyframe_region_lasso_test(ked->data, pt))
+ gpframe_select(gpf, select_mode);
+ }
+ else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
+ /* Circle */
+ if (keyframe_region_circle_test(ked->data, pt))
+ gpframe_select(gpf, select_mode);
+ }
+ }
+}
+
/* ***************************************** */
/* Frame Editing Tools */
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index bd1697b9a54..ac49a51c716 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -652,7 +652,7 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
/* identifiers */
ot->name = "Delete Active Frame";
ot->idname = "GPENCIL_OT_active_frame_delete";
- ot->description = "Delete the active frame for the active Grease Pencil datablock";
+ ot->description = "Delete the active frame for the active Grease Pencil Layer";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -661,6 +661,64 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
ot->poll = gp_actframe_delete_poll;
}
+/* **************** Delete All Active Frames ****************** */
+
+static int gp_actframe_delete_all_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ /* 1) There must be grease pencil data
+ * 2) Hopefully some of the layers have stuff we can use
+ */
+ return (gpd && gpd->layers.first);
+}
+
+static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ bool success = false;
+
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ /* try to get the "active" frame - but only if it actually occurs on this frame */
+ bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+
+ if (gpf == NULL)
+ continue;
+
+ /* delete it... */
+ gpencil_layer_delframe(gpl, gpf);
+
+ /* we successfully modified something */
+ success = true;
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ if (success) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No active frame(s) to delete");
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete All Active Frames";
+ ot->idname = "GPENCIL_OT_active_frames_delete_all";
+ ot->description = "Delete the active frame(s) of all editable Grease Pencil layers";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_actframe_delete_all_exec;
+ ot->poll = gp_actframe_delete_all_poll;
+}
+
/* ******************* Delete Operator ************************ */
typedef enum eGP_DeleteMode {
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index dd28f6ac531..53fb33eeb9b 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -218,6 +218,7 @@ void GPENCIL_OT_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot);
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
+void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 405b673c42b..65ee1122b56 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -105,7 +105,7 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
/* Delete Active Frame - For easier video tutorials/review sessions */
/* NOTE: This works even when not in EditMode */
- WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, 0, DKEY);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, 0, DKEY);
}
/* ==================== */
@@ -238,7 +238,7 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, KM_SHIFT, 0);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, KM_SHIFT, 0);
/* copy + paste */
WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
@@ -364,6 +364,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_layer_isolate);
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
+ WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
WM_operatortype_append(GPENCIL_OT_convert);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index fba2f30e715..a570d586f50 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -97,7 +97,8 @@ typedef enum eGP_StrokeAdd_Result {
typedef enum eGPencil_PaintFlags {
GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
GP_PAINTFLAG_STROKEADDED = (1 << 1),
- GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2)
+ GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
+ GP_PAINTFLAG_SELECTMASK = (1 << 3),
} eGPencil_PaintFlags;
@@ -813,18 +814,21 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
BLI_freelinkN(&gpf->strokes, gps);
}
else if (gps->totpoints == 1) {
- gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
-
- /* do boundbox check first */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
- /* only check if point is inside */
- if (len_v2v2_int(mval, pc1) <= radius) {
- /* free stroke */
- // XXX: pressure sensitive eraser should apply here too?
- MEM_freeN(gps->points);
- if (gps->triangles)
- MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ /* only process if it hasn't been masked out... */
+ if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
+ gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
+
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ if (len_v2v2_int(mval, pc1) <= radius) {
+ /* free stroke */
+ // XXX: pressure sensitive eraser should apply here too?
+ MEM_freeN(gps->points);
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+ }
}
}
}
@@ -862,6 +866,11 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
+ /* only process if it hasn't been masked out... */
+ if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
+ continue;
+
+ /* get coordinates of point in screenspace */
gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
@@ -1199,6 +1208,7 @@ static void gp_session_cleanup(tGPsdata *p)
static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
{
Scene *scene = p->scene;
+ ToolSettings *ts = scene->toolsettings;
/* get active layer (or add a new one if non-existent) */
p->gpl = gpencil_layer_getactive(p->gpd);
@@ -1242,6 +1252,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
/* Ensure this gets set... */
p->gpf = p->gpl->actframe;
+ /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
+ * (though this is only available in editmode)
+ */
+ if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ if (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) {
+ p->flags |= GP_PAINTFLAG_SELECTMASK;
+ }
+ }
+
if (p->gpf == NULL) {
p->status = GP_STATUS_ERROR;
//if (G.debug & G_DEBUG)
@@ -1251,7 +1270,6 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
}
else {
/* Drawing Modes - Add a new frame if needed on the active layer */
- ToolSettings *ts = p->scene->toolsettings;
short add_frame_mode;
if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 80f930a0c30..92acfa6c1d2 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -109,7 +109,7 @@ int ED_file_extension_icon(const char *path);
void ED_file_read_bookmarks(void);
-void ED_file_change_dir(struct bContext *C, const bool checkdir);
+void ED_file_change_dir(struct bContext *C);
/* File menu stuff */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 255827db373..de5ab80a88f 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -42,6 +42,7 @@ struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
struct bAnimContext;
+struct KeyframeEditData;
struct PointerRNA;
struct wmWindowManager;
struct wmKeyConfig;
@@ -120,6 +121,7 @@ void ED_gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool only
bool ED_gplayer_frame_select_check(struct bGPDlayer *gpl);
void ED_gplayer_frame_select_set(struct bGPDlayer *gpl, short mode);
void ED_gplayer_frames_select_border(struct bGPDlayer *gpl, float min, float max, short select_mode);
+void ED_gplayer_frames_select_region(struct KeyframeEditData *ked, struct bGPDlayer *gpl, short tool, short select_mode);
void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode);
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index fae3e3677a0..c0eb88cd982 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -45,14 +45,21 @@ struct Scene;
/* bezt validation */
typedef enum eEditKeyframes_Validate {
+ /* Frame range */
BEZT_OK_FRAME = 1,
BEZT_OK_FRAMERANGE,
+ /* Selection status */
BEZT_OK_SELECTED,
+ /* Values (y-val) only */
BEZT_OK_VALUE,
BEZT_OK_VALUERANGE,
+ /* For graph editor keyframes (2D tests) */
BEZT_OK_REGION,
BEZT_OK_REGION_LASSO,
BEZT_OK_REGION_CIRCLE,
+ /* Only for keyframes a certain Dopesheet channel */
+ BEZT_OK_CHANNEL_LASSO,
+ BEZT_OK_CHANNEL_CIRCLE,
} eEditKeyframes_Validate;
/* ------------ */
@@ -97,20 +104,20 @@ typedef enum eEditKeyframes_Mirror {
} eEditKeyframes_Mirror;
/* use with BEZT_OK_REGION_LASSO */
-struct KeyframeEdit_LassoData {
- const rctf *rectf_scaled;
+typedef struct KeyframeEdit_LassoData {
+ rctf *rectf_scaled;
const rctf *rectf_view;
const int (*mcords)[2];
int mcords_tot;
-};
+} KeyframeEdit_LassoData;
/* use with BEZT_OK_REGION_CIRCLE */
-struct KeyframeEdit_CircleData {
- const rctf *rectf_scaled;
+typedef struct KeyframeEdit_CircleData {
+ rctf *rectf_scaled;
const rctf *rectf_view;
float mval[2];
float radius_squared;
-};
+} KeyframeEdit_CircleData;
/* ************************************************ */
@@ -157,7 +164,8 @@ typedef struct KeyframeEditData {
/* current iteration data */
struct FCurve *fcu; /* F-Curve that is being iterated over */
int curIndex; /* index of current keyframe being iterated over */
-
+ float channel_y; /* y-position of midpoint of the channel (for the dopesheet) */
+
/* flags */
eKeyframeVertOk curflags; /* current flags for the keyframe we're reached in the iteration process */
eKeyframeIterFlags iterflags; /* settings for iteration process */
@@ -258,6 +266,18 @@ short bezt_to_cfraelem(KeyframeEditData *ked, struct BezTriple *bezt);
*/
void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt);
+/* ------ 1.5-D Region Testing Uitls (Lasso/Circle Select) ------- */
+/* XXX: These are temporary, until we can unify GP/Mask Keyframe handling and standard FCurve Keyframe handling */
+
+bool keyframe_region_lasso_test(
+ const KeyframeEdit_LassoData *data_lasso,
+ const float xy[2]);
+
+bool keyframe_region_circle_test(
+ const KeyframeEdit_CircleData *data_circle,
+ const float xy[2]);
+
+
/* ************************************************ */
/* Destructive Editing API (keyframes_general.c) */
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 1f13b46ff2a..2ab788d5e2a 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -35,6 +35,7 @@ struct bContext;
struct wmKeyConfig;
struct MaskLayer;
struct MaskLayerShape;
+struct KeyframeEditData;
/* mask_edit.c */
void ED_mask_get_size(struct ScrArea *sa, int *width, int *height);
@@ -80,6 +81,7 @@ void ED_masklayer_make_cfra_list(struct MaskLayer *masklay, ListBase *elems, boo
bool ED_masklayer_frame_select_check(struct MaskLayer *masklay);
void ED_masklayer_frame_select_set(struct MaskLayer *masklay, short mode);
void ED_masklayer_frames_select_border(struct MaskLayer *masklay, float min, float max, short select_mode);
+void ED_masklayer_frames_select_region(struct KeyframeEditData *ked, struct MaskLayer *masklay, short tool, short select_mode);
void ED_mask_select_frames(struct MaskLayer *masklay, short select_mode);
void ED_mask_select_frame(struct MaskLayer *masklay, int selx, short select_mode);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 9aad340d2fb..a623f5cfb9c 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1020,12 +1020,18 @@ bool UI_context_copy_to_selected_list(
/* Helpers for Operators */
uiBut *UI_context_active_but_get(const struct bContext *C);
-void UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index);
+void UI_context_active_but_prop_get(
+ const struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index);
void UI_context_active_but_prop_handle(struct bContext *C);
struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
void UI_context_update_anim_flag(const struct bContext *C);
-void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo);
-void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop);
+void UI_context_active_but_prop_get_filebrowser(
+ const struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo);
+void UI_context_active_but_prop_get_templateID(
+ struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop);
/* Styled text draw */
void UI_fontstyle_set(const struct uiFontStyle *fs);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index fac1267cc62..77990066027 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -4323,7 +4323,7 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle
/**
- * \param sfunc, bfunc: both get it as \a arg.
+ * \param search_func, bfunc: both get it as \a arg.
* \param arg: user value,
* \param active: when set, button opens with this item visible and selected.
*/
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 133487e1846..f941993a9e1 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -8013,20 +8013,21 @@ uiBut *UI_context_active_but_get(const struct bContext *C)
}
/* helper function for insert keyframe, reset to default, etc operators */
-void UI_context_active_but_prop_get(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index)
+void UI_context_active_but_prop_get(
+ const bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index)
{
uiBut *activebut = ui_context_rna_button_active(C);
- memset(ptr, 0, sizeof(*ptr));
-
if (activebut && activebut->rnapoin.data) {
- *ptr = activebut->rnapoin;
- *prop = activebut->rnaprop;
- *index = activebut->rnaindex;
+ *r_ptr = activebut->rnapoin;
+ *r_prop = activebut->rnaprop;
+ *r_index = activebut->rnaindex;
}
else {
- *prop = NULL;
- *index = 0;
+ memset(r_ptr, 0, sizeof(*r_ptr));
+ *r_prop = NULL;
+ *r_index = 0;
}
}
@@ -9812,10 +9813,17 @@ static int ui_handle_menus_recursive(
retval = ui_pie_handler(C, event, menu);
}
else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK) {
+ bool handled = false;
+
if (listbox) {
- retval = ui_handle_list_event(C, event, menu->region, listbox);
+ int retval_test = ui_handle_list_event(C, event, menu->region, listbox);
+ if (retval_test != WM_UI_HANDLER_CONTINUE) {
+ retval = retval_test;
+ handled = true;
+ }
}
- if (retval == WM_UI_HANDLER_CONTINUE) {
+
+ if (handled == false) {
retval = ui_handle_menu_event(
C, event, menu, level,
is_parent_inside, is_parent_menu, is_floating);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index f1f9c4ef0cb..cf3a50d632a 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -231,15 +231,17 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
/* This is for browsing and editing the ID-blocks used */
/* for new/open operators */
-void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
+void UI_context_active_but_prop_get_templateID(
+ bContext *C,
+ PointerRNA *r_ptr, PropertyRNA **r_prop)
{
TemplateID *template;
ARegion *ar = CTX_wm_region(C);
uiBlock *block;
uiBut *but;
- memset(ptr, 0, sizeof(*ptr));
- *prop = NULL;
+ memset(r_ptr, 0, sizeof(*r_ptr));
+ *r_prop = NULL;
if (!ar)
return;
@@ -250,8 +252,8 @@ void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, Pro
if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) {
if (but->func_argN) {
template = but->func_argN;
- *ptr = template->ptr;
- *prop = template->prop;
+ *r_ptr = template->ptr;
+ *r_prop = template->prop;
return;
}
}
diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c
index bcf9ee5c88d..16147bdc7f8 100644
--- a/source/blender/editors/mask/mask_editaction.c
+++ b/source/blender/editors/mask/mask_editaction.c
@@ -201,6 +201,36 @@ void ED_masklayer_frames_select_border(MaskLayer *masklay, float min, float max,
}
}
+/* select the frames in this layer that occur within the lasso/circle region specified */
+void ED_masklayer_frames_select_region(KeyframeEditData *ked, MaskLayer *masklay, short tool, short select_mode)
+{
+ MaskLayerShape *masklay_shape;
+
+ if (masklay == NULL)
+ return;
+
+ /* only select frames which are within the region */
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
+ /* construct a dummy point coordinate to do this testing with */
+ float pt[2] = {0};
+
+ pt[0] = masklay_shape->frame;
+ pt[1] = ked->channel_y;
+
+ /* check the necessary regions */
+ if (tool == BEZT_OK_CHANNEL_LASSO) {
+ /* Lasso */
+ if (keyframe_region_lasso_test(ked->data, pt))
+ masklayshape_select(masklay_shape, select_mode);
+ }
+ else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
+ /* Circle */
+ if (keyframe_region_circle_test(ked->data, pt))
+ masklayshape_select(masklay_shape, select_mode);
+ }
+ }
+}
+
/* ***************************************** */
/* Frame Editing Tools */
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 01be8f848aa..c4e87614732 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -53,6 +53,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "GPU_draw.h"
#include "GPU_buffers.h"
/* own include */
@@ -433,7 +434,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
if (ENDIAN_ORDER == B_ENDIAN) {
IMB_convert_rgba_to_abgr(ibuf);
}
- WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]);
+ GPU_select_to_index_array(ibuf->rect, size[0] * size[1]);
a = size[0] * size[1];
while (a--) {
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index efd1ebbd51b..9c2806f6f5a 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -1560,12 +1560,12 @@ void OBJECT_OT_constraints_copy(wmOperatorType *ot)
/************************ add constraint operators *********************/
/* get the Object and/or PoseChannel to use as target */
-static short get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, short add)
+static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add)
{
Object *obact = ED_object_active_context(C);
bPoseChannel *pchanact = BKE_pose_channel_active(obact);
- short only_curve = 0, only_mesh = 0, only_ob = 0;
- short found = 0;
+ bool only_curve = false, only_mesh = false, only_ob = false;
+ bool found = false;
/* clear tar_ob and tar_pchan fields before use
* - assume for now that both always exist...
@@ -1585,7 +1585,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
case CONSTRAINT_TYPE_ROTLIMIT:
case CONSTRAINT_TYPE_SIZELIMIT:
case CONSTRAINT_TYPE_SAMEVOL:
- return 0;
+ return false;
/* restricted target-type constraints -------------- */
/* NOTE: for these, we cannot try to add a target object if no valid ones are found, since that doesn't work */
@@ -1593,26 +1593,26 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
case CONSTRAINT_TYPE_CLAMPTO:
case CONSTRAINT_TYPE_FOLLOWPATH:
case CONSTRAINT_TYPE_SPLINEIK:
- only_curve = 1;
- only_ob = 1;
- add = 0;
+ only_curve = true;
+ only_ob = true;
+ add = false;
break;
/* mesh only? */
case CONSTRAINT_TYPE_SHRINKWRAP:
- only_mesh = 1;
- only_ob = 1;
- add = 0;
+ only_mesh = true;
+ only_ob = true;
+ add = false;
break;
/* object only - add here is ok? */
case CONSTRAINT_TYPE_RIGIDBODYJOINT:
- only_ob = 1;
+ only_ob = true;
break;
}
/* if the active Object is Armature, and we can search for bones, do so... */
- if ((obact->type == OB_ARMATURE) && (only_ob == 0)) {
+ if ((obact->type == OB_ARMATURE) && (only_ob == false)) {
/* search in list of selected Pose-Channels for target */
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
{
@@ -1620,7 +1620,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
if (pchan != pchanact) {
*tar_ob = obact;
*tar_pchan = pchan;
- found = 1;
+ found = true;
break;
}
@@ -1629,36 +1629,50 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
}
/* if not yet found, try selected Objects... */
- if (found == 0) {
+ if (found == false) {
/* search in selected objects context */
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
/* just use the first object we encounter (that isn't the active object)
* and which fulfills the criteria for the object-target that we've got
*/
- if ((ob != obact) &&
- ((!only_curve) || (ob->type == OB_CURVE)) &&
- ((!only_mesh) || (ob->type == OB_MESH)))
- {
- /* set target */
- *tar_ob = ob;
- found = 1;
-
- /* perform some special operations on the target */
- if (only_curve) {
- /* Curve-Path option must be enabled for follow-path constraints to be able to work */
- Curve *cu = (Curve *)ob->data;
- cu->flag |= CU_PATH;
+ if (ob != obact) {
+ /* for armatures in pose mode, look inside the armature for the active bone
+ * so that we set up cross-armature constraints with less effort
+ */
+ if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) &&
+ (!only_curve && !only_mesh))
+ {
+ /* just use the active bone, and assume that it is visible + usable */
+ *tar_ob = ob;
+ *tar_pchan = BKE_pose_channel_active(ob);
+ found = true;
+
+ break;
+ }
+ else if (((!only_curve) || (ob->type == OB_CURVE)) &&
+ ((!only_mesh) || (ob->type == OB_MESH)))
+ {
+ /* set target */
+ *tar_ob = ob;
+ found = true;
+
+ /* perform some special operations on the target */
+ if (only_curve) {
+ /* Curve-Path option must be enabled for follow-path constraints to be able to work */
+ Curve *cu = (Curve *)ob->data;
+ cu->flag |= CU_PATH;
+ }
+
+ break;
}
-
- break;
}
}
CTX_DATA_END;
}
/* if still not found, add a new empty to act as a target (if allowed) */
- if ((found == 0) && (add)) {
+ if ((found == false) && (add)) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Base *base = BASACT, *newbase = NULL;
@@ -1692,7 +1706,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
/* make our new target the new object */
*tar_ob = obt;
- found = 1;
+ found = true;
}
/* return whether there's any target */
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 31b7b584a3a..7a55418b082 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -436,7 +436,7 @@ typedef enum eObClearParentTypes {
EnumPropertyItem prop_clear_parent_types[] = {
{CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent",
- "Completely clear the parenting relationship, including involved modifiers is any"},
+ "Completely clear the parenting relationship, including involved modifiers if any"},
{CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation",
"As 'Clear Parent', but keep the current visual transformations of the object"},
{CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse",
diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h
index 50e10e7e154..408eb38d386 100644
--- a/source/blender/editors/space_action/action_intern.h
+++ b/source/blender/editors/space_action/action_intern.h
@@ -59,6 +59,8 @@ void draw_channel_strips(struct bAnimContext *ac, struct SpaceAction *saction, s
void ACTION_OT_select_all_toggle(struct wmOperatorType *ot);
void ACTION_OT_select_border(struct wmOperatorType *ot);
+void ACTION_OT_select_lasso(struct wmOperatorType *ot);
+void ACTION_OT_select_circle(struct wmOperatorType *ot);
void ACTION_OT_select_column(struct wmOperatorType *ot);
void ACTION_OT_select_linked(struct wmOperatorType *ot);
void ACTION_OT_select_more(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c
index f69f9944f8a..a261202b690 100644
--- a/source/blender/editors/space_action/action_ops.c
+++ b/source/blender/editors/space_action/action_ops.c
@@ -59,6 +59,8 @@ void action_operatortypes(void)
WM_operatortype_append(ACTION_OT_clickselect);
WM_operatortype_append(ACTION_OT_select_all_toggle);
WM_operatortype_append(ACTION_OT_select_border);
+ WM_operatortype_append(ACTION_OT_select_lasso);
+ WM_operatortype_append(ACTION_OT_select_circle);
WM_operatortype_append(ACTION_OT_select_column);
WM_operatortype_append(ACTION_OT_select_linked);
WM_operatortype_append(ACTION_OT_select_more);
@@ -178,6 +180,14 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
+ /* region select */
+ kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", false);
+ kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", true);
+
+ WM_keymap_add_item(keymap, "ACTION_OT_select_circle", CKEY, KM_PRESS, 0, 0);
+
/* column select */
RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS);
RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA);
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index f2813b2a8d3..0b6d3cb1f60 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -36,6 +36,7 @@
#include "BLI_blenlib.h"
#include "BLI_dlrbTree.h"
+#include "BLI_lasso.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@@ -375,6 +376,264 @@ void ACTION_OT_select_border(wmOperatorType *ot)
ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
}
+/* ******************** Region Select Operators ***************************** */
+/* "Region Select" operators include the Lasso and Circle Select operators.
+ * These two ended up being lumped together, as it was easier in the
+ * original Graph Editor implmentation of these to do it this way.
+ */
+
+static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, void *data)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ KeyframeEditData ked;
+ KeyframeEditFunc ok_cb, select_cb;
+ View2D *v2d = &ac->ar->v2d;
+ rctf rectf, scaled_rectf;
+ float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF);
+
+ /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
+ UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf);
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* get beztriple editing/validation funcs */
+ select_cb = ANIM_editkeyframes_select(selectmode);
+ ok_cb = ANIM_editkeyframes_ok(mode);
+
+ /* init editing data */
+ memset(&ked, 0, sizeof(KeyframeEditData));
+ if (mode == BEZT_OK_CHANNEL_LASSO) {
+ KeyframeEdit_LassoData *data_lasso = data;
+ data_lasso->rectf_scaled = &scaled_rectf;
+ ked.data = data_lasso;
+ }
+ else if (mode == BEZT_OK_CHANNEL_CIRCLE) {
+ KeyframeEdit_CircleData *data_circle = data;
+ data_circle->rectf_scaled = &scaled_rectf;
+ ked.data = data;
+ }
+ else {
+ ked.data = &scaled_rectf;
+ }
+
+ /* loop over data, doing region select */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+
+ /* get new vertical minimum extent of channel */
+ ymin = ymax - ACHANNEL_STEP;
+
+ /* compute midpoint of channel (used for testing if the key is in the region or not) */
+ ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF;
+
+ /* if channel is mapped in NLA, apply correction
+ * - Apply to the bounds being checked, not all the keyframe points,
+ * to avoid having scaling everything
+ * - Save result to the scaled_rect, which is all that these operators
+ * will read from
+ */
+ if (adt) {
+ ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP);
+ ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP);
+ ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
+ ked.f1 = rectf.xmin;
+ ked.f2 = rectf.xmax;
+ }
+
+ /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks
+ * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these
+ * with the properly remapped ked.f1/f2 values, when needed
+ */
+ scaled_rectf.xmin = ked.f1;
+ scaled_rectf.xmax = ked.f2;
+ scaled_rectf.ymin = ymin;
+ scaled_rectf.ymax = ymax;
+
+ /* perform vertical suitability check (if applicable) */
+ if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) ||
+ !((ymax < rectf.ymin) || (ymin > rectf.ymax)))
+ {
+ /* loop over data selecting */
+ switch (ale->type) {
+ case ANIMTYPE_GPDATABLOCK:
+ {
+ bGPdata *gpd = ale->data;
+ bGPDlayer *gpl;
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ }
+ break;
+ }
+ case ANIMTYPE_GPLAYER:
+ {
+ ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ break;
+ }
+ case ANIMTYPE_MASKDATABLOCK:
+ {
+ Mask *mask = ale->data;
+ MaskLayer *masklay;
+ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ ED_masklayer_frames_select_region(&ked, masklay, mode, selectmode);
+ }
+ break;
+ }
+ case ANIMTYPE_MASKLAYER:
+ {
+ ED_masklayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ break;
+ }
+ default:
+ ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
+ break;
+ }
+ }
+
+ /* set minimum extent to be the maximum of the next channel */
+ ymax = ymin;
+ }
+
+ /* cleanup */
+ ANIM_animdata_freelist(&anim_data);
+}
+
+/* ----------------------------------- */
+
+static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ KeyframeEdit_LassoData data_lasso;
+ rcti rect;
+ rctf rect_fl;
+
+ short selectmode;
+ bool extend;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ data_lasso.rectf_view = &rect_fl;
+ data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
+ if (data_lasso.mcords == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* clear all selection if not extending selection */
+ extend = RNA_boolean_get(op->ptr, "extend");
+ if (!extend)
+ deselect_action_keys(&ac, 1, SELECT_SUBTRACT);
+
+ if (!RNA_boolean_get(op->ptr, "deselect"))
+ selectmode = SELECT_ADD;
+ else
+ selectmode = SELECT_SUBTRACT;
+
+ /* get settings from operator */
+ BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
+ BLI_rctf_rcti_copy(&rect_fl, &rect);
+
+ /* apply borderselect action */
+ region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso);
+
+ MEM_freeN((void *)data_lasso.mcords);
+
+ /* send notifier that keyframe selection has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_select_lasso(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Lasso Select";
+ ot->description = "Select keyframe points using lasso selection";
+ ot->idname = "ACTION_OT_select_lasso";
+
+ /* api callbacks */
+ ot->invoke = WM_gesture_lasso_invoke;
+ ot->modal = WM_gesture_lasso_modal;
+ ot->exec = actkeys_lassoselect_exec;
+ ot->poll = ED_operator_action_active;
+ ot->cancel = WM_gesture_lasso_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
+ RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
+ RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
+}
+
+/* ------------------- */
+
+static int action_circle_select_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+ const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
+ const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT;
+
+ KeyframeEdit_CircleData data = {0};
+ rctf rect_fl;
+
+ float x = RNA_int_get(op->ptr, "x");
+ float y = RNA_int_get(op->ptr, "y");
+ float radius = RNA_int_get(op->ptr, "radius");
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ data.mval[0] = x;
+ data.mval[1] = y;
+ data.radius_squared = radius * radius;
+ data.rectf_view = &rect_fl;
+
+ rect_fl.xmin = x - radius;
+ rect_fl.xmax = x + radius;
+ rect_fl.ymin = y - radius;
+ rect_fl.ymax = y + radius;
+
+ /* apply region select action */
+ region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data);
+
+ /* send notifier that keyframe selection has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_select_circle(wmOperatorType *ot)
+{
+ ot->name = "Circle Select";
+ ot->description = "Select keyframe points using circle selection";
+ ot->idname = "ACTION_OT_select_circle";
+
+ ot->invoke = WM_gesture_circle_invoke;
+ ot->modal = WM_gesture_circle_modal;
+ ot->exec = action_circle_select_exec;
+ ot->poll = ED_operator_action_active;
+ ot->cancel = WM_gesture_circle_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
+ RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
+}
+
/* ******************** Column Select Operator **************************** */
/* This operator works in one of four ways:
* - 1) select all keyframes in the same frame as a selected one (KKEY)
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 71e38f72a7a..a55b18a2212 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -128,6 +128,7 @@ void file_panels_register(struct ARegionType *art);
/* file_utils.c */
void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds);
+bool file_is_dir(struct SpaceFile *sfile, const char *path);
#endif /* __FILE_INTERN_H__ */
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index d83a7d5ea62..c42ff120102 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -208,7 +208,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
BLI_add_slash(params->dir);
}
- ED_file_change_dir(C, false);
+ ED_file_change_dir(C);
retval = FILE_SELECT_DIR;
}
}
@@ -826,7 +826,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op)
RNA_property_string_get(op->ptr, prop, entry);
BLI_strncpy(params->dir, entry, sizeof(params->dir));
BLI_cleanup_dir(G.main->name, params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -1379,7 +1379,7 @@ int file_exec(bContext *C, wmOperator *exec_op)
BLI_add_slash(sfile->params->dir);
}
- ED_file_change_dir(C, false);
+ ED_file_change_dir(C);
}
/* opening file - sends events now, so things get handled on windowqueue level */
else if (sfile->op) {
@@ -1447,19 +1447,7 @@ int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
if (sfile->params) {
if (BLI_parent_dir(sfile->params->dir)) {
BLI_cleanup_dir(G.main->name, sfile->params->dir);
- /* if not browsing in .blend file, we still want to check whether the path is a directory */
- if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX];
- if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, NULL)) {
- ED_file_change_dir(C, false);
- }
- else {
- ED_file_change_dir(C, true);
- }
- }
- else {
- ED_file_change_dir(C, true);
- }
+ ED_file_change_dir(C);
if (sfile->params->recursion_level > 1) {
/* Disable 'dirtree' recursion when going up in tree. */
sfile->params->recursion_level = 0;
@@ -1529,7 +1517,7 @@ int file_previous_exec(bContext *C, wmOperator *UNUSED(unused))
folderlist_popdir(sfile->folders_prev, sfile->params->dir);
folderlist_pushdir(sfile->folders_next, sfile->params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1561,7 +1549,7 @@ int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
// update folders_prev so we can check for it in folderlist_clear_next()
folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1809,7 +1797,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "open")) {
BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir));
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1906,17 +1894,35 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
file_expand_directory(C);
/* special case, user may have pasted a filepath into the directory */
- if (BLI_is_file(sfile->params->dir)) {
- char path[sizeof(sfile->params->dir)];
- BLI_strncpy(path, sfile->params->dir, sizeof(path));
- BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file));
+ if (!file_is_dir(sfile, sfile->params->dir)) {
+ char tdir[FILE_MAX_LIBEXTRA];
+ char *group, *name;
+
+ if (BLI_is_file(sfile->params->dir)) {
+ char path[sizeof(sfile->params->dir)];
+ BLI_strncpy(path, sfile->params->dir, sizeof(path));
+ BLI_split_dirfile(path, sfile->params->dir, sfile->params->file,
+ sizeof(sfile->params->dir), sizeof(sfile->params->file));
+ }
+ else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) {
+ if (group) {
+ BLI_path_append(tdir, sizeof(tdir), group);
+ }
+ BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir));
+ if (name) {
+ BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file));
+ }
+ else {
+ sfile->params->file[0] = '\0';
+ }
+ }
}
BLI_cleanup_dir(G.main->name, sfile->params->dir);
- if (BLI_exists(sfile->params->dir)) {
+ if (file_is_dir(sfile, sfile->params->dir)) {
/* if directory exists, enter it immediately */
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
/* don't do for now because it selects entire text instead of
* placing cursor at the end */
@@ -1931,20 +1937,26 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
#endif
else {
const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
+ char tdir[FILE_MAX_LIBEXTRA];
- /* if not, ask to create it and enter if confirmed */
- wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
- PointerRNA ptr;
- WM_operator_properties_create_ptr(&ptr, ot);
- RNA_string_set(&ptr, "directory", sfile->params->dir);
- RNA_boolean_set(&ptr, "open", true);
-
- if (lastdir)
+ /* If we are 'inside' a blend library, we cannot do anything... */
+ if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) {
BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
-
-
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
- WM_operator_properties_free(&ptr);
+ }
+ else {
+ /* if not, ask to create it and enter if confirmed */
+ wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
+ PointerRNA ptr;
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_string_set(&ptr, "directory", sfile->params->dir);
+ RNA_boolean_set(&ptr, "open", true);
+
+ if (lastdir)
+ BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
+ WM_operator_properties_free(&ptr);
+ }
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1971,8 +1983,6 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
BLI_filename_make_safe(sfile->params->file);
if (matches) {
- /* int i, numfiles = filelist_numfiles(sfile->files); */ /* XXX UNUSED */
- sfile->params->file[0] = '\0';
/* replace the pattern (or filename that the user typed in, with the first selected file of the match */
BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file));
@@ -1980,30 +1990,17 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
}
if (matches == 1) {
-
BLI_join_dirfile(filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file);
/* if directory, open it and empty filename field */
- if (BLI_is_dir(filepath)) {
+ if (file_is_dir(sfile, filepath)) {
BLI_cleanup_dir(G.main->name, filepath);
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
sfile->params->file[0] = '\0';
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
UI_textbutton_activate_but(C, but);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
- else if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX];
- BLI_add_slash(filepath);
- if (BLO_library_path_explode(filepath, tdir, NULL, NULL)) {
- BLI_cleanup_dir(G.main->name, filepath);
- BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
- sfile->params->file[0] = '\0';
- ED_file_change_dir(C, false);
- UI_textbutton_activate_but(C, but);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
- }
- }
}
else if (matches > 1) {
file_draw_check(C);
diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c
index 3c007f25da3..f19e301064d 100644
--- a/source/blender/editors/space_file/file_utils.c
+++ b/source/blender/editors/space_file/file_utils.c
@@ -25,6 +25,9 @@
*/
#include "BLI_rect.h"
+#include "BLI_fileops.h"
+
+#include "BLO_readfile.h"
#include "BKE_context.h"
@@ -45,3 +48,17 @@ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, r
BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x,
ymax - layout->tile_h - layout->tile_border_y, ymax);
}
+
+/* Cannot directly use BLI_is_dir in libloading context... */
+bool file_is_dir(struct SpaceFile *sfile, const char *path)
+{
+ if (sfile->params->type == FILE_LOADLIB) {
+ char tdir[FILE_MAX_LIBEXTRA];
+ char *name;
+ if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, &name) && BLI_is_file(tdir)) {
+ /* .blend file itself and group are considered as directories, not final datablock names. */
+ return name ? false : true;
+ }
+ }
+ return BLI_is_dir(path);
+}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index fc3341bfb92..5e9eb1f9207 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -624,7 +624,7 @@ static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root)
static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
{
bool is_filtered;
- char path[FILE_MAX_LIBEXTRA], dir[FILE_MAXDIR], *group, *name;
+ char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
BLI_join_dirfile(path, sizeof(path), root, file->relpath);
@@ -697,7 +697,7 @@ void filelist_filter(FileList *filelist)
if (filelist->max_recursion) {
/* Never show lib ID 'categories' directories when we are in 'flat' mode, unless
* root path is a blend file. */
- char dir[FILE_MAXDIR];
+ char dir[FILE_MAX_LIBEXTRA];
if (!filelist_islibrary(filelist, dir, NULL)) {
filelist->filter_data.flags |= FLF_HIDE_LIB_DIR;
}
@@ -947,7 +947,7 @@ static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir
static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir)
{
- char dir[FILE_MAXDIR];
+ char dir[FILE_MAX_LIBEXTRA];
if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) {
/* if not a valid library, we need it to be a valid directory! */
BLI_make_exist(r_dir);
@@ -2113,6 +2113,7 @@ unsigned int filelist_entry_select_index_get(FileList *filelist, const int index
return 0;
}
+/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
bool filelist_islibrary(struct FileList *filelist, char *dir, char **group)
{
return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL);
@@ -2208,7 +2209,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const
FileListInternEntry *entry;
LinkNode *ln, *names;
int i, nnames, idcode = 0, nbr_entries = 0;
- char dir[FILE_MAX], *group;
+ char dir[FILE_MAX_LIBEXTRA], *group;
bool ok;
struct BlendHandle *libfiledata = NULL;
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 2a3f964f477..2d28108f544 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -576,7 +576,7 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *ar)
return sfile->layout;
}
-void ED_file_change_dir(bContext *C, const bool checkdir)
+void ED_file_change_dir(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -590,7 +590,7 @@ void ED_file_change_dir(bContext *C, const bool checkdir)
sfile->params->filter_search[0] = '\0';
sfile->params->active_file = -1;
- if (checkdir && !BLI_is_dir(sfile->params->dir)) {
+ if (!file_is_dir(sfile, sfile->params->dir)) {
BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir));
/* could return but just refresh the current dir */
}
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 6b860990c10..478dbd3d9c0 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -555,19 +555,20 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
RNA_boolean_set(kmi->ptr, "include_handles", false);
-
+
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "axis_range", false);
RNA_boolean_set(kmi->ptr, "include_handles", true);
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
RNA_boolean_set(kmi->ptr, "include_handles", true);
-
+
+ /* region select */
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "deselect", false);
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "deselect", true);
-
+
WM_keymap_add_item(keymap, "GRAPH_OT_select_circle", CKEY, KM_PRESS, 0, 0);
/* column select */
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index eb786d872ec..67b960bfa53 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -210,6 +210,8 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot)
* -> ALT-BKEY - depending on which axis of the region was larger...
* -> 2) x-axis, so select all frames within frame range (validation with BEZT_OK_FRAMERANGE)
* -> 3) y-axis, so select all frames within channels that region included (validation with BEZT_OK_VALUERANGE)
+ *
+ * The selection backend is also reused for the Lasso and Circle select operators.
*/
/* Borderselect only selects keyframes now, as overshooting handles often get caught too,
@@ -245,12 +247,12 @@ static void borderselect_graphkeys(
/* init editing data */
memset(&ked, 0, sizeof(KeyframeEditData));
if (mode == BEZT_OK_REGION_LASSO) {
- struct KeyframeEdit_LassoData *data_lasso = data;
+ KeyframeEdit_LassoData *data_lasso = data;
data_lasso->rectf_scaled = &scaled_rectf;
ked.data = data_lasso;
}
else if (mode == BEZT_OK_REGION_CIRCLE) {
- struct KeyframeEdit_CircleData *data_circle = data;
+ KeyframeEdit_CircleData *data_circle = data;
data_circle->rectf_scaled = &scaled_rectf;
ked.data = data;
}
@@ -265,27 +267,27 @@ static void borderselect_graphkeys(
}
else
mapping_flag = ANIM_UNITCONV_ONLYKEYS;
-
+
mapping_flag |= ANIM_get_normalization_flags(ac);
-
+
/* loop over data, doing border select */
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
float offset;
float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
-
+
/* apply NLA mapping to all the keyframes, since it's easier than trying to
* guess when a callback might use something different
*/
if (adt)
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, incl_handles == 0);
-
+
scaled_rectf.xmin = rectf.xmin;
scaled_rectf.xmax = rectf.xmax;
scaled_rectf.ymin = rectf.ymin / unit_scale - offset;
scaled_rectf.ymax = rectf.ymax / unit_scale - offset;
-
+
/* set horizontal range (if applicable)
* NOTE: these values are only used for x-range and y-range but not region
* (which uses ked.data, i.e. rectf)
@@ -406,37 +408,41 @@ void GRAPH_OT_select_border(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "include_handles", 0, "Include Handles", "Are handles tested individually against the selection criteria");
}
+
+/* ------------------- */
+
static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+
+ KeyframeEdit_LassoData data_lasso = {0};
rcti rect;
rctf rect_fl;
+
short selectmode;
bool incl_handles;
bool extend;
-
- struct KeyframeEdit_LassoData data_lasso;
-
+
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
-
+
data_lasso.rectf_view = &rect_fl;
data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
if (data_lasso.mcords == NULL)
return OPERATOR_CANCELLED;
-
+
/* clear all selection if not extending selection */
extend = RNA_boolean_get(op->ptr, "extend");
if (!extend)
deselect_graph_keys(&ac, 1, SELECT_SUBTRACT, true);
-
+
if (!RNA_boolean_get(op->ptr, "deselect"))
selectmode = SELECT_ADD;
else
selectmode = SELECT_SUBTRACT;
-
- if (ac.spacetype == SPACE_IPO) {
+
+ {
SpaceIpo *sipo = (SpaceIpo *)ac.sl;
if (selectmode == SELECT_ADD) {
incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) ||
@@ -446,60 +452,57 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
}
}
- else {
- incl_handles = false;
- }
-
-
+
/* get settings from operator */
BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
-
BLI_rctf_rcti_copy(&rect_fl, &rect);
-
+
/* apply borderselect action */
borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
-
+
MEM_freeN((void *)data_lasso.mcords);
-
-
+
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+
return OPERATOR_FINISHED;
}
-
void GRAPH_OT_select_lasso(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Lasso Select";
ot->description = "Select keyframe points using lasso selection";
ot->idname = "GRAPH_OT_select_lasso";
-
+
/* api callbacks */
ot->invoke = WM_gesture_lasso_invoke;
ot->modal = WM_gesture_lasso_modal;
ot->exec = graphkeys_lassoselect_exec;
ot->poll = graphop_visible_keyframes_poll;
ot->cancel = WM_gesture_lasso_cancel;
-
+
/* flags */
ot->flag = OPTYPE_UNDO;
-
+
/* properties */
RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
}
+/* ------------------- */
+
static int graph_circle_select_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
- short selectmode;
- bool incl_handles;
+ const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT;
+ bool incl_handles = false;
+
+ KeyframeEdit_CircleData data = {0};
rctf rect_fl;
- struct KeyframeEdit_CircleData data;
+
float x = RNA_int_get(op->ptr, "x");
float y = RNA_int_get(op->ptr, "y");
float radius = RNA_int_get(op->ptr, "radius");
@@ -507,23 +510,18 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op)
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
-
+
data.mval[0] = x;
data.mval[1] = y;
data.radius_squared = radius * radius;
data.rectf_view = &rect_fl;
- if (gesture_mode == GESTURE_MODAL_SELECT)
- selectmode = SELECT_ADD;
- else
- selectmode = SELECT_SUBTRACT;
-
rect_fl.xmin = x - radius;
rect_fl.xmax = x + radius;
rect_fl.ymin = y - radius;
rect_fl.ymax = y + radius;
- if (ac.spacetype == SPACE_IPO) {
+ {
SpaceIpo *sipo = (SpaceIpo *)ac.sl;
if (selectmode == SELECT_ADD) {
incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) ||
@@ -533,10 +531,7 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op)
incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
}
}
- else {
- incl_handles = false;
- }
-
+
/* apply borderselect action */
borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data);
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index a7284694f64..8ae5932f3fd 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -611,6 +611,51 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
}
break;
}
+ case FCURVE_COLOR_AUTO_YRGB:
+ {
+ /* Like FCURVE_COLOR_AUTO_RGB, except this is for quaternions... */
+ float *col = fcu->color;
+
+ switch (fcu->array_index) {
+ case 1:
+ UI_GetThemeColor3fv(TH_AXIS_X, col);
+ break;
+ case 2:
+ UI_GetThemeColor3fv(TH_AXIS_Y, col);
+ break;
+ case 3:
+ UI_GetThemeColor3fv(TH_AXIS_Z, col);
+ break;
+
+ case 0:
+ {
+ /* Special Case: "W" channel should be yellowish, so blend X and Y channel colors... */
+ float c1[3], c2[3];
+ float h1[3], h2[3];
+ float hresult[3];
+
+ /* - get colors (rgb) */
+ UI_GetThemeColor3fv(TH_AXIS_X, c1);
+ UI_GetThemeColor3fv(TH_AXIS_Y, c2);
+
+ /* - perform blending in HSV space (to keep brightness similar) */
+ rgb_to_hsv_v(c1, h1);
+ rgb_to_hsv_v(c2, h2);
+
+ interp_v3_v3v3(hresult, h1, h2, 0.5f);
+
+ /* - convert back to RGB for display */
+ hsv_to_rgb_v(hresult, col);
+ break;
+ }
+
+ default:
+ /* 'unknown' color - bluish so as to not conflict with handles */
+ col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f;
+ break;
+ }
+ break;
+ }
case FCURVE_COLOR_AUTO_RAINBOW:
default:
{
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 687869ae727..57d9ff7825b 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -399,13 +399,22 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op)
ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id"));
/* check for invalid states */
- if (soops == NULL)
+ if (soops == NULL) {
return OPERATOR_CANCELLED;
+ }
if (!(old_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) {
+ BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Invalid old/new ID pair ('%s' / '%s')",
+ old_id->name, new_id->name);
return OPERATOR_CANCELLED;
}
+ if (old_id->lib) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Old ID '%s' is linked from a library, indirect usages of this datablock will not be remapped",
+ old_id->name);
+ }
+
BKE_libblock_remap(bmain, old_id, new_id,
ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index d404e7aaf15..94ed280f792 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -384,8 +384,7 @@ static int text_unlink_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- BKE_text_unlink(bmain, text);
- BKE_libblock_free(bmain, text);
+ BKE_libblock_delete(bmain, text);
text_drawcache_tag_update(st, 1);
WM_event_add_notifier(C, NC_TEXT | NA_REMOVED, NULL);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index c32de6eafc3..3b1ce5f8ab0 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -7032,7 +7032,7 @@ static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const floa
MVert *mv = &data->mvert[index];
if (!(mv->flag & ME_HIDE)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
glVertex3fv(co);
}
}
@@ -7057,7 +7057,7 @@ static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3]
BMVert *eve = BM_vert_at_index(data->bm, index);
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
glVertex3fv(co);
}
}
@@ -7076,7 +7076,7 @@ static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index)
BMEdge *eed = BM_edge_at_index(data->bm, index);
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -7090,7 +7090,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset)
}
/**
- * dont set #WM_framebuffer_index_set. just use to mask other
+ * dont set #GPU_framebuffer_index_set. just use to mask other
*/
static DMDrawOption bbs_mesh_mask__setSolidDrawOptions(void *userData, int index)
{
@@ -7109,7 +7109,7 @@ static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int inde
BMFace *efa = BM_face_at_index(userData, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -7122,7 +7122,7 @@ static void bbs_mesh_solid__drawCenter(void *userData, int index, const float ce
BMFace *efa = BM_face_at_index(userData, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
glVertex3fv(cent);
}
@@ -7153,7 +7153,7 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d,
static DMDrawOption bbs_mesh_solid__setDrawOpts(void *UNUSED(userData), int index)
{
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
@@ -7162,7 +7162,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index)
Mesh *me = userData;
if (!(me->mpoly[index].flag & ME_HIDE)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -7170,7 +7170,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index)
}
}
-/* must have called WM_framebuffer_index_set beforehand */
+/* must have called GPU_framebuffer_index_set beforehand */
static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index)
{
Mesh *me = userData;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 64b12498ae2..dcab05c80d6 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1483,7 +1483,7 @@ unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y)
BLI_endian_switch_uint32(&col);
}
- return WM_framebuffer_to_index(col);
+ return GPU_select_to_index(col);
}
/* reads full rect, converts indices */
@@ -1516,7 +1516,7 @@ ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int
IMB_convert_rgba_to_abgr(ibuf_clip);
}
- WM_framebuffer_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
+ GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
if ((clip.xmin == xmin) &&
(clip.xmax == xmax) &&
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index fd7179d06dd..148db20b41d 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -93,6 +93,8 @@
#include "UI_interface.h"
+#include "GPU_draw.h"
+
#include "view3d_intern.h" /* own include */
float ED_view3d_select_dist_px(void)
@@ -1687,7 +1689,7 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo
if (ENDIAN_ORDER == B_ENDIAN) {
IMB_convert_rgba_to_abgr(ibuf);
}
- WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]);
+ GPU_select_to_index_array(ibuf->rect, size[0] * size[1]);
a = size[0] * size[1];
while (a--) {
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 943490bbc3a..c94b0d53468 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1202,8 +1202,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
if (t->flag & T_PROP_EDIT) {
float fac = 1.0f + 0.005f *(event->y - event->prevy);
t->prop_size *= fac;
- if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
- t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+ if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
+ t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->far), T_PROP_SIZE_MIN);
+ }
+ else {
+ t->prop_size = max_ff(min_ff(t->prop_size, T_PROP_SIZE_MAX), T_PROP_SIZE_MIN);
+ }
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1212,8 +1216,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_PROPSIZE_UP:
if (t->flag & T_PROP_EDIT) {
t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
- if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
+ if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+ }
+ else {
+ t->prop_size = min_ff(t->prop_size, T_PROP_SIZE_MAX);
+ }
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1222,6 +1230,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_PROPSIZE_DOWN:
if (t->flag & T_PROP_EDIT) {
t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
+ t->prop_size = max_ff(t->prop_size, T_PROP_SIZE_MIN);
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 4e8aa0cc20b..da448faa16b 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -592,6 +592,10 @@ typedef struct TransInfo {
#define POINT_INIT 4
#define MULTI_POINTS 8
+/* Hard min/max for proportional size. */
+#define T_PROP_SIZE_MIN 1e-6f
+#define T_PROP_SIZE_MAX 1e12f
+
bool initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, const struct wmEvent *event, int mode);
void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op);
int transformEvent(TransInfo *t, const struct wmEvent *event);
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 2fb92d73515..6e399d9fde3 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -528,7 +528,8 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
prop = RNA_def_enum(ot->srna, "proportional_edit_falloff", rna_enum_proportional_falloff_items, 0,
"Proportional Editing Falloff", "Falloff type for proportional editing mode");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
- RNA_def_float(ot->srna, "proportional_size", 1, 0.00001f, FLT_MAX, "Proportional Size", "", 0.001, 100);
+ RNA_def_float(ot->srna, "proportional_size", 1, T_PROP_SIZE_MIN, T_PROP_SIZE_MAX,
+ "Proportional Size", "", 0.001f, 100.0f);
}
if (flags & P_SNAP) {
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index d706c574d1f..1db4ee0e2e5 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -1627,7 +1627,7 @@ static bool transform_snap_context_project_view3d_mixed_impl(
* Given a 2D region value, snap to vert/edge/face.
*
* \param sctx: Snap context.
- * \param mval: Screenspace coordinate.
+ * \param mval_fl: Screenspace coordinate.
* \param dist_px: Maximum distance to snap (in pixels).
* \param use_depth: Snap to the closest element, use when using more than one snap type.
* \param r_co: hit location.
diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h
index 5403ec6b13b..0e08af1bac8 100644
--- a/source/blender/freestyle/intern/system/PythonInterpreter.h
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.h
@@ -84,8 +84,7 @@ public:
Text *text = BKE_text_load(&_freestyle_bmain, fn, G.main->name);
if (text) {
ok = BPY_execute_text(_context, text, reports, false);
- BKE_text_unlink(&_freestyle_bmain, text);
- BKE_libblock_free(&_freestyle_bmain, text);
+ BKE_libblock_delete(&_freestyle_bmain, text);
}
else {
BKE_reportf(reports, RPT_ERROR, "Cannot open file: %s", fn);
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index bc732387c85..90b65af87c8 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -160,6 +160,12 @@ struct DerivedMesh;
void GPU_draw_update_fvar_offset(struct DerivedMesh *dm);
#endif
+/* utilities */
+void GPU_select_index_set(int index);
+void GPU_select_index_get(int index, int *r_col);
+int GPU_select_to_index(unsigned int col);
+void GPU_select_to_index_array(unsigned int *col, const unsigned int size);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 52177b756c5..3ea64e1f6d5 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -2327,3 +2327,152 @@ void GPU_draw_update_fvar_offset(DerivedMesh *dm)
}
}
#endif
+
+
+/** \name Framebuffer color depth, for selection codes
+ * \{ */
+
+#ifdef __APPLE__
+
+/* apple seems to round colors to below and up on some configs */
+
+static unsigned int index_to_framebuffer(int index)
+{
+ unsigned int i = index;
+
+ switch (GPU_color_depth()) {
+ case 12:
+ i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
+ /* sometimes dithering subtracts! */
+ i |= 0x070707;
+ break;
+ case 15:
+ case 16:
+ i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
+ i |= 0x030303;
+ break;
+ case 24:
+ break;
+ default: /* 18 bits... */
+ i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
+ i |= 0x010101;
+ break;
+ }
+
+ return i;
+}
+
+#else
+
+/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */
+
+static unsigned int index_to_framebuffer(int index)
+{
+ unsigned int i = index;
+
+ switch (GPU_color_depth()) {
+ case 8:
+ i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6);
+ i |= 0x3F3F3F;
+ break;
+ case 12:
+ i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
+ /* sometimes dithering subtracts! */
+ i |= 0x0F0F0F;
+ break;
+ case 15:
+ case 16:
+ i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
+ i |= 0x070707;
+ break;
+ case 24:
+ break;
+ default: /* 18 bits... */
+ i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
+ i |= 0x030303;
+ break;
+ }
+
+ return i;
+}
+
+#endif
+
+
+void GPU_select_index_set(int index)
+{
+ const int col = index_to_framebuffer(index);
+ glColor3ub(( (col) & 0xFF),
+ (((col) >> 8) & 0xFF),
+ (((col) >> 16) & 0xFF));
+}
+
+void GPU_select_index_get(int index, int *r_col)
+{
+ const int col = index_to_framebuffer(index);
+ char *c_col = (char *)r_col;
+ c_col[0] = (col & 0xFF); /* red */
+ c_col[1] = ((col >> 8) & 0xFF); /* green */
+ c_col[2] = ((col >> 16) & 0xFF); /* blue */
+ c_col[3] = 0xFF; /* alpha */
+}
+
+
+#define INDEX_FROM_BUF_8(col) ((((col) & 0xC00000) >> 18) + (((col) & 0xC000) >> 12) + (((col) & 0xC0) >> 6))
+#define INDEX_FROM_BUF_12(col) ((((col) & 0xF00000) >> 12) + (((col) & 0xF000) >> 8) + (((col) & 0xF0) >> 4))
+#define INDEX_FROM_BUF_15_16(col) ((((col) & 0xF80000) >> 9) + (((col) & 0xF800) >> 6) + (((col) & 0xF8) >> 3))
+#define INDEX_FROM_BUF_18(col) ((((col) & 0xFC0000) >> 6) + (((col) & 0xFC00) >> 4) + (((col) & 0xFC) >> 2))
+#define INDEX_FROM_BUF_24(col) ((col) & 0xFFFFFF)
+
+int GPU_select_to_index(unsigned int col)
+{
+ if (col == 0) {
+ return 0;
+ }
+
+ switch (GPU_color_depth()) {
+ case 8: return INDEX_FROM_BUF_8(col);
+ case 12: return INDEX_FROM_BUF_12(col);
+ case 15:
+ case 16: return INDEX_FROM_BUF_15_16(col);
+ case 24: return INDEX_FROM_BUF_24(col);
+ default: return INDEX_FROM_BUF_18(col);
+ }
+}
+
+void GPU_select_to_index_array(unsigned int *col, const unsigned int size)
+{
+#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \
+ for (i = size; i--; col++) { \
+ if ((c = *col)) { \
+ *col = INDEX_FROM_BUF_BITS(c); \
+ } \
+ } ((void)0)
+
+ if (size > 0) {
+ unsigned int i, c;
+
+ switch (GPU_color_depth()) {
+ case 8:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_8);
+ break;
+ case 12:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_12);
+ break;
+ case 15:
+ case 16:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16);
+ break;
+ case 24:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_24);
+ break;
+ default:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_18);
+ break;
+ }
+ }
+
+#undef INDEX_BUF_ARRAY
+}
+
+/** \} */
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
index 9a6537b4f09..db0068d2f3d 100644
--- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
@@ -14,6 +14,9 @@ varying vec3 varnormal;
varying float gl_ClipDistance[6];
#endif
+
+/* Color, keep in sync with: gpu_shader_vertex_world.glsl */
+
float srgb_to_linearrgb(float c)
{
if (c < 0.04045)
@@ -76,6 +79,9 @@ void set_var_from_attr(vec4 attr, int info, out vec4 var)
}
}
+/* end color code */
+
+
void main()
{
#ifndef USE_OPENSUBDIV
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
index 9dbcaeb7a32..d45a4b316a8 100644
--- a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
@@ -2,6 +2,74 @@
varying vec3 varposition;
varying vec3 varnormal;
+
+/* Color, keep in sync with: gpu_shader_vertex.glsl */
+
+float srgb_to_linearrgb(float c)
+{
+ if (c < 0.04045)
+ return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
+ else
+ return pow((c + 0.055) * (1.0 / 1.055), 2.4);
+}
+
+void srgb_to_linearrgb(vec3 col_from, out vec3 col_to)
+{
+ col_to.r = srgb_to_linearrgb(col_from.r);
+ col_to.g = srgb_to_linearrgb(col_from.g);
+ col_to.b = srgb_to_linearrgb(col_from.b);
+}
+
+void srgb_to_linearrgb(vec4 col_from, out vec4 col_to)
+{
+ col_to.r = srgb_to_linearrgb(col_from.r);
+ col_to.g = srgb_to_linearrgb(col_from.g);
+ col_to.b = srgb_to_linearrgb(col_from.b);
+ col_to.a = col_from.a;
+}
+
+bool is_srgb(int info)
+{
+#ifdef USE_NEW_SHADING
+ return (info == 1)? true: false;
+#else
+ return false;
+#endif
+}
+
+void set_var_from_attr(float attr, int info, out float var)
+{
+ var = attr;
+}
+
+void set_var_from_attr(vec2 attr, int info, out vec2 var)
+{
+ var = attr;
+}
+
+void set_var_from_attr(vec3 attr, int info, out vec3 var)
+{
+ if (is_srgb(info)) {
+ srgb_to_linearrgb(attr, var);
+ }
+ else {
+ var = attr;
+ }
+}
+
+void set_var_from_attr(vec4 attr, int info, out vec4 var)
+{
+ if (is_srgb(info)) {
+ srgb_to_linearrgb(attr, var);
+ }
+ else {
+ var = attr;
+ }
+}
+
+/* end color code */
+
+
void main()
{
/* position does not need to be transformed, we already have it */
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 95d061bcb75..3629332a4ac 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -46,6 +46,8 @@
#include "BLO_readfile.h"
+#include "DNA_space_types.h" /* For FILE_MAX_LIBEXTRA */
+
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_thumbs.h"
@@ -533,7 +535,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source
char thumb_path[FILE_MAX];
char thumb_name[40];
char uri[URI_MAX];
- char path_buff[FILE_MAX];
+ char path_buff[FILE_MAX_LIBEXTRA];
const char *file_path;
const char *path;
BLI_stat_t st;
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 4c1283452ff..6bd7b3a4999 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -537,8 +537,9 @@ typedef enum eFCurve_Extend {
/* curve coloring modes */
typedef enum eFCurve_Coloring {
FCURVE_COLOR_AUTO_RAINBOW = 0, /* automatically determine color using rainbow (calculated at drawtime) */
- FCURVE_COLOR_AUTO_RGB, /* automatically determine color using XYZ (array index) <-> RGB */
- FCURVE_COLOR_CUSTOM /* custom color */
+ FCURVE_COLOR_AUTO_RGB = 1, /* automatically determine color using XYZ (array index) <-> RGB */
+ FCURVE_COLOR_AUTO_YRGB = 3, /* automatically determine color where XYZ <-> RGB, but index(X) != 0 */
+ FCURVE_COLOR_CUSTOM = 2, /* custom color */
} eFCurve_Coloring;
/* ************************************************ */
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 6cba3322135..46b30f41f5b 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -912,7 +912,8 @@ typedef struct NodeSunBeams {
#define SHD_GLOSSY_BECKMANN 0
#define SHD_GLOSSY_SHARP 1
#define SHD_GLOSSY_GGX 2
-#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3
+#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3
+#define SHD_GLOSSY_MULTI_GGX 4
/* vector transform */
#define SHD_VECT_TRANSFORM_TYPE_VECTOR 0
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 19545336f46..6851f380cd8 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -324,11 +324,6 @@ static void rna_ID_user_clear(ID *id)
id->us = 0; /* don't save */
}
-static void rna_ID_delete(ID *id, Main *bmain)
-{
- BKE_libblock_delete(bmain, id);
-}
-
static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id)
{
if (GS(id->name) == GS(new_id->name)) {
@@ -977,10 +972,6 @@ static void rna_def_ID(BlenderRNA *brna)
parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "destroy", "rna_ID_delete");
- RNA_def_function_flag(func, FUNC_USE_MAIN);
- RNA_def_function_ui_description(func, "Delete this ID from Blender (WARNING: no undo, do not use it after calling this!)");
-
func = RNA_def_function(srna, "user_clear", "rna_ID_user_clear");
RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, "
"on reload the data will be removed");
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index 678b0ac8f1f..492430fbda6 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -257,13 +257,15 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipsta");
- RNA_def_property_range(prop, 0.001f, FLT_MAX);
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Clip Start", "Camera near clipping distance");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipend");
- RNA_def_property_range(prop, 1.0f, FLT_MAX);
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Clip End", "Camera far clipping distance");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 1487dfa074e..3043c5452c0 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -1844,6 +1844,8 @@ static void rna_def_fcurve(BlenderRNA *brna)
"Cycle through the rainbow, trying to give each curve a unique color"},
{FCURVE_COLOR_AUTO_RGB, "AUTO_RGB", 0, "Auto XYZ to RGB",
"Use axis colors for transform and color properties, and auto-rainbow for the rest"},
+ {FCURVE_COLOR_AUTO_YRGB, "AUTO_YRGB", 0, "Auto WXYZ to YRGB",
+ "Use axis colors for XYZ parts of transform, and yellow for the 'W' channel"},
{FCURVE_COLOR_CUSTOM, "CUSTOM", 0, "User Defined",
"Use custom hand-picked color for F-Curve"},
{0, NULL, 0, NULL, NULL}
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index cd379603901..c30414ab585 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -62,6 +62,7 @@
#include "BKE_object.h"
#include "BKE_material.h"
#include "BKE_icons.h"
+#include "BKE_idcode.h"
#include "BKE_image.h"
#include "BKE_texture.h"
#include "BKE_scene.h"
@@ -112,30 +113,38 @@
# include "BPY_extern.h"
#endif
+
+static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, int do_unlink)
+{
+ ID *id = id_ptr->data;
+ if (do_unlink) {
+ BKE_libblock_delete(bmain, id);
+ RNA_POINTER_INVALIDATE(id_ptr);
+ }
+ else if (ID_REAL_USERS(id) <= 0) {
+ BKE_libblock_free(bmain, id);
+ RNA_POINTER_INVALIDATE(id_ptr);
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR,
+ "%s '%s' must have zero users to be removed, found %d (try with unlink=True parameter)",
+ BKE_idcode_to_name(GS(id->name)), id->name + 2, ID_REAL_USERS(id));
+ }
+}
+
+
static Camera *rna_Main_cameras_new(Main *bmain, const char *name)
{
ID *id = BKE_camera_add(bmain, name);
id_us_min(id);
return (Camera *)id;
}
-static void rna_Main_cameras_remove(Main *bmain, ReportList *reports, PointerRNA *camera_ptr)
-{
- Camera *camera = camera_ptr->data;
- if (ID_REAL_USERS(camera) <= 0) {
- BKE_libblock_free(bmain, camera);
- RNA_POINTER_INVALIDATE(camera_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Camera '%s' must have zero users to be removed, found %d",
- camera->id.name + 2, ID_REAL_USERS(camera));
- }
-}
static Scene *rna_Main_scenes_new(Main *bmain, const char *name)
{
return BKE_scene_add(bmain, name);
}
-static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr)
+static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr, int do_unlink)
{
/* don't call BKE_libblock_free(...) directly */
Scene *scene = scene_ptr->data;
@@ -144,24 +153,23 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports
if ((scene_new = scene->id.prev) ||
(scene_new = scene->id.next))
{
- bScreen *sc = CTX_wm_screen(C);
- if (sc->scene == scene) {
+ if (do_unlink) {
+ bScreen *sc = CTX_wm_screen(C);
+ if (sc->scene == scene) {
#ifdef WITH_PYTHON
- BPy_BEGIN_ALLOW_THREADS;
+ BPy_BEGIN_ALLOW_THREADS;
#endif
- ED_screen_set_scene(C, sc, scene_new);
+ ED_screen_set_scene(C, sc, scene_new);
#ifdef WITH_PYTHON
- BPy_END_ALLOW_THREADS;
+ BPy_END_ALLOW_THREADS;
#endif
+ }
}
-
- BKE_libblock_remap(bmain, scene, scene_new, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
- BKE_libblock_free(bmain, scene);
- RNA_POINTER_INVALIDATE(scene_ptr);
+ rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink);
}
else {
BKE_reportf(reports, RPT_ERROR, "Scene '%s' is the last, cannot be removed", scene->id.name + 2);
@@ -222,38 +230,12 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
return ob;
}
-static void rna_Main_objects_remove(Main *bmain, ReportList *reports, PointerRNA *object_ptr)
-{
- Object *object = object_ptr->data;
- if (ID_REAL_USERS(object) <= 0) {
- BKE_libblock_unlink(bmain, object, false);
- BKE_libblock_free(bmain, object);
- RNA_POINTER_INVALIDATE(object_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Object '%s' must have zero users to be removed, found %d",
- object->id.name + 2, ID_REAL_USERS(object));
- }
-}
-
static Material *rna_Main_materials_new(Main *bmain, const char *name)
{
ID *id = (ID *)BKE_material_add(bmain, name);
id_us_min(id);
return (Material *)id;
}
-static void rna_Main_materials_remove(Main *bmain, ReportList *reports, PointerRNA *material_ptr)
-{
- Material *material = material_ptr->data;
- if (ID_REAL_USERS(material) <= 0) {
- BKE_libblock_free(bmain, material);
- RNA_POINTER_INVALIDATE(material_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Material '%s' must have zero users to be removed, found %d",
- material->id.name + 2, ID_REAL_USERS(material));
- }
-}
static EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -271,18 +253,6 @@ static struct bNodeTree *rna_Main_nodetree_new(Main *bmain, const char *name, in
else
return NULL;
}
-static void rna_Main_nodetree_remove(Main *bmain, ReportList *reports, PointerRNA *ntree_ptr)
-{
- bNodeTree *ntree = ntree_ptr->data;
- if (ID_REAL_USERS(ntree) <= 0) {
- BKE_libblock_free(bmain, ntree);
- RNA_POINTER_INVALIDATE(ntree_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Node tree '%s' must have zero users to be removed, found %d",
- ntree->id.name + 2, ID_REAL_USERS(ntree));
- }
-}
static Mesh *rna_Main_meshes_new(Main *bmain, const char *name)
{
@@ -312,19 +282,6 @@ Mesh *rna_Main_meshes_new_from_object(
return BKE_mesh_new_from_object(bmain, sce, ob, apply_modifiers, settings, calc_tessface, calc_undeformed);
}
-static void rna_Main_meshes_remove(Main *bmain, ReportList *reports, PointerRNA *mesh_ptr)
-{
- Mesh *mesh = mesh_ptr->data;
- if (ID_REAL_USERS(mesh) <= 0) {
- BKE_libblock_free(bmain, mesh);
- RNA_POINTER_INVALIDATE(mesh_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Mesh '%s' must have zero users to be removed, found %d",
- mesh->id.name + 2, ID_REAL_USERS(mesh));
- }
-}
-
static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type)
{
Lamp *lamp = BKE_lamp_add(bmain, name);
@@ -332,18 +289,6 @@ static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type)
id_us_min(&lamp->id);
return lamp;
}
-static void rna_Main_lamps_remove(Main *bmain, ReportList *reports, PointerRNA *lamp_ptr)
-{
- Lamp *lamp = lamp_ptr->data;
- if (ID_REAL_USERS(lamp) <= 0) {
- BKE_libblock_free(bmain, lamp);
- RNA_POINTER_INVALIDATE(lamp_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Lamp '%s' must have zero users to be removed, found %d",
- lamp->id.name + 2, ID_REAL_USERS(lamp));
- }
-}
static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer, int stereo3d)
{
@@ -372,18 +317,6 @@ static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char
id_us_min((ID *)ima);
return ima;
}
-static void rna_Main_images_remove(Main *bmain, ReportList *reports, PointerRNA *image_ptr)
-{
- Image *image = image_ptr->data;
- if (ID_REAL_USERS(image) <= 0) {
- BKE_libblock_free(bmain, image);
- RNA_POINTER_INVALIDATE(image_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Image '%s' must have zero users to be removed, found %d",
- image->id.name + 2, ID_REAL_USERS(image));
- }
-}
static Lattice *rna_Main_lattices_new(Main *bmain, const char *name)
{
@@ -391,18 +324,6 @@ static Lattice *rna_Main_lattices_new(Main *bmain, const char *name)
id_us_min(&lt->id);
return lt;
}
-static void rna_Main_lattices_remove(Main *bmain, ReportList *reports, PointerRNA *lt_ptr)
-{
- Lattice *lt = lt_ptr->data;
- if (ID_REAL_USERS(lt) <= 0) {
- BKE_libblock_free(bmain, lt);
- RNA_POINTER_INVALIDATE(lt_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Lattice '%s' must have zero users to be removed, found %d",
- lt->id.name + 2, ID_REAL_USERS(lt));
- }
-}
static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type)
{
@@ -410,18 +331,6 @@ static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type)
id_us_min(&cu->id);
return cu;
}
-static void rna_Main_curves_remove(Main *bmain, ReportList *reports, PointerRNA *cu_ptr)
-{
- Curve *cu = cu_ptr->data;
- if (ID_REAL_USERS(cu) <= 0) {
- BKE_libblock_free(bmain, cu);
- RNA_POINTER_INVALIDATE(cu_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Curve '%s' must have zero users to be removed, found %d",
- cu->id.name + 2, ID_REAL_USERS(cu));
- }
-}
static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name)
{
@@ -429,18 +338,6 @@ static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name)
id_us_min(&mb->id);
return mb;
}
-static void rna_Main_metaballs_remove(Main *bmain, ReportList *reports, PointerRNA *mb_ptr)
-{
- MetaBall *mb = mb_ptr->data;
- if (ID_REAL_USERS(mb) <= 0) {
- BKE_libblock_free(bmain, mb);
- RNA_POINTER_INVALIDATE(mb_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Metaball '%s' must have zero users to be removed, found %d",
- mb->id.name + 2, ID_REAL_USERS(mb));
- }
-}
static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing)
{
@@ -462,18 +359,6 @@ static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *
return font;
}
-static void rna_Main_fonts_remove(Main *bmain, ReportList *reports, PointerRNA *vfont_ptr)
-{
- VFont *vfont = vfont_ptr->data;
- if (ID_REAL_USERS(vfont) <= 0) {
- BKE_libblock_free(bmain, vfont);
- RNA_POINTER_INVALIDATE(vfont_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Font '%s' must have zero users to be removed, found %d",
- vfont->id.name + 2, ID_REAL_USERS(vfont));
- }
-}
static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type)
{
@@ -482,18 +367,6 @@ static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type)
id_us_min(&tex->id);
return tex;
}
-static void rna_Main_textures_remove(Main *bmain, ReportList *reports, PointerRNA *tex_ptr)
-{
- Tex *tex = tex_ptr->data;
- if (ID_REAL_USERS(tex) <= 0) {
- BKE_libblock_free(bmain, tex);
- RNA_POINTER_INVALIDATE(tex_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Texture '%s' must have zero users to be removed, found %d",
- tex->id.name + 2, ID_REAL_USERS(tex));
- }
-}
static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode)
{
@@ -502,50 +375,17 @@ static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode)
return brush;
}
-static void rna_Main_brushes_remove(Main *bmain, ReportList *reports, PointerRNA *brush_ptr)
-{
- Brush *brush = brush_ptr->data;
- if (ID_REAL_USERS(brush) <= 0) {
- BKE_brush_unlink(bmain, brush);
- BKE_libblock_free(bmain, brush);
- RNA_POINTER_INVALIDATE(brush_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Brush '%s' must have zero users to be removed, found %d",
- brush->id.name + 2, ID_REAL_USERS(brush));
- }
-}
-
static World *rna_Main_worlds_new(Main *bmain, const char *name)
{
World *world = add_world(bmain, name);
id_us_min(&world->id);
return world;
}
-static void rna_Main_worlds_remove(Main *bmain, ReportList *reports, PointerRNA *world_ptr)
-{
- Group *world = world_ptr->data;
- if (ID_REAL_USERS(world) <= 0) {
- BKE_libblock_free(bmain, world);
- RNA_POINTER_INVALIDATE(world_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "World '%s' must have zero users to be removed, found %d",
- world->id.name + 2, ID_REAL_USERS(world));
- }
-}
static Group *rna_Main_groups_new(Main *bmain, const char *name)
{
return BKE_group_add(bmain, name);
}
-static void rna_Main_groups_remove(Main *bmain, PointerRNA *group_ptr)
-{
- Group *group = group_ptr->data;
- BKE_libblock_unlink(bmain, group, false);
- BKE_libblock_free(bmain, group);
- RNA_POINTER_INVALIDATE(group_ptr);
-}
static Speaker *rna_Main_speakers_new(Main *bmain, const char *name)
{
@@ -553,18 +393,6 @@ static Speaker *rna_Main_speakers_new(Main *bmain, const char *name)
id_us_min(&speaker->id);
return speaker;
}
-static void rna_Main_speakers_remove(Main *bmain, ReportList *reports, PointerRNA *speaker_ptr)
-{
- Speaker *speaker = speaker_ptr->data;
- if (ID_REAL_USERS(speaker) <= 0) {
- BKE_libblock_free(bmain, speaker);
- RNA_POINTER_INVALIDATE(speaker_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Speaker '%s' must have zero users to be removed, found %d",
- speaker->id.name + 2, ID_REAL_USERS(speaker));
- }
-}
static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_existing)
{
@@ -580,30 +408,11 @@ static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_exi
id_us_min(&sound->id);
return sound;
}
-static void rna_Main_sounds_remove(Main *bmain, ReportList *reports, PointerRNA *sound_ptr)
-{
- Speaker *sound = sound_ptr->data;
- if (ID_REAL_USERS(sound) <= 0) {
- BKE_libblock_free(bmain, sound);
- RNA_POINTER_INVALIDATE(sound_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Sound '%s' must have zero users to be removed, found %d",
- sound->id.name + 2, ID_REAL_USERS(sound));
- }
-}
static Text *rna_Main_texts_new(Main *bmain, const char *name)
{
return BKE_text_add(bmain, name);
}
-static void rna_Main_texts_remove(Main *bmain, PointerRNA *text_ptr)
-{
- Text *text = text_ptr->data;
- BKE_text_unlink(bmain, text);
- BKE_libblock_free(bmain, text);
- RNA_POINTER_INVALIDATE(text_ptr);
-}
static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *filepath, int is_internal)
{
@@ -625,37 +434,12 @@ static bArmature *rna_Main_armatures_new(Main *bmain, const char *name)
id_us_min(&arm->id);
return arm;
}
-static void rna_Main_armatures_remove(Main *bmain, ReportList *reports, PointerRNA *arm_ptr)
-{
- bArmature *arm = arm_ptr->data;
- if (ID_REAL_USERS(arm) <= 0) {
- BKE_libblock_free(bmain, arm);
- RNA_POINTER_INVALIDATE(arm_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Armature '%s' must have zero users to be removed, found %d",
- arm->id.name + 2, ID_REAL_USERS(arm));
- }
-}
static bAction *rna_Main_actions_new(Main *bmain, const char *name)
{
bAction *act = add_empty_action(bmain, name);
id_fake_user_clear(&act->id);
return act;
-}
-static void rna_Main_actions_remove(Main *bmain, ReportList *reports, PointerRNA *act_ptr)
-{
- bAction *act = act_ptr->data;
- if (ID_REAL_USERS(act) <= 0) {
- BKE_libblock_free(bmain, act);
- RNA_POINTER_INVALIDATE(act_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Action '%s' must have zero users to be removed, found %d",
- act->id.name + 2, ID_REAL_USERS(act));
- }
-}
static Palette *rna_Main_palettes_new(Main *bmain, const char *name)
{
@@ -663,18 +447,6 @@ static Palette *rna_Main_palettes_new(Main *bmain, const char *name)
id_us_min(&palette->id);
return (Palette *)palette;
}
-static void rna_Main_palettes_remove(Main *bmain, ReportList *reports, PointerRNA *palette_ptr)
-{
- Palette *palette = palette_ptr->data;
- if (ID_REAL_USERS(palette) <= 0) {
- BKE_libblock_free(bmain, palette);
- RNA_POINTER_INVALIDATE(palette_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Palette settings '%s' must have zero users to be removed, found %d",
- palette->id.name + 2, ID_REAL_USERS(palette));
- }
-}
static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing)
{
@@ -697,14 +469,6 @@ static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, cons
return clip;
}
-static void rna_Main_movieclips_remove(Main *bmain, PointerRNA *clip_ptr)
-{
- MovieClip *clip = clip_ptr->data;
- BKE_movieclip_unlink(bmain, clip);
- BKE_libblock_free(bmain, clip);
- RNA_POINTER_INVALIDATE(clip_ptr);
-}
-
static Mask *rna_Main_mask_new(Main *bmain, const char *name)
{
Mask *mask;
@@ -714,26 +478,6 @@ static Mask *rna_Main_mask_new(Main *bmain, const char *name)
return mask;
}
-static void rna_Main_masks_remove(Main *bmain, PointerRNA *mask_ptr)
-{
- Mask *mask = mask_ptr->data;
- BKE_libblock_free(bmain, mask);
- RNA_POINTER_INVALIDATE(mask_ptr);
-}
-
-static void rna_Main_grease_pencil_remove(Main *bmain, ReportList *reports, PointerRNA *gpd_ptr)
-{
- bGPdata *gpd = gpd_ptr->data;
- if (ID_REAL_USERS(gpd) <= 0) {
- BKE_gpencil_free(gpd);
- BKE_libblock_free(bmain, gpd);
- RNA_POINTER_INVALIDATE(gpd_ptr);
- }
- else
- BKE_reportf(reports, RPT_ERROR, "Grease pencil '%s' must have zero users to be removed, found %d",
- gpd->id.name + 2, ID_REAL_USERS(gpd));
-}
-
static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name)
{
FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, name);
@@ -741,17 +485,6 @@ static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name
return linestyle;
}
-static void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, FreestyleLineStyle *linestyle)
-{
- if (ID_REAL_USERS(linestyle) <= 0)
- BKE_libblock_free(bmain, linestyle);
- else
- BKE_reportf(reports, RPT_ERROR, "Line style '%s' must have zero users to be removed, found %d",
- linestyle->id.name + 2, ID_REAL_USERS(linestyle));
-
- /* XXX python now has invalid pointer? */
-}
-
/* tag and is_updated functions, all the same */
#define RNA_MAIN_ID_TAG_FUNCS_DEF(_func_name, _listbase_name, _id_type) \
static void rna_Main_##_func_name##_tag(Main *bmain, int value) { \
@@ -833,12 +566,15 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "camera", "Camera", "", "New camera data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_cameras_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a camera from the current blendfile");
parm = RNA_def_pointer(func, "camera", "Camera", "", "Camera to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this camera before deleting it "
+ "(WARNING: will also delete objects instancing that camera data)");
func = RNA_def_function(srna, "tag", "rna_Main_cameras_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -875,6 +611,7 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this scene before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_scenes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -909,12 +646,13 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "object", "Object", "", "New object data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_objects_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_ui_description(func, "Remove a object from the current blendfile");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this object before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_objects_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -945,12 +683,13 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "material", "Material", "", "New material data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_materials_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a material from the current blendfile");
parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this material before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_materials_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -988,12 +727,13 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "tree", "NodeTree", "", "New node tree data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_nodetree_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a node tree from the current blendfile");
parm = RNA_def_pointer(func, "tree", "NodeTree", "", "Node tree to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this node tree before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1046,12 +786,15 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
"Mesh created from object, remove it if it is only used for export");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_meshes_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a mesh from the current blendfile");
parm = RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this mesh before deleting it "
+ "(WARNING: will also delete objects instancing that mesh data)");
func = RNA_def_function(srna, "tag", "rna_Main_meshes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1083,12 +826,15 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "lamp", "Lamp", "", "New lamp data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_lamps_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a lamp from the current blendfile");
parm = RNA_def_pointer(func, "lamp", "Lamp", "", "Lamp to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this lamp before deleting it "
+ "(WARNING: will also delete objects instancing that lamp data)");
func = RNA_def_function(srna, "tag", "rna_Main_lamps_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1198,12 +944,13 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "image", "Image", "", "New image data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_images_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove an image from the current blendfile");
parm = RNA_def_pointer(func, "image", "Image", "", "Image to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this image before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_images_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1234,12 +981,15 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "lattice", "Lattice", "", "New lattices data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_lattices_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a lattice from the current blendfile");
parm = RNA_def_pointer(func, "lattice", "Lattice", "", "Lattice to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this lattice before deleting it "
+ "(WARNING: will also delete objects instancing that lattice data)");
func = RNA_def_function(srna, "tag", "rna_Main_lattices_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1271,12 +1021,15 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "curve", "Curve", "", "New curve data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_curves_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a curve from the current blendfile");
parm = RNA_def_pointer(func, "curve", "Curve", "", "Curve to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this curve before deleting it "
+ "(WARNING: will also delete objects instancing that curve data)");
func = RNA_def_function(srna, "tag", "rna_Main_curves_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1306,12 +1059,15 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "New metaball data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_metaballs_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a metaball from the current blendfile");
parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "Metaball to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this metaball before deleting it "
+ "(WARNING: will also delete objects instancing that metaball data)");
func = RNA_def_function(srna, "tag", "rna_Main_metaballs_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1343,12 +1099,13 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "New font data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_fonts_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a font from the current blendfile");
parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "Font to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this font before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1380,12 +1137,13 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "texture", "Texture", "", "New texture data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_textures_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a texture from the current blendfile");
parm = RNA_def_pointer(func, "texture", "Texture", "", "Texture to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this texture before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_textures_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1416,12 +1174,13 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "brush", "Brush", "", "New brush data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_brushes_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a brush from the current blendfile");
parm = RNA_def_pointer(func, "brush", "Brush", "", "Brush to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this brush before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1452,12 +1211,13 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "world", "World", "", "New world data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_worlds_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a world from the current blendfile");
parm = RNA_def_pointer(func, "world", "World", "", "World to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this world before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1488,11 +1248,13 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "group", "Group", "", "New group data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_groups_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_ui_description(func, "Remove a group from the current blendfile");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "group", "Group", "", "Group to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this group before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1523,12 +1285,15 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "speaker", "Speaker", "", "New speaker data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_speakers_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a speaker from the current blendfile");
parm = RNA_def_pointer(func, "speaker", "Speaker", "", "Speaker to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this speaker before deleting it "
+ "(WARNING: will also delete objects instancing that speaker data)");
func = RNA_def_function(srna, "tag", "rna_Main_speakers_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1559,11 +1324,13 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_texts_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_ui_description(func, "Remove a text from the current blendfile");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "text", "Text", "", "Text to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this text before deleting it");
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_texts_load");
@@ -1607,12 +1374,13 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "sound", "Sound", "", "New text data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_sounds_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a sound from the current blendfile");
parm = RNA_def_pointer(func, "sound", "Sound", "", "Sound to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this sound before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1643,12 +1411,15 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "armature", "Armature", "", "New armature data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_armatures_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a armature from the current blendfile");
parm = RNA_def_pointer(func, "armature", "Armature", "", "Armature to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this armature before deleting it "
+ "(WARNING: will also delete objects instancing that armature data)");
func = RNA_def_function(srna, "tag", "rna_Main_armatures_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1678,12 +1449,13 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "action", "Action", "", "New action data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_actions_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a action from the current blendfile");
parm = RNA_def_pointer(func, "action", "Action", "", "Action to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this action before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_actions_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1713,12 +1485,13 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "palette", "Palette", "", "New palette data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_palettes_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a palette from the current blendfile");
parm = RNA_def_pointer(func, "palette", "Palette", "", "Palette to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this palette before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1752,12 +1525,13 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "New grease pencil data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_grease_pencil_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a grease pencil instance from the current blendfile");
parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "Grease Pencil to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this grease pencil before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1780,11 +1554,13 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
- func = RNA_def_function(srna, "remove", "rna_Main_movieclips_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a movie clip from the current blendfile.");
parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this movie clip before deleting it");
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_movieclip_load");
@@ -1830,11 +1606,13 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
/* remove func */
- func = RNA_def_function(srna, "remove", "rna_Main_masks_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a masks from the current blendfile.");
parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this mask before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1865,11 +1643,13 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "New line style data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_linestyles_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a line style instance from the current blendfile");
parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "Line style to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this line style before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 1ab52aa45d3..e5dc613a0cd 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1812,6 +1812,12 @@ static void rna_def_modifier_hook(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Hook Center", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_float_sdna(prop, NULL, "parentinv");
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(prop, "Matrix", "Reverse the transformation between this object and its target");
+ RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Object", "Parent Object for hook, also recalculates and clears offset");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index dffdd7fe6c7..95f258e95f4 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -3162,12 +3162,14 @@ static EnumPropertyItem node_glossy_items[] = {
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
{SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""},
+ {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem node_anisotropic_items[] = {
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
+ {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
{SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -3176,6 +3178,14 @@ static EnumPropertyItem node_glass_items[] = {
{SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
+ {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static EnumPropertyItem node_refraction_items[] = {
+ {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
+ {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
+ {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -4120,6 +4130,17 @@ static void def_glass(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_refraction(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, node_refraction_items);
+ RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_anisotropic(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 0b8717fc982..559d7e82076 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -1793,7 +1793,7 @@ static void rna_FileBrowser_FSMenu_active_range(
static void rna_FileBrowser_FSMenu_active_update(struct bContext *C, PointerRNA *UNUSED(ptr))
{
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
static int rna_FileBrowser_FSMenuSystem_active_get(PointerRNA *ptr)
@@ -2437,14 +2437,16 @@ static void rna_def_space_view3d(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "near");
- RNA_def_property_range(prop, 0.001f, FLT_MAX);
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop, "Clip Start", "3D View near clipping distance (perspective view only)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "far");
- RNA_def_property_range(prop, 1.0f, FLT_MAX);
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_float_default(prop, 1000.0f);
RNA_def_property_ui_text(prop, "Clip End", "3D View far clipping distance");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 9e1a0c926fa..171d5313c1d 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -82,7 +82,7 @@ DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BS
DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "" )
-DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_glass, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" )
+DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "" )
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index d6c57f4c302..eaa96e6243c 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -264,6 +264,11 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
if ((reports->flag & RPT_FREE) == 0) {
MEM_freeN(reports);
}
+ else {
+ /* The WM is now responsible for running the modal operator,
+ * show reports in the info window. */
+ reports->flag &= ~RPT_OP_HOLD;
+ }
}
WM_operator_properties_free(&ptr);
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 69ae7433fff..af6ac4a8fbf 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -1672,7 +1672,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
}
}
- if (dl->bevelSplitFlag || timeoffset==0) {
+ if (dl->bevel_split || timeoffset == 0) {
const int startvlak= obr->totvlak;
for (a=0; a<dl->parts; a++) {
@@ -1712,10 +1712,15 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
}
}
- if (dl->bevelSplitFlag) {
- for (a=0; a<dl->parts-1+!!(dl->flag&DL_CYCL_V); a++)
- if (dl->bevelSplitFlag[a>>5]&(1<<(a&0x1F)))
- split_v_renderfaces(obr, startvlak, startvert, dl->parts, dl->nr, a, dl->flag&DL_CYCL_V, dl->flag&DL_CYCL_U);
+ if (dl->bevel_split) {
+ for (a = 0; a < dl->parts - 1 + !!(dl->flag & DL_CYCL_V); a++) {
+ if (BLI_BITMAP_TEST(dl->bevel_split, a)) {
+ split_v_renderfaces(
+ obr, startvlak, startvert, dl->parts, dl->nr, a,
+ /* intentionally swap (v, u) --> (u, v) */
+ dl->flag & DL_CYCL_V, dl->flag & DL_CYCL_U);
+ }
+ }
}
/* vertex normals */
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 9bb2462a4e9..7a247d9791b 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -413,12 +413,6 @@ void wmOrtho2 (float x1, float x2, float y1, float y2);
void wmOrtho2_region_pixelspace(const struct ARegion *ar);
void wmOrtho2_pixelspace(const float x, const float y);
- /* utilities */
-void WM_framebuffer_index_set(int index);
-void WM_framebuffer_index_get(int index, int *r_col);
-int WM_framebuffer_to_index(unsigned int col);
-void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size);
-
/* threaded Jobs Manager */
enum {
WM_JOB_PRIORITY = (1 << 0),
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index a1ca89c6a8c..9d1083bbf63 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -141,6 +141,11 @@ static void wm_free_reports(bContext *C)
BKE_reports_clear(reports);
}
+static void wm_undo_kill_callback(bContext *C)
+{
+ WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C));
+}
+
bool wm_start_with_console = false; /* used in creator.c */
/* only called once, for startup */
@@ -159,6 +164,8 @@ void WM_init(bContext *C, int argc, const char **argv)
WM_menutype_init();
WM_uilisttype_init();
+ BKE_undo_callback_wm_kill_jobs_set(wm_undo_kill_callback);
+
BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */
BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */
BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); /* library.c */
@@ -579,6 +586,8 @@ void WM_exit_ext(bContext *C, const bool do_python)
BLI_threadapi_exit();
+ BKE_blender_atexit();
+
if (MEM_get_memory_blocks_in_use() != 0) {
size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use();
printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n",
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index a51648290db..8968c2a4543 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -4208,7 +4208,8 @@ static void gesture_circle_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "MASK_OT_select_circle");
WM_modalkeymap_assign(keymap, "NODE_OT_select_circle");
WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_circle");
- WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle");
+ WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle");
+ WM_modalkeymap_assign(keymap, "ACTION_OT_select_circle");
}
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 6526d419914..458ac4a121a 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -378,149 +378,5 @@ void wmOrtho2_pixelspace(const float x, const float y)
wmOrtho2_offset(x, y, -GLA_PIXEL_OFS);
}
-/* *************************** Framebuffer color depth, for selection codes ********************** */
-
-#ifdef __APPLE__
-
-/* apple seems to round colors to below and up on some configs */
-
-unsigned int index_to_framebuffer(int index)
-{
- unsigned int i = index;
-
- switch (GPU_color_depth()) {
- case 12:
- i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
- /* sometimes dithering subtracts! */
- i |= 0x070707;
- break;
- case 15:
- case 16:
- i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
- i |= 0x030303;
- break;
- case 24:
- break;
- default: /* 18 bits... */
- i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
- i |= 0x010101;
- break;
- }
-
- return i;
-}
-
-#else
-
-/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */
-
-unsigned int index_to_framebuffer(int index)
-{
- unsigned int i = index;
-
- switch (GPU_color_depth()) {
- case 8:
- i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6);
- i |= 0x3F3F3F;
- break;
- case 12:
- i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
- /* sometimes dithering subtracts! */
- i |= 0x0F0F0F;
- break;
- case 15:
- case 16:
- i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
- i |= 0x070707;
- break;
- case 24:
- break;
- default: /* 18 bits... */
- i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
- i |= 0x030303;
- break;
- }
-
- return i;
-}
-
-#endif
-
-void WM_framebuffer_index_set(int index)
-{
- const int col = index_to_framebuffer(index);
- cpack(col);
-}
-
-void WM_framebuffer_index_get(int index, int *r_col)
-{
- const int col = index_to_framebuffer(index);
- char *c_col = (char *)r_col;
- c_col[0] = (col & 0xFF); /* red */
- c_col[1] = ((col >> 8) & 0xFF); /* green */
- c_col[2] = ((col >> 16) & 0xFF); /* blue */
- c_col[3] = 0xFF; /* alpha */
-}
-
-
-
-#define INDEX_FROM_BUF_8(col) (((col & 0xC00000) >> 18) + ((col & 0xC000) >> 12) + ((col & 0xC0) >> 6))
-#define INDEX_FROM_BUF_12(col) (((col & 0xF00000) >> 12) + ((col & 0xF000) >> 8) + ((col & 0xF0) >> 4))
-#define INDEX_FROM_BUF_15_16(col) (((col & 0xF80000) >> 9) + ((col & 0xF800) >> 6) + ((col & 0xF8) >> 3))
-#define INDEX_FROM_BUF_18(col) (((col & 0xFC0000) >> 6) + ((col & 0xFC00) >> 4) + ((col & 0xFC) >> 2))
-#define INDEX_FROM_BUF_24(col) (col & 0xFFFFFF)
-
-int WM_framebuffer_to_index(unsigned int col)
-{
- if (col == 0) {
- return 0;
- }
-
- switch (GPU_color_depth()) {
- case 8: return INDEX_FROM_BUF_8(col);
- case 12: return INDEX_FROM_BUF_12(col);
- case 15:
- case 16: return INDEX_FROM_BUF_15_16(col);
- case 24: return INDEX_FROM_BUF_24(col);
- default: return INDEX_FROM_BUF_18(col);
- }
-}
-
-void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size)
-{
-#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \
- for (i = size; i--; col++) { \
- if ((c = *col)) { \
- *col = INDEX_FROM_BUF_BITS(c); \
- } \
- } ((void)0)
-
- if (size > 0) {
- unsigned int i, c;
-
- switch (GPU_color_depth()) {
- case 8:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_8);
- break;
- case 12:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_12);
- break;
- case 15:
- case 16:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16);
- break;
- case 24:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_24);
- break;
- default:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_18);
- break;
- }
- }
-
-#undef INDEX_BUF_ARRAY
-}
-
-
/* ********** END MY WINDOW ************** */
diff --git a/source/blender/windowmanager/wm_subwindow.h b/source/blender/windowmanager/wm_subwindow.h
index 2a8118a726b..cc9abf87514 100644
--- a/source/blender/windowmanager/wm_subwindow.h
+++ b/source/blender/windowmanager/wm_subwindow.h
@@ -48,7 +48,5 @@ void wm_subwindow_matrix_get(wmWindow *win, int swinid, float mat[4][4]);
void wm_subwindow_rect_get(wmWindow *win, int swinid, struct rcti *r_rect);
void wm_subwindow_rect_set(wmWindow *win, int swinid, const rcti *rect);
-unsigned int index_to_framebuffer(int index);
-
#endif /* __WM_SUBWINDOW_H__ */
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 3a577cadff3..863a2636a94 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -325,8 +325,6 @@ bool WM_uilisttype_add(struct uiListType *ult) RET_ZERO
void WM_uilisttype_freelink(struct uiListType *ult) RET_NONE
void WM_uilisttype_free(void) RET_NONE
-void WM_framebuffer_index_get(int index, int *r_col) RET_NONE
-
struct wmKeyMapItem *WM_keymap_item_find_id(struct wmKeyMap *keymap, int id) RET_NULL
int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event) RET_ZERO
void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference) RET_NONE
@@ -379,7 +377,7 @@ void ED_area_tag_redraw_regiontype(struct ScrArea *sa, int regiontype) RET_NONE
void ED_render_engine_changed(struct Main *bmain) RET_NONE
void ED_file_read_bookmarks(void) RET_NONE
-void ED_file_change_dir(struct bContext *C, const bool checkdir) RET_NONE
+void ED_file_change_dir(struct bContext *C) RET_NONE
void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain) RET_NONE
struct FSMenu *ED_fsmenu_get(void) RET_NULL
struct FSMenuEntry *ED_fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category) RET_NULL
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 122c10ef216..91d03da005e 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -338,6 +338,8 @@ if(WITH_PYTHON)
DIRECTORY ${CMAKE_SOURCE_DIR}/release/scripts
DESTINATION ${TARGETDIR_VER}
PATTERN ".git" EXCLUDE
+ PATTERN ".gitignore" EXCLUDE
+ PATTERN ".arcconfig" EXCLUDE
PATTERN "__pycache__" EXCLUDE
PATTERN "${ADDON_EXCLUDE_CONDITIONAL}" EXCLUDE
PATTERN "${FREESTYLE_EXCLUDE_CONDITIONAL}" EXCLUDE
@@ -538,6 +540,7 @@ if(UNIX AND NOT APPLE)
DIRECTORY ${PYTHON_LIBPATH}/python${PYTHON_VERSION}
DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}
PATTERN "__pycache__" EXCLUDE # * any cache *
+ PATTERN "config-${PYTHON_VERSION}m/*.a" EXCLUDE # static lib
PATTERN "lib2to3" EXCLUDE # ./lib2to3
PATTERN "site-packages/*" EXCLUDE # ./site-packages/*
PATTERN "tkinter" EXCLUDE # ./tkinter
@@ -914,6 +917,7 @@ elseif(APPLE)
PATTERN "__pycache__" EXCLUDE
PATTERN "__MACOSX" EXCLUDE
PATTERN ".DS_Store" EXCLUDE
+ PATTERN "config-${PYTHON_VERSION}m/*.a" EXCLUDE # static lib
)
endmacro()
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 9236e01a703..bd4db12888f 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -147,6 +147,35 @@ static void main_callback_setup(void)
MEM_set_error_callback(callback_mem_error);
}
+/* free data on early exit (if Python calls 'sys.exit()' while parsing args for eg). */
+struct CreatorAtExitData {
+ bArgs *ba;
+#ifdef WIN32
+ const char **argv;
+ int argv_num;
+#endif
+};
+
+static void callback_main_atexit(void *user_data)
+{
+ struct CreatorAtExitData *app_init_data = user_data;
+
+ if (app_init_data->ba) {
+ BLI_argsFree(app_init_data->ba);
+ app_init_data->ba = NULL;
+ }
+
+#ifdef WIN32
+ if (app_init_data->argv) {
+ while (app_init_data->argv_num) {
+ free(app_init_data->argv[--app_init_data->argv_num]);
+ }
+ free(app_init_data->argv);
+ app_init_data->argv = NULL;
+ }
+#endif
+}
+
/** \} */
@@ -198,6 +227,9 @@ int main(
/* --- end declarations --- */
+ /* ensure we free data on early-exit */
+ struct CreatorAtExitData app_init_data = {NULL};
+ BKE_blender_atexit_register(callback_main_atexit, &app_init_data);
#ifdef WIN32
/* We delay loading of openmp so we can set the policy here. */
@@ -221,6 +253,10 @@ int main(
argv[argv_num] = alloc_utf_8_from_16(argv_16[argv_num], 0);
}
LocalFree(argv_16);
+
+ /* free on early-exit */
+ app_init_data.argv = argv;
+ app_init_data.argv_num = argv_num;
}
#endif /* WIN32 */
@@ -335,6 +371,10 @@ int main(
/* first test for background */
#ifndef WITH_PYTHON_MODULE
ba = BLI_argsInit(argc, (const char **)argv); /* skip binary path */
+
+ /* ensure we free on early exit */
+ app_init_data.ba = ba;
+
main_args_setup(C, ba, &syshandle);
BLI_argsParse(ba, 1, NULL, NULL);
@@ -430,16 +470,22 @@ int main(
#endif
+ /* Explicitly free data allocated for argument parsing:
+ * - 'ba'
+ * - 'argv' on WIN32.
+ */
+ callback_main_atexit(&app_init_data);
+ BKE_blender_atexit_unregister(callback_main_atexit, &app_init_data);
+
+ /* paranoid, avoid accidental re-use */
#ifndef WITH_PYTHON_MODULE
- BLI_argsFree(ba);
+ ba = NULL;
+ (void)ba;
#endif
#ifdef WIN32
- while (argv_num) {
- free(argv[--argv_num]);
- }
- free(argv);
argv = NULL;
+ (void)argv;
#endif
#ifdef WITH_PYTHON_MODULE
diff --git a/tests/gtests/blenlib/BLI_array_utils_test.cc b/tests/gtests/blenlib/BLI_array_utils_test.cc
index e532419691a..eabf5bc72cf 100644
--- a/tests/gtests/blenlib/BLI_array_utils_test.cc
+++ b/tests/gtests/blenlib/BLI_array_utils_test.cc
@@ -5,6 +5,7 @@
extern "C" {
#include "BLI_utildefines.h"
#include "BLI_array_utils.h"
+#include "BLI_stackdefines.h"
}
/* -------------------------------------------------------------------- */
@@ -44,33 +45,102 @@ TEST(array_utils, ReverseInt4)
TEST(array_utils, FindIndexStringEmpty)
{
char data[] = "", find = '0';
- EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(-1, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find));
}
TEST(array_utils, FindIndexStringSingle)
{
char data[] = "0", find = '0';
- EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(0, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find));
}
TEST(array_utils, FindIndexStringSingleMissing)
{
char data[] = "1", find = '0';
- EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(-1, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find));
}
TEST(array_utils, FindIndexString4)
{
char data[] = "0123", find = '3';
- EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find));
}
TEST(array_utils, FindIndexInt4)
{
- int data[] = {0, 1, 2, 3}, find = 2;
- EXPECT_EQ(2, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ int data[] = {0, 1, 2, 3}, find = 3;
+ EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data), &find));
+ EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find));
}
+TEST(array_utils, FindIndexInt4_DupeEnd)
+{
+ int data[] = {0, 1, 2, 0}, find = 0;
+ EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data), &find));
+ EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find));
+}
+
+TEST(array_utils, FindIndexInt4_DupeMid)
+{
+ int data[] = {1, 0, 0, 3}, find = 0;
+ EXPECT_EQ(1, BLI_array_findindex(data, ARRAY_SIZE(data), &find));
+ EXPECT_EQ(2, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find));
+}
+
+TEST(array_utils, FindIndexPointer)
+{
+ const char *data[4] = {NULL};
+ STACK_DECLARE(data);
+
+ STACK_INIT(data, ARRAY_SIZE(data));
+
+ const char *a = "a", *b = "b", *c = "c", *d = "d";
+
+#define STACK_PUSH_AND_CHECK_FORWARD(v, i) { \
+ STACK_PUSH(data, v); \
+ EXPECT_EQ(i, BLI_array_findindex(data, STACK_SIZE(data), &(v))); \
+} ((void)0)
+
+#define STACK_PUSH_AND_CHECK_BACKWARD(v, i) { \
+ STACK_PUSH(data, v); \
+ EXPECT_EQ(i, BLI_array_rfindindex(data, STACK_SIZE(data), &(v))); \
+} ((void)0)
+
+#define STACK_PUSH_AND_CHECK_BOTH(v, i) { \
+ STACK_PUSH(data, v); \
+ EXPECT_EQ(i, BLI_array_findindex(data, STACK_SIZE(data), &(v))); \
+ EXPECT_EQ(i, BLI_array_rfindindex(data, STACK_SIZE(data), &(v))); \
+} ((void)0)
+
+ STACK_PUSH_AND_CHECK_BOTH(a, 0);
+ STACK_PUSH_AND_CHECK_BOTH(b, 1);
+ STACK_PUSH_AND_CHECK_BOTH(c, 2);
+ STACK_PUSH_AND_CHECK_BOTH(d, 3);
+
+ STACK_POP(data);
+ STACK_PUSH_AND_CHECK_BACKWARD(a, 3);
+
+ STACK_POP(data);
+ STACK_PUSH_AND_CHECK_FORWARD(a, 0);
+
+ STACK_POP(data);
+ STACK_POP(data);
+
+ STACK_PUSH_AND_CHECK_BACKWARD(b, 2);
+ STACK_PUSH_AND_CHECK_BACKWARD(a, 3);
+
+#undef STACK_PUSH_AND_CHECK_FORWARD
+#undef STACK_PUSH_AND_CHECK_BACKWARD
+#undef STACK_PUSH_AND_CHECK_BOTH
+
+}
+
+
+
/* BLI_array_binary_and */
#define BINARY_AND_TEST(data_cmp, data_a, data_b, data_combine, length) \
{ \